1 //===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "Win64EHDumper.h"
11 #include "llvm-readobj.h"
12 #include "llvm/Object/COFF.h"
13 #include "llvm/Support/ErrorHandling.h"
14 #include "llvm/Support/Format.h"
17 using namespace llvm::object
;
18 using namespace llvm::Win64EH
;
20 static const EnumEntry
<unsigned> UnwindFlags
[] = {
21 { "ExceptionHandler", UNW_ExceptionHandler
},
22 { "TerminateHandler", UNW_TerminateHandler
},
23 { "ChainInfo" , UNW_ChainInfo
}
26 static const EnumEntry
<unsigned> UnwindOpInfo
[] = {
45 static uint64_t getOffsetOfLSDA(const UnwindInfo
& UI
) {
46 return static_cast<const char*>(UI
.getLanguageSpecificData())
47 - reinterpret_cast<const char*>(&UI
);
50 static uint32_t getLargeSlotValue(ArrayRef
<UnwindCode
> UC
) {
53 return UC
[1].FrameOffset
+ (static_cast<uint32_t>(UC
[2].FrameOffset
) << 16);
56 // Returns the name of the unwind code.
57 static StringRef
getUnwindCodeTypeName(uint8_t Code
) {
59 default: llvm_unreachable("Invalid unwind code");
60 case UOP_PushNonVol
: return "PUSH_NONVOL";
61 case UOP_AllocLarge
: return "ALLOC_LARGE";
62 case UOP_AllocSmall
: return "ALLOC_SMALL";
63 case UOP_SetFPReg
: return "SET_FPREG";
64 case UOP_SaveNonVol
: return "SAVE_NONVOL";
65 case UOP_SaveNonVolBig
: return "SAVE_NONVOL_FAR";
66 case UOP_SaveXMM128
: return "SAVE_XMM128";
67 case UOP_SaveXMM128Big
: return "SAVE_XMM128_FAR";
68 case UOP_PushMachFrame
: return "PUSH_MACHFRAME";
72 // Returns the name of a referenced register.
73 static StringRef
getUnwindRegisterName(uint8_t Reg
) {
75 default: llvm_unreachable("Invalid register");
86 case 10: return "R10";
87 case 11: return "R11";
88 case 12: return "R12";
89 case 13: return "R13";
90 case 14: return "R14";
91 case 15: return "R15";
95 // Calculates the number of array slots required for the unwind code.
96 static unsigned getNumUsedSlots(const UnwindCode
&UnwindCode
) {
97 switch (UnwindCode
.getUnwindOp()) {
98 default: llvm_unreachable("Invalid unwind code");
102 case UOP_PushMachFrame
:
107 case UOP_SaveNonVolBig
:
108 case UOP_SaveXMM128Big
:
111 return (UnwindCode
.getOpInfo() == 0) ? 2 : 3;
115 static std::string
formatSymbol(const Dumper::Context
&Ctx
,
116 const coff_section
*Section
, uint64_t Offset
,
117 uint32_t Displacement
) {
119 raw_string_ostream
OS(Buffer
);
122 if (!Ctx
.ResolveSymbol(Section
, Offset
, Symbol
, Ctx
.UserData
)) {
123 Expected
<StringRef
> Name
= Symbol
.getName();
126 if (Displacement
> 0)
127 OS
<< format(" +0x%X (0x%" PRIX64
")", Displacement
, Offset
);
129 OS
<< format(" (0x%" PRIX64
")", Offset
);
132 // TODO: Actually report errors helpfully.
133 consumeError(Name
.takeError());
137 OS
<< format(" (0x%" PRIX64
")", Offset
);
141 static std::error_code
resolveRelocation(const Dumper::Context
&Ctx
,
142 const coff_section
*Section
,
144 const coff_section
*&ResolvedSection
,
145 uint64_t &ResolvedAddress
) {
147 if (std::error_code EC
=
148 Ctx
.ResolveSymbol(Section
, Offset
, Symbol
, Ctx
.UserData
))
151 Expected
<uint64_t> ResolvedAddressOrErr
= Symbol
.getAddress();
152 if (!ResolvedAddressOrErr
)
153 return errorToErrorCode(ResolvedAddressOrErr
.takeError());
154 ResolvedAddress
= *ResolvedAddressOrErr
;
156 Expected
<section_iterator
> SI
= Symbol
.getSection();
158 return errorToErrorCode(SI
.takeError());
159 ResolvedSection
= Ctx
.COFF
.getCOFFSection(**SI
);
160 return std::error_code();
165 void Dumper::printRuntimeFunctionEntry(const Context
&Ctx
,
166 const coff_section
*Section
,
168 const RuntimeFunction
&RF
) {
169 SW
.printString("StartAddress",
170 formatSymbol(Ctx
, Section
, Offset
+ 0, RF
.StartAddress
));
171 SW
.printString("EndAddress",
172 formatSymbol(Ctx
, Section
, Offset
+ 4, RF
.EndAddress
));
173 SW
.printString("UnwindInfoAddress",
174 formatSymbol(Ctx
, Section
, Offset
+ 8, RF
.UnwindInfoOffset
));
177 // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
178 // the unwind codes array, this function requires that the correct number of
179 // slots is provided.
180 void Dumper::printUnwindCode(const UnwindInfo
& UI
, ArrayRef
<UnwindCode
> UC
) {
181 assert(UC
.size() >= getNumUsedSlots(UC
[0]));
183 SW
.startLine() << format("0x%02X: ", unsigned(UC
[0].u
.CodeOffset
))
184 << getUnwindCodeTypeName(UC
[0].getUnwindOp());
186 switch (UC
[0].getUnwindOp()) {
188 OS
<< " reg=" << getUnwindRegisterName(UC
[0].getOpInfo());
193 << ((UC
[0].getOpInfo() == 0) ? UC
[1].FrameOffset
* 8
194 : getLargeSlotValue(UC
));
198 OS
<< " size=" << (UC
[0].getOpInfo() + 1) * 8;
202 if (UI
.getFrameRegister() == 0)
203 OS
<< " reg=<invalid>";
205 OS
<< " reg=" << getUnwindRegisterName(UI
.getFrameRegister())
206 << format(", offset=0x%X", UI
.getFrameOffset() * 16);
210 OS
<< " reg=" << getUnwindRegisterName(UC
[0].getOpInfo())
211 << format(", offset=0x%X", UC
[1].FrameOffset
* 8);
214 case UOP_SaveNonVolBig
:
215 OS
<< " reg=" << getUnwindRegisterName(UC
[0].getOpInfo())
216 << format(", offset=0x%X", getLargeSlotValue(UC
));
220 OS
<< " reg=XMM" << static_cast<uint32_t>(UC
[0].getOpInfo())
221 << format(", offset=0x%X", UC
[1].FrameOffset
* 16);
224 case UOP_SaveXMM128Big
:
225 OS
<< " reg=XMM" << static_cast<uint32_t>(UC
[0].getOpInfo())
226 << format(", offset=0x%X", getLargeSlotValue(UC
));
229 case UOP_PushMachFrame
:
230 OS
<< " errcode=" << (UC
[0].getOpInfo() == 0 ? "no" : "yes");
237 void Dumper::printUnwindInfo(const Context
&Ctx
, const coff_section
*Section
,
238 off_t Offset
, const UnwindInfo
&UI
) {
239 DictScope
UIS(SW
, "UnwindInfo");
240 SW
.printNumber("Version", UI
.getVersion());
241 SW
.printFlags("Flags", UI
.getFlags(), makeArrayRef(UnwindFlags
));
242 SW
.printNumber("PrologSize", UI
.PrologSize
);
243 if (UI
.getFrameRegister()) {
244 SW
.printEnum("FrameRegister", UI
.getFrameRegister(),
245 makeArrayRef(UnwindOpInfo
));
246 SW
.printHex("FrameOffset", UI
.getFrameOffset());
248 SW
.printString("FrameRegister", StringRef("-"));
249 SW
.printString("FrameOffset", StringRef("-"));
252 SW
.printNumber("UnwindCodeCount", UI
.NumCodes
);
254 ListScope
UCS(SW
, "UnwindCodes");
255 ArrayRef
<UnwindCode
> UC(&UI
.UnwindCodes
[0], UI
.NumCodes
);
256 for (const UnwindCode
*UCI
= UC
.begin(), *UCE
= UC
.end(); UCI
< UCE
; ++UCI
) {
257 unsigned UsedSlots
= getNumUsedSlots(*UCI
);
258 if (UsedSlots
> UC
.size()) {
259 errs() << "corrupt unwind data";
263 printUnwindCode(UI
, makeArrayRef(UCI
, UCE
));
264 UCI
= UCI
+ UsedSlots
- 1;
268 uint64_t LSDAOffset
= Offset
+ getOffsetOfLSDA(UI
);
269 if (UI
.getFlags() & (UNW_ExceptionHandler
| UNW_TerminateHandler
)) {
270 SW
.printString("Handler",
271 formatSymbol(Ctx
, Section
, LSDAOffset
,
272 UI
.getLanguageSpecificHandlerOffset()));
273 } else if (UI
.getFlags() & UNW_ChainInfo
) {
274 if (const RuntimeFunction
*Chained
= UI
.getChainedFunctionEntry()) {
275 DictScope
CS(SW
, "Chained");
276 printRuntimeFunctionEntry(Ctx
, Section
, LSDAOffset
, *Chained
);
281 void Dumper::printRuntimeFunction(const Context
&Ctx
,
282 const coff_section
*Section
,
283 uint64_t SectionOffset
,
284 const RuntimeFunction
&RF
) {
285 DictScope
RFS(SW
, "RuntimeFunction");
286 printRuntimeFunctionEntry(Ctx
, Section
, SectionOffset
, RF
);
288 const coff_section
*XData
;
290 resolveRelocation(Ctx
, Section
, SectionOffset
+ 8, XData
, Offset
);
292 ArrayRef
<uint8_t> Contents
;
293 error(Ctx
.COFF
.getSectionContents(XData
, Contents
));
294 if (Contents
.empty())
297 Offset
= Offset
+ RF
.UnwindInfoOffset
;
298 if (Offset
> Contents
.size())
301 const auto UI
= reinterpret_cast<const UnwindInfo
*>(Contents
.data() + Offset
);
302 printUnwindInfo(Ctx
, XData
, Offset
, *UI
);
305 void Dumper::printData(const Context
&Ctx
) {
306 for (const auto &Section
: Ctx
.COFF
.sections()) {
308 Section
.getName(Name
);
310 if (Name
!= ".pdata" && !Name
.startswith(".pdata$"))
313 const coff_section
*PData
= Ctx
.COFF
.getCOFFSection(Section
);
314 ArrayRef
<uint8_t> Contents
;
315 error(Ctx
.COFF
.getSectionContents(PData
, Contents
));
316 if (Contents
.empty())
319 const RuntimeFunction
*Entries
=
320 reinterpret_cast<const RuntimeFunction
*>(Contents
.data());
321 const size_t Count
= Contents
.size() / sizeof(RuntimeFunction
);
322 ArrayRef
<RuntimeFunction
> RuntimeFunctions(Entries
, Count
);
325 for (const auto &RF
: RuntimeFunctions
) {
326 printRuntimeFunction(Ctx
, Ctx
.COFF
.getCOFFSection(Section
),
327 Index
* sizeof(RuntimeFunction
), RF
);