]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data 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 | // Windows on ARM uses a series of serialised data structures (RuntimeFunction) | |
11 | // to create a table of information for unwinding. In order to conserve space, | |
12 | // there are two different ways that this data is represented. | |
13 | // | |
14 | // For functions with canonical forms for the prologue and epilogue, the data | |
15 | // can be stored in a "packed" form. In this case, the data is packed into the | |
16 | // RuntimeFunction's remaining 30-bits and can fully describe the entire frame. | |
17 | // | |
18 | // +---------------------------------------+ | |
19 | // | Function Entry Address | | |
20 | // +---------------------------------------+ | |
21 | // | Packed Form Data | | |
22 | // +---------------------------------------+ | |
23 | // | |
24 | // This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is | |
25 | // associated with such a frame as they can be derived from the provided data. | |
26 | // The decoder does not synthesize this data as it is unnecessary for the | |
27 | // purposes of validation, with the synthesis being required only by a proper | |
28 | // unwinder. | |
29 | // | |
30 | // For functions that are large or do not match canonical forms, the data is | |
31 | // split up into two portions, with the actual data residing in the "exception | |
32 | // data" table (.xdata) with a reference to the entry from the "procedure data" | |
33 | // (.pdata) entry. | |
34 | // | |
35 | // The exception data contains information about the frame setup, all of the | |
36 | // epilouge scopes (for functions for which there are multiple exit points) and | |
37 | // the associated exception handler. Additionally, the entry contains byte-code | |
38 | // describing how to unwind the function (c.f. Decoder::decodeOpcodes). | |
39 | // | |
40 | // +---------------------------------------+ | |
41 | // | Function Entry Address | | |
42 | // +---------------------------------------+ | |
43 | // | Exception Data Entry Address | | |
44 | // +---------------------------------------+ | |
45 | // | |
46 | // This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must | |
47 | // first resolve the exception data entry address. This structure | |
48 | // (ExceptionDataRecord) has a variable sized header | |
49 | // (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as | |
50 | // the packed form. However, because this information is insufficient to | |
51 | // synthesize the unwinding, there are associated unwinding bytecode which make | |
52 | // up the bulk of the Decoder. | |
53 | // | |
54 | // The decoder itself is table-driven, using the first byte to determine the | |
55 | // opcode and dispatching to the associated printing routine. The bytecode | |
56 | // itself is a variable length instruction encoding that can fully describe the | |
57 | // state of the stack and the necessary operations for unwinding to the | |
58 | // beginning of the frame. | |
59 | // | |
60 | // The byte-code maintains a 1-1 instruction mapping, indicating both the width | |
61 | // of the instruction (Thumb2 instructions are variable length, 16 or 32 bits | |
62 | // wide) allowing the program to unwind from any point in the prologue, body, or | |
63 | // epilogue of the function. | |
64 | ||
65 | #include "ARMWinEHPrinter.h" | |
66 | #include "Error.h" | |
1a4d82fc | 67 | #include "llvm/ADT/STLExtras.h" |
85aaf69f | 68 | #include "llvm/ADT/StringExtras.h" |
1a4d82fc JJ |
69 | #include "llvm/Support/ARMWinEH.h" |
70 | #include "llvm/Support/Format.h" | |
71 | ||
72 | using namespace llvm; | |
73 | using namespace llvm::object; | |
74 | using namespace llvm::support; | |
75 | ||
76 | namespace llvm { | |
77 | raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { | |
78 | switch (RT) { | |
79 | case ARM::WinEH::ReturnType::RT_POP: | |
80 | OS << "pop {pc}"; | |
81 | break; | |
82 | case ARM::WinEH::ReturnType::RT_B: | |
83 | OS << "b target"; | |
84 | break; | |
85 | case ARM::WinEH::ReturnType::RT_BW: | |
86 | OS << "b.w target"; | |
87 | break; | |
88 | case ARM::WinEH::ReturnType::RT_NoEpilogue: | |
89 | OS << "(no epilogue)"; | |
90 | break; | |
91 | } | |
92 | return OS; | |
93 | } | |
94 | } | |
95 | ||
96 | static std::string formatSymbol(StringRef Name, uint64_t Address, | |
97 | uint64_t Offset = 0) { | |
98 | std::string Buffer; | |
99 | raw_string_ostream OS(Buffer); | |
100 | ||
101 | if (!Name.empty()) | |
102 | OS << Name << " "; | |
103 | ||
104 | if (Offset) | |
105 | OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address); | |
106 | else if (!Name.empty()) | |
107 | OS << format("(0x%" PRIX64 ")", Address); | |
108 | else | |
109 | OS << format("0x%" PRIX64, Address); | |
110 | ||
111 | return OS.str(); | |
112 | } | |
113 | ||
114 | namespace llvm { | |
115 | namespace ARM { | |
116 | namespace WinEH { | |
117 | const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); | |
118 | ||
119 | // TODO name the uops more appropriately | |
120 | const Decoder::RingEntry Decoder::Ring[] = { | |
121 | { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) | |
122 | { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) | |
123 | { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) | |
124 | { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) | |
125 | { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) | |
126 | { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) | |
127 | { 0xfc, 0xe8, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) | |
128 | { 0xfe, 0xec, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) | |
129 | { 0xff, 0xee, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) | |
130 | // UOP_PUSH_MACHINE_FRAME | |
131 | // UOP_PUSH_CONTEXT | |
132 | // UOP_PUSH_TRAP_FRAME | |
133 | // UOP_REDZONE_RESTORE_LR | |
134 | { 0xff, 0xef, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) | |
135 | { 0xff, 0xf5, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) | |
136 | { 0xff, 0xf6, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) | |
137 | { 0xff, 0xf7, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) | |
138 | { 0xff, 0xf8, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) | |
139 | { 0xff, 0xf9, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) | |
140 | { 0xff, 0xfa, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) | |
141 | { 0xff, 0xfb, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) | |
142 | { 0xff, 0xfc, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) | |
143 | { 0xff, 0xfd, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END | |
144 | { 0xff, 0xfe, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END | |
145 | { 0xff, 0xff, &Decoder::opcode_11111111 }, // UOP_END | |
146 | }; | |
147 | ||
148 | void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) { | |
149 | static const char * const GPRRegisterNames[16] = { | |
150 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", | |
151 | "r11", "ip", "sp", "lr", "pc", | |
152 | }; | |
153 | ||
154 | const uint16_t GPRMask = std::get<0>(RegisterMask); | |
155 | const uint16_t VFPMask = std::get<1>(RegisterMask); | |
156 | ||
157 | OS << '{'; | |
158 | bool Comma = false; | |
159 | for (unsigned RI = 0, RE = 11; RI < RE; ++RI) { | |
160 | if (GPRMask & (1 << RI)) { | |
161 | if (Comma) | |
162 | OS << ", "; | |
163 | OS << GPRRegisterNames[RI]; | |
164 | Comma = true; | |
165 | } | |
166 | } | |
167 | for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { | |
168 | if (VFPMask & (1 << RI)) { | |
169 | if (Comma) | |
170 | OS << ", "; | |
171 | OS << "d" << unsigned(RI); | |
172 | Comma = true; | |
173 | } | |
174 | } | |
175 | for (unsigned RI = 11, RE = 16; RI < RE; ++RI) { | |
176 | if (GPRMask & (1 << RI)) { | |
177 | if (Comma) | |
178 | OS << ", "; | |
179 | OS << GPRRegisterNames[RI]; | |
180 | Comma = true; | |
181 | } | |
182 | } | |
183 | OS << '}'; | |
184 | } | |
185 | ||
186 | ErrorOr<object::SectionRef> | |
187 | Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { | |
188 | for (const auto &Section : COFF.sections()) { | |
85aaf69f SL |
189 | uint64_t Address = Section.getAddress(); |
190 | uint64_t Size = Section.getSize(); | |
1a4d82fc JJ |
191 | |
192 | if (VA >= Address && (VA - Address) <= Size) | |
193 | return Section; | |
194 | } | |
195 | return readobj_error::unknown_symbol; | |
196 | } | |
197 | ||
198 | ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, | |
199 | uint64_t VA, bool FunctionOnly) { | |
200 | for (const auto &Symbol : COFF.symbols()) { | |
201 | if (FunctionOnly) { | |
202 | SymbolRef::Type Type; | |
203 | if (std::error_code EC = Symbol.getType(Type)) | |
204 | return EC; | |
205 | if (Type != SymbolRef::ST_Function) | |
206 | continue; | |
207 | } | |
208 | ||
209 | uint64_t Address; | |
210 | if (std::error_code EC = Symbol.getAddress(Address)) | |
211 | return EC; | |
212 | if (Address == VA) | |
213 | return Symbol; | |
214 | } | |
215 | return readobj_error::unknown_symbol; | |
216 | } | |
217 | ||
218 | ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, | |
219 | const SectionRef &Section, | |
220 | uint64_t Offset) { | |
221 | for (const auto &Relocation : Section.relocations()) { | |
222 | uint64_t RelocationOffset; | |
223 | if (auto Error = Relocation.getOffset(RelocationOffset)) | |
224 | return Error; | |
225 | if (RelocationOffset == Offset) | |
226 | return *Relocation.getSymbol(); | |
227 | } | |
228 | return readobj_error::unknown_symbol; | |
229 | } | |
230 | ||
231 | bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, | |
232 | unsigned Length, bool Prologue) { | |
233 | uint8_t Imm = OC[Offset] & 0x7f; | |
234 | SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", | |
235 | OC[Offset], | |
236 | static_cast<const char *>(Prologue ? "sub" : "add"), | |
237 | Imm); | |
238 | ++Offset; | |
239 | return false; | |
240 | } | |
241 | ||
242 | bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, | |
243 | unsigned Length, bool Prologue) { | |
244 | unsigned Link = (OC[Offset] & 0x20) >> 5; | |
245 | uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) | |
246 | | ((OC[Offset + 0] & 0x1f) << 8) | |
247 | | ((OC[Offset + 1] & 0xff) << 0); | |
248 | assert((~RegisterMask & (1 << 13)) && "sp must not be set"); | |
249 | assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); | |
250 | ||
251 | SW.startLine() << format("0x%02x 0x%02x ; %s.w ", | |
252 | OC[Offset + 0], OC[Offset + 1], | |
253 | Prologue ? "push" : "pop"); | |
254 | printRegisters(std::make_pair(RegisterMask, 0)); | |
255 | OS << '\n'; | |
256 | ||
257 | ++Offset, ++Offset; | |
258 | return false; | |
259 | } | |
260 | ||
261 | bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, | |
262 | unsigned Length, bool Prologue) { | |
263 | if (Prologue) | |
264 | SW.startLine() << format("0x%02x ; mov r%u, sp\n", | |
265 | OC[Offset], OC[Offset] & 0xf); | |
266 | else | |
267 | SW.startLine() << format("0x%02x ; mov sp, r%u\n", | |
268 | OC[Offset], OC[Offset] & 0xf); | |
269 | ++Offset; | |
270 | return false; | |
271 | } | |
272 | ||
273 | bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, | |
274 | unsigned Length, bool Prologue) { | |
275 | unsigned Link = (OC[Offset] & 0x4) >> 3; | |
276 | unsigned Count = (OC[Offset] & 0x3); | |
277 | ||
278 | uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) | |
279 | | (((1 << (Count + 1)) - 1) << 4); | |
280 | ||
281 | SW.startLine() << format("0x%02x ; %s ", OC[Offset], | |
282 | Prologue ? "push" : "pop"); | |
283 | printRegisters(std::make_pair(GPRMask, 0)); | |
284 | OS << '\n'; | |
285 | ||
286 | ++Offset; | |
287 | return false; | |
288 | } | |
289 | ||
290 | bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, | |
291 | unsigned Length, bool Prologue) { | |
292 | unsigned Link = (OC[Offset] & 0x4) >> 2; | |
293 | unsigned Count = (OC[Offset] & 0x3) + 4; | |
294 | ||
295 | uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) | |
296 | | (((1 << (Count + 1)) - 1) << 4); | |
297 | ||
298 | SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], | |
299 | Prologue ? "push" : "pop"); | |
300 | printRegisters(std::make_pair(GPRMask, 0)); | |
301 | OS << '\n'; | |
302 | ||
303 | ++Offset; | |
304 | return false; | |
305 | } | |
306 | ||
307 | bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, | |
308 | unsigned Length, bool Prologue) { | |
309 | unsigned High = (OC[Offset] & 0x7); | |
310 | uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); | |
311 | ||
312 | SW.startLine() << format("0x%02x ; %s ", OC[Offset], | |
313 | Prologue ? "vpush" : "vpop"); | |
314 | printRegisters(std::make_pair(0, VFPMask)); | |
315 | OS << '\n'; | |
316 | ||
317 | ++Offset; | |
318 | return false; | |
319 | } | |
320 | ||
321 | bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, | |
322 | unsigned Length, bool Prologue) { | |
323 | uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); | |
324 | ||
325 | SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", | |
326 | OC[Offset + 0], OC[Offset + 1], | |
327 | static_cast<const char *>(Prologue ? "sub" : "add"), | |
328 | Imm); | |
329 | ||
330 | ++Offset, ++Offset; | |
331 | return false; | |
332 | } | |
333 | ||
334 | bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, | |
335 | unsigned Length, bool Prologue) { | |
336 | uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) | |
337 | | ((OC[Offset + 1] & 0xff) << 0); | |
338 | ||
339 | SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], | |
340 | OC[Offset + 1], Prologue ? "push" : "pop"); | |
341 | printRegisters(std::make_pair(GPRMask, 0)); | |
342 | OS << '\n'; | |
343 | ||
344 | ++Offset, ++Offset; | |
345 | return false; | |
346 | } | |
347 | ||
348 | bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, | |
349 | unsigned Length, bool Prologue) { | |
350 | assert(!Prologue && "may not be used in prologue"); | |
351 | ||
352 | if (OC[Offset + 1] & 0xf0) | |
353 | SW.startLine() << format("0x%02x 0x%02x ; reserved\n", | |
354 | OC[Offset + 0], OC[Offset + 1]); | |
355 | else | |
356 | SW.startLine() | |
357 | << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", | |
358 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); | |
359 | ||
360 | ++Offset, ++Offset; | |
361 | return false; | |
362 | } | |
363 | ||
364 | bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, | |
365 | unsigned Length, bool Prologue) { | |
366 | assert(!Prologue && "may not be used in prologue"); | |
367 | ||
368 | if (OC[Offset + 1] & 0xf0) | |
369 | SW.startLine() << format("0x%02x 0x%02x ; reserved\n", | |
370 | OC[Offset + 0], OC[Offset + 1]); | |
371 | else | |
372 | SW.startLine() | |
373 | << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", | |
374 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); | |
375 | ||
376 | ++Offset, ++Offset; | |
377 | return false; | |
378 | } | |
379 | ||
380 | bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, | |
381 | unsigned Length, bool Prologue) { | |
382 | unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; | |
383 | unsigned End = (OC[Offset + 1] & 0x0f) >> 0; | |
384 | uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start; | |
385 | ||
386 | SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], | |
387 | OC[Offset + 1], Prologue ? "vpush" : "vpop"); | |
388 | printRegisters(std::make_pair(0, VFPMask)); | |
389 | OS << '\n'; | |
390 | ||
391 | ++Offset, ++Offset; | |
392 | return false; | |
393 | } | |
394 | ||
395 | bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, | |
396 | unsigned Length, bool Prologue) { | |
397 | unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; | |
398 | unsigned End = (OC[Offset + 1] & 0x0f) >> 0; | |
399 | uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16; | |
400 | ||
401 | SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], | |
402 | OC[Offset + 1], Prologue ? "vpush" : "vpop"); | |
403 | printRegisters(std::make_pair(0, VFPMask)); | |
404 | OS << '\n'; | |
405 | ||
406 | ++Offset, ++Offset; | |
407 | return false; | |
408 | } | |
409 | ||
410 | bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, | |
411 | unsigned Length, bool Prologue) { | |
412 | uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); | |
413 | ||
414 | SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", | |
415 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], | |
416 | static_cast<const char *>(Prologue ? "sub" : "add"), | |
417 | Imm); | |
418 | ||
419 | ++Offset, ++Offset, ++Offset; | |
420 | return false; | |
421 | } | |
422 | ||
423 | bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, | |
424 | unsigned Length, bool Prologue) { | |
425 | uint32_t Imm = (OC[Offset + 1] << 16) | |
426 | | (OC[Offset + 2] << 8) | |
427 | | (OC[Offset + 3] << 0); | |
428 | ||
429 | SW.startLine() | |
430 | << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", | |
431 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], | |
432 | static_cast<const char *>(Prologue ? "sub" : "add"), Imm); | |
433 | ||
434 | ++Offset, ++Offset, ++Offset, ++Offset; | |
435 | return false; | |
436 | } | |
437 | ||
438 | bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, | |
439 | unsigned Length, bool Prologue) { | |
440 | uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); | |
441 | ||
442 | SW.startLine() | |
443 | << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", | |
444 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], | |
445 | static_cast<const char *>(Prologue ? "sub" : "add"), Imm); | |
446 | ||
447 | ++Offset, ++Offset, ++Offset; | |
448 | return false; | |
449 | } | |
450 | ||
451 | bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, | |
452 | unsigned Length, bool Prologue) { | |
453 | uint32_t Imm = (OC[Offset + 1] << 16) | |
454 | | (OC[Offset + 2] << 8) | |
455 | | (OC[Offset + 3] << 0); | |
456 | ||
457 | SW.startLine() | |
458 | << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", | |
459 | OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], | |
460 | static_cast<const char *>(Prologue ? "sub" : "add"), Imm); | |
461 | ||
462 | ++Offset, ++Offset, ++Offset, ++Offset; | |
463 | return false; | |
464 | } | |
465 | ||
466 | bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, | |
467 | unsigned Length, bool Prologue) { | |
468 | SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); | |
469 | ++Offset; | |
470 | return false; | |
471 | } | |
472 | ||
473 | bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, | |
474 | unsigned Length, bool Prologue) { | |
475 | SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); | |
476 | ++Offset; | |
477 | return false; | |
478 | } | |
479 | ||
480 | bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, | |
481 | unsigned Length, bool Prologue) { | |
482 | SW.startLine() << format("0x%02x ; b\n", OC[Offset]); | |
483 | ++Offset; | |
484 | return true; | |
485 | } | |
486 | ||
487 | bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, | |
488 | unsigned Length, bool Prologue) { | |
489 | SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]); | |
490 | ++Offset; | |
491 | return true; | |
492 | } | |
493 | ||
494 | bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, | |
495 | unsigned Length, bool Prologue) { | |
496 | ++Offset; | |
497 | return true; | |
498 | } | |
499 | ||
500 | void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, | |
501 | bool Prologue) { | |
502 | assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); | |
503 | ||
504 | bool Terminated = false; | |
505 | for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { | |
506 | for (unsigned DI = 0;; ++DI) { | |
507 | if ((Opcodes[OI] & Ring[DI].Mask) == Ring[DI].Value) { | |
508 | Terminated = (this->*Ring[DI].Routine)(Opcodes.data(), OI, 0, Prologue); | |
509 | break; | |
510 | } | |
511 | assert(DI < array_lengthof(Ring) && "unhandled opcode"); | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, | |
517 | const SectionRef &Section, | |
518 | uint64_t FunctionAddress, uint64_t VA) { | |
519 | ArrayRef<uint8_t> Contents; | |
520 | if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) | |
521 | return false; | |
522 | ||
85aaf69f | 523 | uint64_t SectionVA = Section.getAddress(); |
1a4d82fc JJ |
524 | uint64_t Offset = VA - SectionVA; |
525 | const ulittle32_t *Data = | |
526 | reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); | |
527 | const ExceptionDataRecord XData(Data); | |
528 | ||
529 | DictScope XRS(SW, "ExceptionData"); | |
530 | SW.printNumber("FunctionLength", XData.FunctionLength() << 1); | |
531 | SW.printNumber("Version", XData.Vers()); | |
532 | SW.printBoolean("ExceptionData", XData.X()); | |
533 | SW.printBoolean("EpiloguePacked", XData.E()); | |
534 | SW.printBoolean("Fragment", XData.F()); | |
535 | SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", | |
536 | XData.EpilogueCount()); | |
537 | SW.printNumber("ByteCodeLength", | |
538 | static_cast<uint64_t>(XData.CodeWords() * sizeof(uint32_t))); | |
539 | ||
540 | if (XData.E()) { | |
541 | ArrayRef<uint8_t> UC = XData.UnwindByteCode(); | |
542 | if (!XData.F()) { | |
543 | ListScope PS(SW, "Prologue"); | |
544 | decodeOpcodes(UC, 0, /*Prologue=*/true); | |
545 | } | |
546 | if (XData.EpilogueCount()) { | |
547 | ListScope ES(SW, "Epilogue"); | |
548 | decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); | |
549 | } | |
550 | } else { | |
551 | ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); | |
552 | ListScope ESS(SW, "EpilogueScopes"); | |
553 | for (const EpilogueScope ES : EpilogueScopes) { | |
554 | DictScope ESES(SW, "EpilogueScope"); | |
555 | SW.printNumber("StartOffset", ES.EpilogueStartOffset()); | |
556 | SW.printNumber("Condition", ES.Condition()); | |
557 | SW.printNumber("EpilogueStartIndex", ES.EpilogueStartIndex()); | |
558 | ||
559 | ListScope Opcodes(SW, "Opcodes"); | |
560 | decodeOpcodes(XData.UnwindByteCode(), ES.EpilogueStartIndex(), | |
561 | /*Prologue=*/false); | |
562 | } | |
563 | } | |
564 | ||
565 | if (XData.X()) { | |
566 | const uint32_t Address = XData.ExceptionHandlerRVA(); | |
567 | const uint32_t Parameter = XData.ExceptionHandlerParameter(); | |
568 | const size_t HandlerOffset = HeaderWords(XData) | |
569 | + (XData.E() ? 0 : XData.EpilogueCount()) | |
570 | + XData.CodeWords(); | |
571 | ||
572 | ErrorOr<SymbolRef> Symbol = | |
573 | getRelocatedSymbol(COFF, Section, HandlerOffset * sizeof(uint32_t)); | |
574 | if (!Symbol) | |
575 | Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); | |
576 | ||
577 | StringRef Name; | |
578 | if (Symbol) | |
579 | Symbol->getName(Name); | |
580 | ||
581 | ListScope EHS(SW, "ExceptionHandler"); | |
582 | SW.printString("Routine", formatSymbol(Name, Address)); | |
583 | SW.printHex("Parameter", Parameter); | |
584 | } | |
585 | ||
586 | return true; | |
587 | } | |
588 | ||
589 | bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, | |
590 | const SectionRef Section, uint64_t Offset, | |
591 | unsigned Index, const RuntimeFunction &RF) { | |
592 | assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && | |
593 | "packed entry cannot be treated as an unpacked entry"); | |
594 | ||
595 | ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); | |
596 | if (!Function) | |
597 | Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); | |
598 | ||
599 | ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); | |
600 | if (!XDataRecord) | |
601 | XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA()); | |
602 | ||
603 | if (!RF.BeginAddress && !Function) | |
604 | return false; | |
605 | if (!RF.UnwindData && !XDataRecord) | |
606 | return false; | |
607 | ||
608 | StringRef FunctionName; | |
609 | uint64_t FunctionAddress; | |
610 | if (Function) { | |
611 | Function->getName(FunctionName); | |
612 | Function->getAddress(FunctionAddress); | |
613 | } else { | |
614 | const pe32_header *PEHeader; | |
615 | if (COFF.getPE32Header(PEHeader)) | |
616 | return false; | |
617 | FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; | |
618 | } | |
619 | ||
620 | SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); | |
621 | ||
622 | if (XDataRecord) { | |
623 | StringRef Name; | |
624 | uint64_t Address; | |
625 | ||
626 | XDataRecord->getName(Name); | |
627 | XDataRecord->getAddress(Address); | |
628 | ||
629 | SW.printString("ExceptionRecord", formatSymbol(Name, Address)); | |
630 | ||
631 | section_iterator SI = COFF.section_end(); | |
632 | if (XDataRecord->getSection(SI)) | |
633 | return false; | |
634 | ||
635 | return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); | |
636 | } else { | |
637 | const pe32_header *PEHeader; | |
638 | if (COFF.getPE32Header(PEHeader)) | |
639 | return false; | |
640 | ||
641 | uint64_t Address = PEHeader->ImageBase + RF.ExceptionInformationRVA(); | |
642 | SW.printString("ExceptionRecord", formatSymbol("", Address)); | |
643 | ||
644 | ErrorOr<SectionRef> Section = | |
645 | getSectionContaining(COFF, RF.ExceptionInformationRVA()); | |
646 | if (!Section) | |
647 | return false; | |
648 | ||
649 | return dumpXDataRecord(COFF, *Section, FunctionAddress, | |
650 | RF.ExceptionInformationRVA()); | |
651 | } | |
652 | } | |
653 | ||
654 | bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, | |
655 | const SectionRef Section, uint64_t Offset, | |
656 | unsigned Index, const RuntimeFunction &RF) { | |
657 | assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || | |
658 | RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && | |
659 | "unpacked entry cannot be treated as a packed entry"); | |
660 | ||
661 | ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); | |
662 | if (!Function) | |
663 | Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); | |
664 | ||
665 | StringRef FunctionName; | |
666 | uint64_t FunctionAddress; | |
667 | if (Function) { | |
668 | Function->getName(FunctionName); | |
669 | Function->getAddress(FunctionAddress); | |
670 | } else { | |
671 | const pe32_header *PEHeader; | |
672 | if (COFF.getPE32Header(PEHeader)) | |
673 | return false; | |
674 | FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; | |
675 | } | |
676 | ||
677 | SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); | |
678 | SW.printBoolean("Fragment", | |
679 | RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); | |
680 | SW.printNumber("FunctionLength", RF.FunctionLength()); | |
681 | SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; | |
682 | SW.printBoolean("HomedParameters", RF.H()); | |
683 | SW.startLine() << "SavedRegisters: "; | |
684 | printRegisters(SavedRegisterMask(RF)); | |
685 | OS << '\n'; | |
686 | SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); | |
687 | ||
688 | return true; | |
689 | } | |
690 | ||
691 | bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, | |
692 | const SectionRef Section, unsigned Index, | |
693 | ArrayRef<uint8_t> Contents) { | |
694 | uint64_t Offset = PDataEntrySize * Index; | |
695 | const ulittle32_t *Data = | |
696 | reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); | |
697 | ||
698 | const RuntimeFunction Entry(Data); | |
699 | DictScope RFS(SW, "RuntimeFunction"); | |
700 | if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) | |
701 | return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); | |
702 | return dumpPackedEntry(COFF, Section, Offset, Index, Entry); | |
703 | } | |
704 | ||
705 | void Decoder::dumpProcedureData(const COFFObjectFile &COFF, | |
706 | const SectionRef Section) { | |
707 | ArrayRef<uint8_t> Contents; | |
708 | if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) | |
709 | return; | |
710 | ||
711 | if (Contents.size() % PDataEntrySize) { | |
712 | errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; | |
713 | return; | |
714 | } | |
715 | ||
716 | for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) | |
717 | if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) | |
718 | break; | |
719 | } | |
720 | ||
721 | std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) { | |
722 | for (const auto &Section : COFF.sections()) { | |
723 | StringRef SectionName; | |
724 | if (std::error_code EC = | |
725 | COFF.getSectionName(COFF.getCOFFSection(Section), SectionName)) | |
726 | return EC; | |
727 | ||
728 | if (SectionName.startswith(".pdata")) | |
729 | dumpProcedureData(COFF, Section); | |
730 | } | |
731 | return std::error_code(); | |
732 | } | |
733 | } | |
734 | } | |
735 | } |