File: | tools/llvm-readobj/Win64EHDumper.cpp |
Warning: | line 293, column 9 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | ||||
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" | |||
15 | ||||
16 | using namespace llvm; | |||
17 | using namespace llvm::object; | |||
18 | using namespace llvm::Win64EH; | |||
19 | ||||
20 | static const EnumEntry<unsigned> UnwindFlags[] = { | |||
21 | { "ExceptionHandler", UNW_ExceptionHandler }, | |||
22 | { "TerminateHandler", UNW_TerminateHandler }, | |||
23 | { "ChainInfo" , UNW_ChainInfo } | |||
24 | }; | |||
25 | ||||
26 | static const EnumEntry<unsigned> UnwindOpInfo[] = { | |||
27 | { "RAX", 0 }, | |||
28 | { "RCX", 1 }, | |||
29 | { "RDX", 2 }, | |||
30 | { "RBX", 3 }, | |||
31 | { "RSP", 4 }, | |||
32 | { "RBP", 5 }, | |||
33 | { "RSI", 6 }, | |||
34 | { "RDI", 7 }, | |||
35 | { "R8", 8 }, | |||
36 | { "R9", 9 }, | |||
37 | { "R10", 10 }, | |||
38 | { "R11", 11 }, | |||
39 | { "R12", 12 }, | |||
40 | { "R13", 13 }, | |||
41 | { "R14", 14 }, | |||
42 | { "R15", 15 } | |||
43 | }; | |||
44 | ||||
45 | static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) { | |||
46 | return static_cast<const char*>(UI.getLanguageSpecificData()) | |||
47 | - reinterpret_cast<const char*>(&UI); | |||
48 | } | |||
49 | ||||
50 | static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) { | |||
51 | if (UC.size() < 3) | |||
52 | return 0; | |||
53 | return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16); | |||
54 | } | |||
55 | ||||
56 | // Returns the name of the unwind code. | |||
57 | static StringRef getUnwindCodeTypeName(uint8_t Code) { | |||
58 | switch (Code) { | |||
59 | default: llvm_unreachable("Invalid unwind code")::llvm::llvm_unreachable_internal("Invalid unwind code", "/build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-readobj/Win64EHDumper.cpp" , 59); | |||
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"; | |||
69 | } | |||
70 | } | |||
71 | ||||
72 | // Returns the name of a referenced register. | |||
73 | static StringRef getUnwindRegisterName(uint8_t Reg) { | |||
74 | switch (Reg) { | |||
75 | default: llvm_unreachable("Invalid register")::llvm::llvm_unreachable_internal("Invalid register", "/build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-readobj/Win64EHDumper.cpp" , 75); | |||
76 | case 0: return "RAX"; | |||
77 | case 1: return "RCX"; | |||
78 | case 2: return "RDX"; | |||
79 | case 3: return "RBX"; | |||
80 | case 4: return "RSP"; | |||
81 | case 5: return "RBP"; | |||
82 | case 6: return "RSI"; | |||
83 | case 7: return "RDI"; | |||
84 | case 8: return "R8"; | |||
85 | case 9: return "R9"; | |||
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"; | |||
92 | } | |||
93 | } | |||
94 | ||||
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")::llvm::llvm_unreachable_internal("Invalid unwind code", "/build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-readobj/Win64EHDumper.cpp" , 98); | |||
99 | case UOP_PushNonVol: | |||
100 | case UOP_AllocSmall: | |||
101 | case UOP_SetFPReg: | |||
102 | case UOP_PushMachFrame: | |||
103 | return 1; | |||
104 | case UOP_SaveNonVol: | |||
105 | case UOP_SaveXMM128: | |||
106 | return 2; | |||
107 | case UOP_SaveNonVolBig: | |||
108 | case UOP_SaveXMM128Big: | |||
109 | return 3; | |||
110 | case UOP_AllocLarge: | |||
111 | return (UnwindCode.getOpInfo() == 0) ? 2 : 3; | |||
112 | } | |||
113 | } | |||
114 | ||||
115 | static std::string formatSymbol(const Dumper::Context &Ctx, | |||
116 | const coff_section *Section, uint64_t Offset, | |||
117 | uint32_t Displacement) { | |||
118 | std::string Buffer; | |||
119 | raw_string_ostream OS(Buffer); | |||
120 | ||||
121 | SymbolRef Symbol; | |||
122 | if (!Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) { | |||
123 | Expected<StringRef> Name = Symbol.getName(); | |||
124 | if (Name) { | |||
125 | OS << *Name; | |||
126 | if (Displacement > 0) | |||
127 | OS << format(" +0x%X (0x%" PRIX64"l" "X" ")", Displacement, Offset); | |||
128 | else | |||
129 | OS << format(" (0x%" PRIX64"l" "X" ")", Offset); | |||
130 | return OS.str(); | |||
131 | } else { | |||
132 | // TODO: Actually report errors helpfully. | |||
133 | consumeError(Name.takeError()); | |||
134 | } | |||
135 | } | |||
136 | ||||
137 | OS << format(" (0x%" PRIX64"l" "X" ")", Offset); | |||
138 | return OS.str(); | |||
139 | } | |||
140 | ||||
141 | static std::error_code resolveRelocation(const Dumper::Context &Ctx, | |||
142 | const coff_section *Section, | |||
143 | uint64_t Offset, | |||
144 | const coff_section *&ResolvedSection, | |||
145 | uint64_t &ResolvedAddress) { | |||
146 | SymbolRef Symbol; | |||
147 | if (std::error_code EC = | |||
148 | Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) | |||
149 | return EC; | |||
150 | ||||
151 | Expected<uint64_t> ResolvedAddressOrErr = Symbol.getAddress(); | |||
152 | if (!ResolvedAddressOrErr) | |||
153 | return errorToErrorCode(ResolvedAddressOrErr.takeError()); | |||
154 | ResolvedAddress = *ResolvedAddressOrErr; | |||
155 | ||||
156 | Expected<section_iterator> SI = Symbol.getSection(); | |||
157 | if (!SI) | |||
158 | return errorToErrorCode(SI.takeError()); | |||
159 | ResolvedSection = Ctx.COFF.getCOFFSection(**SI); | |||
160 | return std::error_code(); | |||
161 | } | |||
162 | ||||
163 | namespace llvm { | |||
164 | namespace Win64EH { | |||
165 | void Dumper::printRuntimeFunctionEntry(const Context &Ctx, | |||
166 | const coff_section *Section, | |||
167 | uint64_t Offset, | |||
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)); | |||
175 | } | |||
176 | ||||
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]))((UC.size() >= getNumUsedSlots(UC[0])) ? static_cast<void > (0) : __assert_fail ("UC.size() >= getNumUsedSlots(UC[0])" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/llvm-readobj/Win64EHDumper.cpp" , 181, __PRETTY_FUNCTION__)); | |||
182 | ||||
183 | SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) | |||
184 | << getUnwindCodeTypeName(UC[0].getUnwindOp()); | |||
185 | ||||
186 | switch (UC[0].getUnwindOp()) { | |||
187 | case UOP_PushNonVol: | |||
188 | OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()); | |||
189 | break; | |||
190 | ||||
191 | case UOP_AllocLarge: | |||
192 | OS << " size=" | |||
193 | << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8 | |||
194 | : getLargeSlotValue(UC)); | |||
195 | break; | |||
196 | ||||
197 | case UOP_AllocSmall: | |||
198 | OS << " size=" << (UC[0].getOpInfo() + 1) * 8; | |||
199 | break; | |||
200 | ||||
201 | case UOP_SetFPReg: | |||
202 | if (UI.getFrameRegister() == 0) | |||
203 | OS << " reg=<invalid>"; | |||
204 | else | |||
205 | OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) | |||
206 | << format(", offset=0x%X", UI.getFrameOffset() * 16); | |||
207 | break; | |||
208 | ||||
209 | case UOP_SaveNonVol: | |||
210 | OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) | |||
211 | << format(", offset=0x%X", UC[1].FrameOffset * 8); | |||
212 | break; | |||
213 | ||||
214 | case UOP_SaveNonVolBig: | |||
215 | OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) | |||
216 | << format(", offset=0x%X", getLargeSlotValue(UC)); | |||
217 | break; | |||
218 | ||||
219 | case UOP_SaveXMM128: | |||
220 | OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) | |||
221 | << format(", offset=0x%X", UC[1].FrameOffset * 16); | |||
222 | break; | |||
223 | ||||
224 | case UOP_SaveXMM128Big: | |||
225 | OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) | |||
226 | << format(", offset=0x%X", getLargeSlotValue(UC)); | |||
227 | break; | |||
228 | ||||
229 | case UOP_PushMachFrame: | |||
230 | OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); | |||
231 | break; | |||
232 | } | |||
233 | ||||
234 | OS << "\n"; | |||
235 | } | |||
236 | ||||
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()); | |||
247 | } else { | |||
248 | SW.printString("FrameRegister", StringRef("-")); | |||
249 | SW.printString("FrameOffset", StringRef("-")); | |||
250 | } | |||
251 | ||||
252 | SW.printNumber("UnwindCodeCount", UI.NumCodes); | |||
253 | { | |||
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"; | |||
260 | return; | |||
261 | } | |||
262 | ||||
263 | printUnwindCode(UI, makeArrayRef(UCI, UCE)); | |||
264 | UCI = UCI + UsedSlots - 1; | |||
265 | } | |||
266 | } | |||
267 | ||||
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); | |||
277 | } | |||
278 | } | |||
279 | } | |||
280 | ||||
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); | |||
287 | ||||
288 | const coff_section *XData; | |||
289 | uint64_t Offset; | |||
290 | resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); | |||
291 | ||||
292 | ArrayRef<uint8_t> Contents; | |||
293 | error(Ctx.COFF.getSectionContents(XData, Contents)); | |||
| ||||
294 | if (Contents.empty()) | |||
295 | return; | |||
296 | ||||
297 | Offset = Offset + RF.UnwindInfoOffset; | |||
298 | if (Offset > Contents.size()) | |||
299 | return; | |||
300 | ||||
301 | const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset); | |||
302 | printUnwindInfo(Ctx, XData, Offset, *UI); | |||
303 | } | |||
304 | ||||
305 | void Dumper::printData(const Context &Ctx) { | |||
306 | for (const auto &Section : Ctx.COFF.sections()) { | |||
307 | StringRef Name; | |||
308 | Section.getName(Name); | |||
309 | ||||
310 | if (Name != ".pdata" && !Name.startswith(".pdata$")) | |||
| ||||
311 | continue; | |||
312 | ||||
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()) | |||
317 | continue; | |||
318 | ||||
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); | |||
323 | ||||
324 | size_t Index = 0; | |||
325 | for (const auto &RF : RuntimeFunctions) { | |||
326 | printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), | |||
327 | Index * sizeof(RuntimeFunction), RF); | |||
328 | ++Index; | |||
329 | } | |||
330 | } | |||
331 | } | |||
332 | } | |||
333 | } | |||
334 |