1 | //===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // Windows on ARM uses a series of serialised data structures (RuntimeFunction) |
10 | // to create a table of information for unwinding. In order to conserve space, |
11 | // there are two different ways that this data is represented. |
12 | // |
13 | // For functions with canonical forms for the prologue and epilogue, the data |
14 | // can be stored in a "packed" form. In this case, the data is packed into the |
15 | // RuntimeFunction's remaining 30-bits and can fully describe the entire frame. |
16 | // |
17 | // +---------------------------------------+ |
18 | // | Function Entry Address | |
19 | // +---------------------------------------+ |
20 | // | Packed Form Data | |
21 | // +---------------------------------------+ |
22 | // |
23 | // This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is |
24 | // associated with such a frame as they can be derived from the provided data. |
25 | // The decoder does not synthesize this data as it is unnecessary for the |
26 | // purposes of validation, with the synthesis being required only by a proper |
27 | // unwinder. |
28 | // |
29 | // For functions that are large or do not match canonical forms, the data is |
30 | // split up into two portions, with the actual data residing in the "exception |
31 | // data" table (.xdata) with a reference to the entry from the "procedure data" |
32 | // (.pdata) entry. |
33 | // |
34 | // The exception data contains information about the frame setup, all of the |
35 | // epilogue scopes (for functions for which there are multiple exit points) and |
36 | // the associated exception handler. Additionally, the entry contains byte-code |
37 | // describing how to unwind the function (c.f. Decoder::decodeOpcodes). |
38 | // |
39 | // +---------------------------------------+ |
40 | // | Function Entry Address | |
41 | // +---------------------------------------+ |
42 | // | Exception Data Entry Address | |
43 | // +---------------------------------------+ |
44 | // |
45 | // This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must |
46 | // first resolve the exception data entry address. This structure |
47 | // (ExceptionDataRecord) has a variable sized header |
48 | // (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as |
49 | // the packed form. However, because this information is insufficient to |
50 | // synthesize the unwinding, there are associated unwinding bytecode which make |
51 | // up the bulk of the Decoder. |
52 | // |
53 | // The decoder itself is table-driven, using the first byte to determine the |
54 | // opcode and dispatching to the associated printing routine. The bytecode |
55 | // itself is a variable length instruction encoding that can fully describe the |
56 | // state of the stack and the necessary operations for unwinding to the |
57 | // beginning of the frame. |
58 | // |
59 | // The byte-code maintains a 1-1 instruction mapping, indicating both the width |
60 | // of the instruction (Thumb2 instructions are variable length, 16 or 32 bits |
61 | // wide) allowing the program to unwind from any point in the prologue, body, or |
62 | // epilogue of the function. |
63 | |
64 | #include "ARMWinEHPrinter.h" |
65 | #include "llvm/ADT/STLExtras.h" |
66 | #include "llvm/ADT/StringExtras.h" |
67 | #include "llvm/Support/ARMWinEH.h" |
68 | #include "llvm/Support/Format.h" |
69 | |
70 | using namespace llvm; |
71 | using namespace llvm::object; |
72 | using namespace llvm::support; |
73 | |
74 | namespace llvm { |
75 | raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { |
76 | switch (RT) { |
77 | case ARM::WinEH::ReturnType::RT_POP: |
78 | OS << "pop {pc}" ; |
79 | break; |
80 | case ARM::WinEH::ReturnType::RT_B: |
81 | OS << "bx <reg>" ; |
82 | break; |
83 | case ARM::WinEH::ReturnType::RT_BW: |
84 | OS << "b.w <target>" ; |
85 | break; |
86 | case ARM::WinEH::ReturnType::RT_NoEpilogue: |
87 | OS << "(no epilogue)" ; |
88 | break; |
89 | } |
90 | return OS; |
91 | } |
92 | } |
93 | |
94 | static std::string formatSymbol(StringRef Name, uint64_t Address, |
95 | uint64_t Offset = 0) { |
96 | std::string Buffer; |
97 | raw_string_ostream OS(Buffer); |
98 | |
99 | if (!Name.empty()) |
100 | OS << Name << " " ; |
101 | |
102 | if (Offset) |
103 | OS << format(Fmt: "+0x%" PRIX64 " (0x%" PRIX64 ")" , Vals: Offset, Vals: Address); |
104 | else if (!Name.empty()) |
105 | OS << format(Fmt: "(0x%" PRIX64 ")" , Vals: Address); |
106 | else |
107 | OS << format(Fmt: "0x%" PRIX64, Vals: Address); |
108 | |
109 | return OS.str(); |
110 | } |
111 | |
112 | namespace llvm { |
113 | namespace ARM { |
114 | namespace WinEH { |
115 | const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); |
116 | |
117 | // TODO name the uops more appropriately |
118 | const Decoder::RingEntry Decoder::Ring[] = { |
119 | { .Mask: 0x80, .Value: 0x00, .Length: 1, .Routine: &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) |
120 | { .Mask: 0xc0, .Value: 0x80, .Length: 2, .Routine: &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) |
121 | { .Mask: 0xf0, .Value: 0xc0, .Length: 1, .Routine: &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) |
122 | { .Mask: 0xf8, .Value: 0xd0, .Length: 1, .Routine: &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) |
123 | { .Mask: 0xf8, .Value: 0xd8, .Length: 1, .Routine: &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) |
124 | { .Mask: 0xf8, .Value: 0xe0, .Length: 1, .Routine: &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) |
125 | { .Mask: 0xfc, .Value: 0xe8, .Length: 2, .Routine: &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) |
126 | { .Mask: 0xfe, .Value: 0xec, .Length: 2, .Routine: &Decoder::opcode_1110110L }, // UOP_POP (16-bit) |
127 | { .Mask: 0xff, .Value: 0xee, .Length: 2, .Routine: &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) |
128 | // UOP_PUSH_MACHINE_FRAME |
129 | // UOP_PUSH_CONTEXT |
130 | // UOP_PUSH_TRAP_FRAME |
131 | // UOP_REDZONE_RESTORE_LR |
132 | { .Mask: 0xff, .Value: 0xef, .Length: 2, .Routine: &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) |
133 | { .Mask: 0xff, .Value: 0xf5, .Length: 2, .Routine: &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) |
134 | { .Mask: 0xff, .Value: 0xf6, .Length: 2, .Routine: &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) |
135 | { .Mask: 0xff, .Value: 0xf7, .Length: 3, .Routine: &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) |
136 | { .Mask: 0xff, .Value: 0xf8, .Length: 4, .Routine: &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) |
137 | { .Mask: 0xff, .Value: 0xf9, .Length: 3, .Routine: &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) |
138 | { .Mask: 0xff, .Value: 0xfa, .Length: 4, .Routine: &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) |
139 | { .Mask: 0xff, .Value: 0xfb, .Length: 1, .Routine: &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) |
140 | { .Mask: 0xff, .Value: 0xfc, .Length: 1, .Routine: &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) |
141 | { .Mask: 0xff, .Value: 0xfd, .Length: 1, .Routine: &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END |
142 | { .Mask: 0xff, .Value: 0xfe, .Length: 1, .Routine: &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END |
143 | { .Mask: 0xff, .Value: 0xff, .Length: 1, .Routine: &Decoder::opcode_11111111 }, // UOP_END |
144 | }; |
145 | |
146 | // Unwind opcodes for ARM64. |
147 | // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling |
148 | const Decoder::RingEntry Decoder::Ring64[] = { |
149 | {.Mask: 0xe0, .Value: 0x00, .Length: 1, .Routine: &Decoder::opcode_alloc_s}, |
150 | {.Mask: 0xe0, .Value: 0x20, .Length: 1, .Routine: &Decoder::opcode_save_r19r20_x}, |
151 | {.Mask: 0xc0, .Value: 0x40, .Length: 1, .Routine: &Decoder::opcode_save_fplr}, |
152 | {.Mask: 0xc0, .Value: 0x80, .Length: 1, .Routine: &Decoder::opcode_save_fplr_x}, |
153 | {.Mask: 0xf8, .Value: 0xc0, .Length: 2, .Routine: &Decoder::opcode_alloc_m}, |
154 | {.Mask: 0xfc, .Value: 0xc8, .Length: 2, .Routine: &Decoder::opcode_save_regp}, |
155 | {.Mask: 0xfc, .Value: 0xcc, .Length: 2, .Routine: &Decoder::opcode_save_regp_x}, |
156 | {.Mask: 0xfc, .Value: 0xd0, .Length: 2, .Routine: &Decoder::opcode_save_reg}, |
157 | {.Mask: 0xfe, .Value: 0xd4, .Length: 2, .Routine: &Decoder::opcode_save_reg_x}, |
158 | {.Mask: 0xfe, .Value: 0xd6, .Length: 2, .Routine: &Decoder::opcode_save_lrpair}, |
159 | {.Mask: 0xfe, .Value: 0xd8, .Length: 2, .Routine: &Decoder::opcode_save_fregp}, |
160 | {.Mask: 0xfe, .Value: 0xda, .Length: 2, .Routine: &Decoder::opcode_save_fregp_x}, |
161 | {.Mask: 0xfe, .Value: 0xdc, .Length: 2, .Routine: &Decoder::opcode_save_freg}, |
162 | {.Mask: 0xff, .Value: 0xde, .Length: 2, .Routine: &Decoder::opcode_save_freg_x}, |
163 | {.Mask: 0xff, .Value: 0xe0, .Length: 4, .Routine: &Decoder::opcode_alloc_l}, |
164 | {.Mask: 0xff, .Value: 0xe1, .Length: 1, .Routine: &Decoder::opcode_setfp}, |
165 | {.Mask: 0xff, .Value: 0xe2, .Length: 2, .Routine: &Decoder::opcode_addfp}, |
166 | {.Mask: 0xff, .Value: 0xe3, .Length: 1, .Routine: &Decoder::opcode_nop}, |
167 | {.Mask: 0xff, .Value: 0xe4, .Length: 1, .Routine: &Decoder::opcode_end}, |
168 | {.Mask: 0xff, .Value: 0xe5, .Length: 1, .Routine: &Decoder::opcode_end_c}, |
169 | {.Mask: 0xff, .Value: 0xe6, .Length: 1, .Routine: &Decoder::opcode_save_next}, |
170 | {.Mask: 0xff, .Value: 0xe7, .Length: 3, .Routine: &Decoder::opcode_save_any_reg}, |
171 | {.Mask: 0xff, .Value: 0xe8, .Length: 1, .Routine: &Decoder::opcode_trap_frame}, |
172 | {.Mask: 0xff, .Value: 0xe9, .Length: 1, .Routine: &Decoder::opcode_machine_frame}, |
173 | {.Mask: 0xff, .Value: 0xea, .Length: 1, .Routine: &Decoder::opcode_context}, |
174 | {.Mask: 0xff, .Value: 0xeb, .Length: 1, .Routine: &Decoder::opcode_ec_context}, |
175 | {.Mask: 0xff, .Value: 0xec, .Length: 1, .Routine: &Decoder::opcode_clear_unwound_to_call}, |
176 | {.Mask: 0xff, .Value: 0xfc, .Length: 1, .Routine: &Decoder::opcode_pac_sign_lr}, |
177 | }; |
178 | |
179 | static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First, |
180 | unsigned Last, char Letter) { |
181 | if (First == Last) |
182 | OS << LS << Letter << First; |
183 | else |
184 | OS << LS << Letter << First << "-" << Letter << Last; |
185 | } |
186 | |
187 | static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS, |
188 | unsigned Start, unsigned End, char Letter) { |
189 | int First = -1; |
190 | for (unsigned RI = Start; RI <= End; ++RI) { |
191 | if (Mask & (1 << RI)) { |
192 | if (First < 0) |
193 | First = RI; |
194 | } else { |
195 | if (First >= 0) { |
196 | printRange(OS, LS, First, Last: RI - 1, Letter); |
197 | First = -1; |
198 | } |
199 | } |
200 | } |
201 | if (First >= 0) |
202 | printRange(OS, LS, First, Last: End, Letter); |
203 | } |
204 | |
205 | void Decoder::printGPRMask(uint16_t GPRMask) { |
206 | OS << '{'; |
207 | ListSeparator LS; |
208 | printRange(OS, Mask: GPRMask, LS, Start: 0, End: 12, Letter: 'r'); |
209 | if (GPRMask & (1 << 14)) |
210 | OS << LS << "lr" ; |
211 | if (GPRMask & (1 << 15)) |
212 | OS << LS << "pc" ; |
213 | OS << '}'; |
214 | } |
215 | |
216 | void Decoder::printVFPMask(uint32_t VFPMask) { |
217 | OS << '{'; |
218 | ListSeparator LS; |
219 | printRange(OS, Mask: VFPMask, LS, Start: 0, End: 31, Letter: 'd'); |
220 | OS << '}'; |
221 | } |
222 | |
223 | ErrorOr<object::SectionRef> |
224 | Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { |
225 | for (const auto &Section : COFF.sections()) { |
226 | uint64_t Address = Section.getAddress(); |
227 | uint64_t Size = Section.getSize(); |
228 | |
229 | if (VA >= Address && (VA - Address) <= Size) |
230 | return Section; |
231 | } |
232 | return inconvertibleErrorCode(); |
233 | } |
234 | |
235 | ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, |
236 | uint64_t VA, bool FunctionOnly) { |
237 | for (const auto &Symbol : COFF.symbols()) { |
238 | Expected<SymbolRef::Type> Type = Symbol.getType(); |
239 | if (!Type) |
240 | return errorToErrorCode(Err: Type.takeError()); |
241 | if (FunctionOnly && *Type != SymbolRef::ST_Function) |
242 | continue; |
243 | |
244 | Expected<uint64_t> Address = Symbol.getAddress(); |
245 | if (!Address) |
246 | return errorToErrorCode(Err: Address.takeError()); |
247 | if (*Address == VA) |
248 | return Symbol; |
249 | } |
250 | return inconvertibleErrorCode(); |
251 | } |
252 | |
253 | ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, |
254 | const SectionRef &Section, |
255 | uint64_t Offset) { |
256 | for (const auto &Relocation : Section.relocations()) { |
257 | uint64_t RelocationOffset = Relocation.getOffset(); |
258 | if (RelocationOffset == Offset) |
259 | return *Relocation.getSymbol(); |
260 | } |
261 | return inconvertibleErrorCode(); |
262 | } |
263 | |
264 | SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym, |
265 | uint64_t &SymbolOffset) { |
266 | // The symbol resolved by getRelocatedSymbol can be any internal |
267 | // nondescriptive symbol; try to resolve a more descriptive one. |
268 | COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Symbol: Sym); |
269 | if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && |
270 | CoffSym.getSectionDefinition() == nullptr) |
271 | return Sym; |
272 | for (const auto &S : COFF.symbols()) { |
273 | COFFSymbolRef CS = COFF.getCOFFSymbol(Symbol: S); |
274 | if (CS.getSectionNumber() == CoffSym.getSectionNumber() && |
275 | CS.getValue() <= CoffSym.getValue() + SymbolOffset && |
276 | CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && |
277 | CS.getSectionDefinition() == nullptr) { |
278 | uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue(); |
279 | if (Offset <= SymbolOffset) { |
280 | SymbolOffset = Offset; |
281 | Sym = S; |
282 | CoffSym = CS; |
283 | if (CS.isExternal() && SymbolOffset == 0) |
284 | return Sym; |
285 | } |
286 | } |
287 | } |
288 | return Sym; |
289 | } |
290 | |
291 | ErrorOr<SymbolRef> Decoder::getSymbolForLocation( |
292 | const COFFObjectFile &COFF, const SectionRef &Section, |
293 | uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress, |
294 | uint64_t &SymbolOffset, bool FunctionOnly) { |
295 | // Try to locate a relocation that points at the offset in the section |
296 | ErrorOr<SymbolRef> SymOrErr = |
297 | getRelocatedSymbol(COFF, Section, Offset: OffsetInSection); |
298 | if (SymOrErr) { |
299 | // We found a relocation symbol; the immediate offset needs to be added |
300 | // to the symbol address. |
301 | SymbolOffset = ImmediateOffset; |
302 | |
303 | Expected<uint64_t> AddressOrErr = SymOrErr->getAddress(); |
304 | if (!AddressOrErr) { |
305 | std::string Buf; |
306 | llvm::raw_string_ostream OS(Buf); |
307 | logAllUnhandledErrors(E: AddressOrErr.takeError(), OS); |
308 | report_fatal_error(reason: Twine(OS.str())); |
309 | } |
310 | // We apply SymbolOffset here directly. We return it separately to allow |
311 | // the caller to print it as an offset on the symbol name. |
312 | SymbolAddress = *AddressOrErr + SymbolOffset; |
313 | |
314 | if (FunctionOnly) // Resolve label/section symbols into function names. |
315 | SymOrErr = getPreferredSymbol(COFF, Sym: *SymOrErr, SymbolOffset); |
316 | } else { |
317 | // No matching relocation found; operating on a linked image. Try to |
318 | // find a descriptive symbol if possible. The immediate offset contains |
319 | // the image relative address, and we shouldn't add any offset to the |
320 | // symbol. |
321 | SymbolAddress = COFF.getImageBase() + ImmediateOffset; |
322 | SymbolOffset = 0; |
323 | SymOrErr = getSymbol(COFF, VA: SymbolAddress, FunctionOnly); |
324 | } |
325 | return SymOrErr; |
326 | } |
327 | |
328 | bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, |
329 | unsigned Length, bool Prologue) { |
330 | uint8_t Imm = OC[Offset] & 0x7f; |
331 | SW.startLine() << format(Fmt: "0x%02x ; %s sp, #(%u * 4)\n" , |
332 | Vals: OC[Offset], |
333 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), |
334 | Vals: Imm); |
335 | ++Offset; |
336 | return false; |
337 | } |
338 | |
339 | bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, |
340 | unsigned Length, bool Prologue) { |
341 | unsigned Link = (OC[Offset] & 0x20) >> 5; |
342 | uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) |
343 | | ((OC[Offset + 0] & 0x1f) << 8) |
344 | | ((OC[Offset + 1] & 0xff) << 0); |
345 | assert((~RegisterMask & (1 << 13)) && "sp must not be set" ); |
346 | assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set" ); |
347 | |
348 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; %s.w " , |
349 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], |
350 | Vals: Prologue ? "push" : "pop" ); |
351 | printGPRMask(GPRMask: RegisterMask); |
352 | OS << '\n'; |
353 | |
354 | Offset += 2; |
355 | return false; |
356 | } |
357 | |
358 | bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, |
359 | unsigned Length, bool Prologue) { |
360 | if (Prologue) |
361 | SW.startLine() << format(Fmt: "0x%02x ; mov r%u, sp\n" , |
362 | Vals: OC[Offset], Vals: OC[Offset] & 0xf); |
363 | else |
364 | SW.startLine() << format(Fmt: "0x%02x ; mov sp, r%u\n" , |
365 | Vals: OC[Offset], Vals: OC[Offset] & 0xf); |
366 | ++Offset; |
367 | return false; |
368 | } |
369 | |
370 | bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, |
371 | unsigned Length, bool Prologue) { |
372 | unsigned Link = (OC[Offset] & 0x4) >> 2; |
373 | unsigned Count = (OC[Offset] & 0x3); |
374 | |
375 | uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) |
376 | | (((1 << (Count + 1)) - 1) << 4); |
377 | |
378 | SW.startLine() << format(Fmt: "0x%02x ; %s " , Vals: OC[Offset], |
379 | Vals: Prologue ? "push" : "pop" ); |
380 | printGPRMask(GPRMask); |
381 | OS << '\n'; |
382 | |
383 | ++Offset; |
384 | return false; |
385 | } |
386 | |
387 | bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, |
388 | unsigned Length, bool Prologue) { |
389 | unsigned Link = (OC[Offset] & 0x4) >> 2; |
390 | unsigned Count = (OC[Offset] & 0x3) + 4; |
391 | |
392 | uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) |
393 | | (((1 << (Count + 1)) - 1) << 4); |
394 | |
395 | SW.startLine() << format(Fmt: "0x%02x ; %s.w " , Vals: OC[Offset], |
396 | Vals: Prologue ? "push" : "pop" ); |
397 | printGPRMask(GPRMask); |
398 | OS << '\n'; |
399 | |
400 | ++Offset; |
401 | return false; |
402 | } |
403 | |
404 | bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, |
405 | unsigned Length, bool Prologue) { |
406 | unsigned High = (OC[Offset] & 0x7); |
407 | uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); |
408 | |
409 | SW.startLine() << format(Fmt: "0x%02x ; %s " , Vals: OC[Offset], |
410 | Vals: Prologue ? "vpush" : "vpop" ); |
411 | printVFPMask(VFPMask); |
412 | OS << '\n'; |
413 | |
414 | ++Offset; |
415 | return false; |
416 | } |
417 | |
418 | bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, |
419 | unsigned Length, bool Prologue) { |
420 | uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); |
421 | |
422 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n" , |
423 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], |
424 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), |
425 | Vals: Imm); |
426 | |
427 | Offset += 2; |
428 | return false; |
429 | } |
430 | |
431 | bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, |
432 | unsigned Length, bool Prologue) { |
433 | uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) |
434 | | ((OC[Offset + 1] & 0xff) << 0); |
435 | |
436 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; %s " , Vals: OC[Offset + 0], |
437 | Vals: OC[Offset + 1], Vals: Prologue ? "push" : "pop" ); |
438 | printGPRMask(GPRMask); |
439 | OS << '\n'; |
440 | |
441 | Offset += 2; |
442 | return false; |
443 | } |
444 | |
445 | bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, |
446 | unsigned Length, bool Prologue) { |
447 | assert(!Prologue && "may not be used in prologue" ); |
448 | |
449 | if (OC[Offset + 1] & 0xf0) |
450 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; reserved\n" , |
451 | Vals: OC[Offset + 0], Vals: OC[Offset + 1]); |
452 | else |
453 | SW.startLine() |
454 | << format(Fmt: "0x%02x 0x%02x ; microsoft-specific (type: %u)\n" , |
455 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 1] & 0x0f); |
456 | |
457 | Offset += 2; |
458 | return false; |
459 | } |
460 | |
461 | bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, |
462 | unsigned Length, bool Prologue) { |
463 | if (OC[Offset + 1] & 0xf0) |
464 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; reserved\n" , |
465 | Vals: OC[Offset + 0], Vals: OC[Offset + 1]); |
466 | else if (Prologue) |
467 | SW.startLine() |
468 | << format(Fmt: "0x%02x 0x%02x ; str.w lr, [sp, #-%u]!\n" , |
469 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 1] << 2); |
470 | else |
471 | SW.startLine() |
472 | << format(Fmt: "0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n" , |
473 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 1] << 2); |
474 | |
475 | Offset += 2; |
476 | return false; |
477 | } |
478 | |
479 | bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, |
480 | unsigned Length, bool Prologue) { |
481 | unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; |
482 | unsigned End = (OC[Offset + 1] & 0x0f) >> 0; |
483 | uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start; |
484 | |
485 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; %s " , Vals: OC[Offset + 0], |
486 | Vals: OC[Offset + 1], Vals: Prologue ? "vpush" : "vpop" ); |
487 | printVFPMask(VFPMask); |
488 | OS << '\n'; |
489 | |
490 | Offset += 2; |
491 | return false; |
492 | } |
493 | |
494 | bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, |
495 | unsigned Length, bool Prologue) { |
496 | unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; |
497 | unsigned End = (OC[Offset + 1] & 0x0f) >> 0; |
498 | uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start); |
499 | |
500 | SW.startLine() << format(Fmt: "0x%02x 0x%02x ; %s " , Vals: OC[Offset + 0], |
501 | Vals: OC[Offset + 1], Vals: Prologue ? "vpush" : "vpop" ); |
502 | printVFPMask(VFPMask); |
503 | OS << '\n'; |
504 | |
505 | Offset += 2; |
506 | return false; |
507 | } |
508 | |
509 | bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, |
510 | unsigned Length, bool Prologue) { |
511 | uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); |
512 | |
513 | SW.startLine() << format(Fmt: "0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n" , |
514 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 2], |
515 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), |
516 | Vals: Imm); |
517 | |
518 | Offset += 3; |
519 | return false; |
520 | } |
521 | |
522 | bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, |
523 | unsigned Length, bool Prologue) { |
524 | uint32_t Imm = (OC[Offset + 1] << 16) |
525 | | (OC[Offset + 2] << 8) |
526 | | (OC[Offset + 3] << 0); |
527 | |
528 | SW.startLine() |
529 | << format(Fmt: "0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n" , |
530 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 2], Vals: OC[Offset + 3], |
531 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), Vals: Imm); |
532 | |
533 | Offset += 4; |
534 | return false; |
535 | } |
536 | |
537 | bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, |
538 | unsigned Length, bool Prologue) { |
539 | uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); |
540 | |
541 | SW.startLine() |
542 | << format(Fmt: "0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n" , |
543 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 2], |
544 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), Vals: Imm); |
545 | |
546 | Offset += 3; |
547 | return false; |
548 | } |
549 | |
550 | bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, |
551 | unsigned Length, bool Prologue) { |
552 | uint32_t Imm = (OC[Offset + 1] << 16) |
553 | | (OC[Offset + 2] << 8) |
554 | | (OC[Offset + 3] << 0); |
555 | |
556 | SW.startLine() |
557 | << format(Fmt: "0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n" , |
558 | Vals: OC[Offset + 0], Vals: OC[Offset + 1], Vals: OC[Offset + 2], Vals: OC[Offset + 3], |
559 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), Vals: Imm); |
560 | |
561 | Offset += 4; |
562 | return false; |
563 | } |
564 | |
565 | bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, |
566 | unsigned Length, bool Prologue) { |
567 | SW.startLine() << format(Fmt: "0x%02x ; nop\n" , Vals: OC[Offset]); |
568 | ++Offset; |
569 | return false; |
570 | } |
571 | |
572 | bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, |
573 | unsigned Length, bool Prologue) { |
574 | SW.startLine() << format(Fmt: "0x%02x ; nop.w\n" , Vals: OC[Offset]); |
575 | ++Offset; |
576 | return false; |
577 | } |
578 | |
579 | bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, |
580 | unsigned Length, bool Prologue) { |
581 | SW.startLine() << format(Fmt: "0x%02x ; bx <reg>\n" , Vals: OC[Offset]); |
582 | ++Offset; |
583 | return true; |
584 | } |
585 | |
586 | bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, |
587 | unsigned Length, bool Prologue) { |
588 | SW.startLine() << format(Fmt: "0x%02x ; b.w <target>\n" , Vals: OC[Offset]); |
589 | ++Offset; |
590 | return true; |
591 | } |
592 | |
593 | bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, |
594 | unsigned Length, bool Prologue) { |
595 | ++Offset; |
596 | return true; |
597 | } |
598 | |
599 | // ARM64 unwind codes start here. |
600 | bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset, |
601 | unsigned Length, bool Prologue) { |
602 | uint32_t NumBytes = (OC[Offset] & 0x1F) << 4; |
603 | SW.startLine() << format(Fmt: "0x%02x ; %s sp, #%u\n" , Vals: OC[Offset], |
604 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), |
605 | Vals: NumBytes); |
606 | ++Offset; |
607 | return false; |
608 | } |
609 | |
610 | bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset, |
611 | unsigned Length, bool Prologue) { |
612 | uint32_t Off = (OC[Offset] & 0x1F) << 3; |
613 | if (Prologue) |
614 | SW.startLine() << format( |
615 | Fmt: "0x%02x ; stp x19, x20, [sp, #-%u]!\n" , Vals: OC[Offset], Vals: Off); |
616 | else |
617 | SW.startLine() << format( |
618 | Fmt: "0x%02x ; ldp x19, x20, [sp], #%u\n" , Vals: OC[Offset], Vals: Off); |
619 | ++Offset; |
620 | return false; |
621 | } |
622 | |
623 | bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset, |
624 | unsigned Length, bool Prologue) { |
625 | uint32_t Off = (OC[Offset] & 0x3F) << 3; |
626 | SW.startLine() << format( |
627 | Fmt: "0x%02x ; %s x29, x30, [sp, #%u]\n" , Vals: OC[Offset], |
628 | Vals: static_cast<const char *>(Prologue ? "stp" : "ldp" ), Vals: Off); |
629 | ++Offset; |
630 | return false; |
631 | } |
632 | |
633 | bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset, |
634 | unsigned Length, bool Prologue) { |
635 | uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3; |
636 | if (Prologue) |
637 | SW.startLine() << format( |
638 | Fmt: "0x%02x ; stp x29, x30, [sp, #-%u]!\n" , Vals: OC[Offset], Vals: Off); |
639 | else |
640 | SW.startLine() << format( |
641 | Fmt: "0x%02x ; ldp x29, x30, [sp], #%u\n" , Vals: OC[Offset], Vals: Off); |
642 | ++Offset; |
643 | return false; |
644 | } |
645 | |
646 | bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset, |
647 | unsigned Length, bool Prologue) { |
648 | uint32_t NumBytes = ((OC[Offset] & 0x07) << 8); |
649 | NumBytes |= (OC[Offset + 1] & 0xFF); |
650 | NumBytes <<= 4; |
651 | SW.startLine() << format(Fmt: "0x%02x%02x ; %s sp, #%u\n" , |
652 | Vals: OC[Offset], Vals: OC[Offset + 1], |
653 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), |
654 | Vals: NumBytes); |
655 | Offset += 2; |
656 | return false; |
657 | } |
658 | |
659 | bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset, |
660 | unsigned Length, bool Prologue) { |
661 | uint32_t Reg = ((OC[Offset] & 0x03) << 8); |
662 | Reg |= (OC[Offset + 1] & 0xC0); |
663 | Reg >>= 6; |
664 | Reg += 19; |
665 | uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; |
666 | SW.startLine() << format( |
667 | Fmt: "0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n" , |
668 | Vals: OC[Offset], Vals: OC[Offset + 1], |
669 | Vals: static_cast<const char *>(Prologue ? "stp" : "ldp" ), Vals: Reg, Vals: Reg + 1, Vals: Off); |
670 | Offset += 2; |
671 | return false; |
672 | } |
673 | |
674 | bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset, |
675 | unsigned Length, bool Prologue) { |
676 | uint32_t Reg = ((OC[Offset] & 0x03) << 8); |
677 | Reg |= (OC[Offset + 1] & 0xC0); |
678 | Reg >>= 6; |
679 | Reg += 19; |
680 | uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; |
681 | if (Prologue) |
682 | SW.startLine() << format( |
683 | Fmt: "0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n" , |
684 | Vals: OC[Offset], Vals: OC[Offset + 1], Vals: Reg, |
685 | Vals: Reg + 1, Vals: Off); |
686 | else |
687 | SW.startLine() << format( |
688 | Fmt: "0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n" , |
689 | Vals: OC[Offset], Vals: OC[Offset + 1], Vals: Reg, |
690 | Vals: Reg + 1, Vals: Off); |
691 | Offset += 2; |
692 | return false; |
693 | } |
694 | |
695 | bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset, |
696 | unsigned Length, bool Prologue) { |
697 | uint32_t Reg = (OC[Offset] & 0x03) << 8; |
698 | Reg |= (OC[Offset + 1] & 0xC0); |
699 | Reg >>= 6; |
700 | Reg += 19; |
701 | uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; |
702 | SW.startLine() << format(Fmt: "0x%02x%02x ; %s x%u, [sp, #%u]\n" , |
703 | Vals: OC[Offset], Vals: OC[Offset + 1], |
704 | Vals: static_cast<const char *>(Prologue ? "str" : "ldr" ), |
705 | Vals: Reg, Vals: Off); |
706 | Offset += 2; |
707 | return false; |
708 | } |
709 | |
710 | bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset, |
711 | unsigned Length, bool Prologue) { |
712 | uint32_t Reg = (OC[Offset] & 0x01) << 8; |
713 | Reg |= (OC[Offset + 1] & 0xE0); |
714 | Reg >>= 5; |
715 | Reg += 19; |
716 | uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; |
717 | if (Prologue) |
718 | SW.startLine() << format(Fmt: "0x%02x%02x ; str x%u, [sp, #-%u]!\n" , |
719 | Vals: OC[Offset], Vals: OC[Offset + 1], Vals: Reg, Vals: Off); |
720 | else |
721 | SW.startLine() << format(Fmt: "0x%02x%02x ; ldr x%u, [sp], #%u\n" , |
722 | Vals: OC[Offset], Vals: OC[Offset + 1], Vals: Reg, Vals: Off); |
723 | Offset += 2; |
724 | return false; |
725 | } |
726 | |
727 | bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset, |
728 | unsigned Length, bool Prologue) { |
729 | uint32_t Reg = (OC[Offset] & 0x01) << 8; |
730 | Reg |= (OC[Offset + 1] & 0xC0); |
731 | Reg >>= 6; |
732 | Reg *= 2; |
733 | Reg += 19; |
734 | uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; |
735 | SW.startLine() << format(Fmt: "0x%02x%02x ; %s x%u, lr, [sp, #%u]\n" , |
736 | Vals: OC[Offset], Vals: OC[Offset + 1], |
737 | Vals: static_cast<const char *>(Prologue ? "stp" : "ldp" ), |
738 | Vals: Reg, Vals: Off); |
739 | Offset += 2; |
740 | return false; |
741 | } |
742 | |
743 | bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset, |
744 | unsigned Length, bool Prologue) { |
745 | uint32_t Reg = (OC[Offset] & 0x01) << 8; |
746 | Reg |= (OC[Offset + 1] & 0xC0); |
747 | Reg >>= 6; |
748 | Reg += 8; |
749 | uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; |
750 | SW.startLine() << format(Fmt: "0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n" , |
751 | Vals: OC[Offset], Vals: OC[Offset + 1], |
752 | Vals: static_cast<const char *>(Prologue ? "stp" : "ldp" ), |
753 | Vals: Reg, Vals: Reg + 1, Vals: Off); |
754 | Offset += 2; |
755 | return false; |
756 | } |
757 | |
758 | bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset, |
759 | unsigned Length, bool Prologue) { |
760 | uint32_t Reg = (OC[Offset] & 0x01) << 8; |
761 | Reg |= (OC[Offset + 1] & 0xC0); |
762 | Reg >>= 6; |
763 | Reg += 8; |
764 | uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; |
765 | if (Prologue) |
766 | SW.startLine() << format( |
767 | Fmt: "0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n" , Vals: OC[Offset], |
768 | Vals: OC[Offset + 1], Vals: Reg, Vals: Reg + 1, Vals: Off); |
769 | else |
770 | SW.startLine() << format( |
771 | Fmt: "0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n" , Vals: OC[Offset], |
772 | Vals: OC[Offset + 1], Vals: Reg, Vals: Reg + 1, Vals: Off); |
773 | Offset += 2; |
774 | return false; |
775 | } |
776 | |
777 | bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset, |
778 | unsigned Length, bool Prologue) { |
779 | uint32_t Reg = (OC[Offset] & 0x01) << 8; |
780 | Reg |= (OC[Offset + 1] & 0xC0); |
781 | Reg >>= 6; |
782 | Reg += 8; |
783 | uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; |
784 | SW.startLine() << format(Fmt: "0x%02x%02x ; %s d%u, [sp, #%u]\n" , |
785 | Vals: OC[Offset], Vals: OC[Offset + 1], |
786 | Vals: static_cast<const char *>(Prologue ? "str" : "ldr" ), |
787 | Vals: Reg, Vals: Off); |
788 | Offset += 2; |
789 | return false; |
790 | } |
791 | |
792 | bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset, |
793 | unsigned Length, bool Prologue) { |
794 | uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8; |
795 | uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; |
796 | if (Prologue) |
797 | SW.startLine() << format( |
798 | Fmt: "0x%02x%02x ; str d%u, [sp, #-%u]!\n" , Vals: OC[Offset], |
799 | Vals: OC[Offset + 1], Vals: Reg, Vals: Off); |
800 | else |
801 | SW.startLine() << format( |
802 | Fmt: "0x%02x%02x ; ldr d%u, [sp], #%u\n" , Vals: OC[Offset], |
803 | Vals: OC[Offset + 1], Vals: Reg, Vals: Off); |
804 | Offset += 2; |
805 | return false; |
806 | } |
807 | |
808 | bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset, |
809 | unsigned Length, bool Prologue) { |
810 | unsigned Off = |
811 | (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0); |
812 | Off <<= 4; |
813 | SW.startLine() << format( |
814 | Fmt: "0x%02x%02x%02x%02x ; %s sp, #%u\n" , Vals: OC[Offset], Vals: OC[Offset + 1], |
815 | Vals: OC[Offset + 2], Vals: OC[Offset + 3], |
816 | Vals: static_cast<const char *>(Prologue ? "sub" : "add" ), Vals: Off); |
817 | Offset += 4; |
818 | return false; |
819 | } |
820 | |
821 | bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, |
822 | bool Prologue) { |
823 | SW.startLine() << format(Fmt: "0x%02x ; mov %s, %s\n" , Vals: OC[Offset], |
824 | Vals: static_cast<const char *>(Prologue ? "fp" : "sp" ), |
825 | Vals: static_cast<const char *>(Prologue ? "sp" : "fp" )); |
826 | ++Offset; |
827 | return false; |
828 | } |
829 | |
830 | bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length, |
831 | bool Prologue) { |
832 | unsigned NumBytes = OC[Offset + 1] << 3; |
833 | SW.startLine() << format( |
834 | Fmt: "0x%02x%02x ; %s %s, %s, #%u\n" , Vals: OC[Offset], Vals: OC[Offset + 1], |
835 | Vals: static_cast<const char *>(Prologue ? "add" : "sub" ), |
836 | Vals: static_cast<const char *>(Prologue ? "fp" : "sp" ), |
837 | Vals: static_cast<const char *>(Prologue ? "sp" : "fp" ), Vals: NumBytes); |
838 | Offset += 2; |
839 | return false; |
840 | } |
841 | |
842 | bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length, |
843 | bool Prologue) { |
844 | SW.startLine() << format(Fmt: "0x%02x ; nop\n" , Vals: OC[Offset]); |
845 | ++Offset; |
846 | return false; |
847 | } |
848 | |
849 | bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length, |
850 | bool Prologue) { |
851 | SW.startLine() << format(Fmt: "0x%02x ; end\n" , Vals: OC[Offset]); |
852 | ++Offset; |
853 | return true; |
854 | } |
855 | |
856 | bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length, |
857 | bool Prologue) { |
858 | SW.startLine() << format(Fmt: "0x%02x ; end_c\n" , Vals: OC[Offset]); |
859 | ++Offset; |
860 | return false; |
861 | } |
862 | |
863 | bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset, |
864 | unsigned Length, bool Prologue) { |
865 | if (Prologue) |
866 | SW.startLine() << format(Fmt: "0x%02x ; save next\n" , Vals: OC[Offset]); |
867 | else |
868 | SW.startLine() << format(Fmt: "0x%02x ; restore next\n" , |
869 | Vals: OC[Offset]); |
870 | ++Offset; |
871 | return false; |
872 | } |
873 | |
874 | bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset, |
875 | unsigned Length, bool Prologue) { |
876 | // Whether the instruction has writeback |
877 | bool Writeback = (OC[Offset + 1] & 0x20) == 0x20; |
878 | // Whether the instruction is paired. (Paired instructions are required |
879 | // to save/restore adjacent registers.) |
880 | bool Paired = (OC[Offset + 1] & 0x40) == 0x40; |
881 | // The kind of register saved: |
882 | // - 0 is an x register |
883 | // - 1 is the low half of a q register |
884 | // - 2 is a whole q register |
885 | int RegKind = (OC[Offset + 2] & 0xC0) >> 6; |
886 | // Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.) |
887 | int Reg = OC[Offset + 1] & 0x1F; |
888 | // Encoded stack offset of load/store instruction; decoding varies by mode. |
889 | int StackOffset = OC[Offset + 2] & 0x3F; |
890 | if (Writeback) |
891 | StackOffset++; |
892 | if (!Writeback && !Paired && RegKind != 2) |
893 | StackOffset *= 8; |
894 | else |
895 | StackOffset *= 16; |
896 | |
897 | SW.startLine() << format(Fmt: "0x%02x%02x%02x ; " , Vals: OC[Offset], |
898 | Vals: OC[Offset + 1], Vals: OC[Offset + 2]); |
899 | |
900 | // Verify the encoding is in a form we understand. The high bit of the first |
901 | // byte, and mode 3 for the register kind are apparently reserved. The |
902 | // encoded register must refer to a valid register. |
903 | int MaxReg = 0x1F; |
904 | if (Paired) |
905 | --MaxReg; |
906 | if (RegKind == 0) |
907 | --MaxReg; |
908 | if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) { |
909 | SW.getOStream() << "invalid save_any_reg encoding\n" ; |
910 | Offset += 3; |
911 | return false; |
912 | } |
913 | |
914 | if (Paired) { |
915 | if (Prologue) |
916 | SW.getOStream() << "stp " ; |
917 | else |
918 | SW.getOStream() << "ldp " ; |
919 | } else { |
920 | if (Prologue) |
921 | SW.getOStream() << "str " ; |
922 | else |
923 | SW.getOStream() << "ldr " ; |
924 | } |
925 | |
926 | char RegChar = 'x'; |
927 | if (RegKind == 1) { |
928 | RegChar = 'd'; |
929 | } else if (RegKind == 2) { |
930 | RegChar = 'q'; |
931 | } |
932 | |
933 | if (Paired) |
934 | SW.getOStream() << format(Fmt: "%c%d, %c%d, " , Vals: RegChar, Vals: Reg, Vals: RegChar, Vals: Reg + 1); |
935 | else |
936 | SW.getOStream() << format(Fmt: "%c%d, " , Vals: RegChar, Vals: Reg); |
937 | |
938 | if (Writeback) { |
939 | if (Prologue) |
940 | SW.getOStream() << format(Fmt: "[sp, #-%d]!\n" , Vals: StackOffset); |
941 | else |
942 | SW.getOStream() << format(Fmt: "[sp], #%d\n" , Vals: StackOffset); |
943 | } else { |
944 | SW.getOStream() << format(Fmt: "[sp, #%d]\n" , Vals: StackOffset); |
945 | } |
946 | |
947 | Offset += 3; |
948 | return false; |
949 | } |
950 | |
951 | bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset, |
952 | unsigned Length, bool Prologue) { |
953 | SW.startLine() << format(Fmt: "0x%02x ; trap frame\n" , Vals: OC[Offset]); |
954 | ++Offset; |
955 | return false; |
956 | } |
957 | |
958 | bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset, |
959 | unsigned Length, bool Prologue) { |
960 | SW.startLine() << format(Fmt: "0x%02x ; machine frame\n" , |
961 | Vals: OC[Offset]); |
962 | ++Offset; |
963 | return false; |
964 | } |
965 | |
966 | bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset, |
967 | unsigned Length, bool Prologue) { |
968 | SW.startLine() << format(Fmt: "0x%02x ; context\n" , Vals: OC[Offset]); |
969 | ++Offset; |
970 | return false; |
971 | } |
972 | |
973 | bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset, |
974 | unsigned Length, bool Prologue) { |
975 | SW.startLine() << format(Fmt: "0x%02x ; EC context\n" , Vals: OC[Offset]); |
976 | ++Offset; |
977 | return false; |
978 | } |
979 | |
980 | bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset, |
981 | unsigned Length, bool Prologue) { |
982 | SW.startLine() << format(Fmt: "0x%02x ; clear unwound to call\n" , |
983 | Vals: OC[Offset]); |
984 | ++Offset; |
985 | return false; |
986 | } |
987 | |
988 | bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset, |
989 | unsigned Length, bool Prologue) { |
990 | if (Prologue) |
991 | SW.startLine() << format(Fmt: "0x%02x ; pacibsp\n" , Vals: OC[Offset]); |
992 | else |
993 | SW.startLine() << format(Fmt: "0x%02x ; autibsp\n" , Vals: OC[Offset]); |
994 | ++Offset; |
995 | return false; |
996 | } |
997 | |
998 | void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, |
999 | bool Prologue) { |
1000 | assert((!Prologue || Offset == 0) && "prologue should always use offset 0" ); |
1001 | const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring; |
1002 | bool Terminated = false; |
1003 | for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { |
1004 | for (unsigned DI = 0;; ++DI) { |
1005 | if ((isAArch64 && (DI >= std::size(Ring64))) || |
1006 | (!isAArch64 && (DI >= std::size(Ring)))) { |
1007 | SW.startLine() << format(Fmt: "0x%02x ; Bad opcode!\n" , |
1008 | Vals: Opcodes.data()[OI]); |
1009 | ++OI; |
1010 | break; |
1011 | } |
1012 | |
1013 | if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) { |
1014 | if (OI + DecodeRing[DI].Length > OE) { |
1015 | SW.startLine() << format(Fmt: "Opcode 0x%02x goes past the unwind data\n" , |
1016 | Vals: Opcodes[OI]); |
1017 | OI += DecodeRing[DI].Length; |
1018 | break; |
1019 | } |
1020 | Terminated = |
1021 | (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue); |
1022 | break; |
1023 | } |
1024 | } |
1025 | } |
1026 | } |
1027 | |
1028 | bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, |
1029 | const SectionRef &Section, |
1030 | uint64_t FunctionAddress, uint64_t VA) { |
1031 | ArrayRef<uint8_t> Contents; |
1032 | if (COFF.getSectionContents(Sec: COFF.getCOFFSection(Section), Res&: Contents)) |
1033 | return false; |
1034 | |
1035 | uint64_t SectionVA = Section.getAddress(); |
1036 | uint64_t Offset = VA - SectionVA; |
1037 | const ulittle32_t *Data = |
1038 | reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); |
1039 | |
1040 | // Sanity check to ensure that the .xdata header is present. |
1041 | // A header is one or two words, followed by at least one word to describe |
1042 | // the unwind codes. Applicable to both ARM and AArch64. |
1043 | if (Contents.size() - Offset < 8) |
1044 | report_fatal_error(reason: ".xdata must be at least 8 bytes in size" ); |
1045 | |
1046 | const ExceptionDataRecord XData(Data, isAArch64); |
1047 | DictScope XRS(SW, "ExceptionData" ); |
1048 | SW.printNumber(Label: "FunctionLength" , |
1049 | Value: isAArch64 ? XData.FunctionLengthInBytesAArch64() : |
1050 | XData.FunctionLengthInBytesARM()); |
1051 | SW.printNumber(Label: "Version" , Value: XData.Vers()); |
1052 | SW.printBoolean(Label: "ExceptionData" , Value: XData.X()); |
1053 | SW.printBoolean(Label: "EpiloguePacked" , Value: XData.E()); |
1054 | if (!isAArch64) |
1055 | SW.printBoolean(Label: "Fragment" , Value: XData.F()); |
1056 | SW.printNumber(Label: XData.E() ? "EpilogueOffset" : "EpilogueScopes" , |
1057 | Value: XData.EpilogueCount()); |
1058 | uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t); |
1059 | SW.printNumber(Label: "ByteCodeLength" , Value: ByteCodeLength); |
1060 | |
1061 | if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XR: XData) - |
1062 | (XData.E() ? 0 : XData.EpilogueCount() * 4) - |
1063 | (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { |
1064 | SW.flush(); |
1065 | report_fatal_error(reason: "Malformed unwind data" ); |
1066 | } |
1067 | |
1068 | if (XData.E()) { |
1069 | ArrayRef<uint8_t> UC = XData.UnwindByteCode(); |
1070 | { |
1071 | ListScope PS(SW, "Prologue" ); |
1072 | decodeOpcodes(Opcodes: UC, Offset: 0, /*Prologue=*/true); |
1073 | } |
1074 | if (XData.EpilogueCount()) { |
1075 | ListScope ES(SW, "Epilogue" ); |
1076 | decodeOpcodes(Opcodes: UC, Offset: XData.EpilogueCount(), /*Prologue=*/false); |
1077 | } |
1078 | } else { |
1079 | { |
1080 | ListScope PS(SW, "Prologue" ); |
1081 | decodeOpcodes(Opcodes: XData.UnwindByteCode(), Offset: 0, /*Prologue=*/true); |
1082 | } |
1083 | ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); |
1084 | ListScope ESS(SW, "EpilogueScopes" ); |
1085 | for (const EpilogueScope ES : EpilogueScopes) { |
1086 | DictScope ESES(SW, "EpilogueScope" ); |
1087 | SW.printNumber(Label: "StartOffset" , Value: ES.EpilogueStartOffset()); |
1088 | if (!isAArch64) |
1089 | SW.printNumber(Label: "Condition" , Value: ES.Condition()); |
1090 | SW.printNumber(Label: "EpilogueStartIndex" , |
1091 | Value: isAArch64 ? ES.EpilogueStartIndexAArch64() |
1092 | : ES.EpilogueStartIndexARM()); |
1093 | unsigned ReservedMask = isAArch64 ? 0xF : 0x3; |
1094 | if ((ES.ES >> 18) & ReservedMask) |
1095 | SW.printNumber(Label: "ReservedBits" , Value: (ES.ES >> 18) & ReservedMask); |
1096 | |
1097 | ListScope Opcodes(SW, "Opcodes" ); |
1098 | decodeOpcodes(Opcodes: XData.UnwindByteCode(), |
1099 | Offset: isAArch64 ? ES.EpilogueStartIndexAArch64() |
1100 | : ES.EpilogueStartIndexARM(), |
1101 | /*Prologue=*/false); |
1102 | } |
1103 | } |
1104 | |
1105 | if (XData.X()) { |
1106 | const uint32_t Parameter = XData.ExceptionHandlerParameter(); |
1107 | const size_t HandlerOffset = HeaderWords(XR: XData) + |
1108 | (XData.E() ? 0 : XData.EpilogueCount()) + |
1109 | XData.CodeWords(); |
1110 | |
1111 | uint64_t Address, SymbolOffset; |
1112 | ErrorOr<SymbolRef> Symbol = getSymbolForLocation( |
1113 | COFF, Section, OffsetInSection: Offset + HandlerOffset * sizeof(uint32_t), |
1114 | ImmediateOffset: XData.ExceptionHandlerRVA(), SymbolAddress&: Address, SymbolOffset, |
1115 | /*FunctionOnly=*/true); |
1116 | if (!Symbol) { |
1117 | ListScope EHS(SW, "ExceptionHandler" ); |
1118 | SW.printHex(Label: "Routine" , Value: Address); |
1119 | SW.printHex(Label: "Parameter" , Value: Parameter); |
1120 | return true; |
1121 | } |
1122 | |
1123 | Expected<StringRef> Name = Symbol->getName(); |
1124 | if (!Name) { |
1125 | std::string Buf; |
1126 | llvm::raw_string_ostream OS(Buf); |
1127 | logAllUnhandledErrors(E: Name.takeError(), OS); |
1128 | report_fatal_error(reason: Twine(OS.str())); |
1129 | } |
1130 | |
1131 | ListScope EHS(SW, "ExceptionHandler" ); |
1132 | SW.printString(Label: "Routine" , Value: formatSymbol(Name: *Name, Address, Offset: SymbolOffset)); |
1133 | SW.printHex(Label: "Parameter" , Value: Parameter); |
1134 | } |
1135 | |
1136 | return true; |
1137 | } |
1138 | |
1139 | bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, |
1140 | const SectionRef Section, uint64_t Offset, |
1141 | unsigned Index, const RuntimeFunction &RF) { |
1142 | assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && |
1143 | "packed entry cannot be treated as an unpacked entry" ); |
1144 | |
1145 | uint64_t FunctionAddress, FunctionOffset; |
1146 | ErrorOr<SymbolRef> Function = getSymbolForLocation( |
1147 | COFF, Section, OffsetInSection: Offset, ImmediateOffset: RF.BeginAddress, SymbolAddress&: FunctionAddress, SymbolOffset&: FunctionOffset, |
1148 | /*FunctionOnly=*/true); |
1149 | |
1150 | uint64_t XDataAddress, XDataOffset; |
1151 | ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation( |
1152 | COFF, Section, OffsetInSection: Offset + 4, ImmediateOffset: RF.ExceptionInformationRVA(), SymbolAddress&: XDataAddress, |
1153 | SymbolOffset&: XDataOffset); |
1154 | |
1155 | if (!RF.BeginAddress && !Function) |
1156 | return false; |
1157 | if (!RF.UnwindData && !XDataRecord) |
1158 | return false; |
1159 | |
1160 | StringRef FunctionName; |
1161 | if (Function) { |
1162 | Expected<StringRef> FunctionNameOrErr = Function->getName(); |
1163 | if (!FunctionNameOrErr) { |
1164 | std::string Buf; |
1165 | llvm::raw_string_ostream OS(Buf); |
1166 | logAllUnhandledErrors(E: FunctionNameOrErr.takeError(), OS); |
1167 | report_fatal_error(reason: Twine(OS.str())); |
1168 | } |
1169 | FunctionName = *FunctionNameOrErr; |
1170 | } |
1171 | |
1172 | SW.printString(Label: "Function" , |
1173 | Value: formatSymbol(Name: FunctionName, Address: FunctionAddress, Offset: FunctionOffset)); |
1174 | |
1175 | if (XDataRecord) { |
1176 | Expected<StringRef> Name = XDataRecord->getName(); |
1177 | if (!Name) { |
1178 | std::string Buf; |
1179 | llvm::raw_string_ostream OS(Buf); |
1180 | logAllUnhandledErrors(E: Name.takeError(), OS); |
1181 | report_fatal_error(reason: Twine(OS.str())); |
1182 | } |
1183 | |
1184 | SW.printString(Label: "ExceptionRecord" , |
1185 | Value: formatSymbol(Name: *Name, Address: XDataAddress, Offset: XDataOffset)); |
1186 | |
1187 | Expected<section_iterator> SIOrErr = XDataRecord->getSection(); |
1188 | if (!SIOrErr) { |
1189 | // TODO: Actually report errors helpfully. |
1190 | consumeError(Err: SIOrErr.takeError()); |
1191 | return false; |
1192 | } |
1193 | section_iterator SI = *SIOrErr; |
1194 | |
1195 | return dumpXDataRecord(COFF, Section: *SI, FunctionAddress, VA: XDataAddress); |
1196 | } else { |
1197 | SW.printString(Label: "ExceptionRecord" , Value: formatSymbol(Name: "" , Address: XDataAddress)); |
1198 | |
1199 | ErrorOr<SectionRef> Section = getSectionContaining(COFF, VA: XDataAddress); |
1200 | if (!Section) |
1201 | return false; |
1202 | |
1203 | return dumpXDataRecord(COFF, Section: *Section, FunctionAddress, VA: XDataAddress); |
1204 | } |
1205 | } |
1206 | |
1207 | bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, |
1208 | const SectionRef Section, uint64_t Offset, |
1209 | unsigned Index, const RuntimeFunction &RF) { |
1210 | assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || |
1211 | RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && |
1212 | "unpacked entry cannot be treated as a packed entry" ); |
1213 | |
1214 | uint64_t FunctionAddress, FunctionOffset; |
1215 | ErrorOr<SymbolRef> Function = getSymbolForLocation( |
1216 | COFF, Section, OffsetInSection: Offset, ImmediateOffset: RF.BeginAddress, SymbolAddress&: FunctionAddress, SymbolOffset&: FunctionOffset, |
1217 | /*FunctionOnly=*/true); |
1218 | |
1219 | StringRef FunctionName; |
1220 | if (Function) { |
1221 | Expected<StringRef> FunctionNameOrErr = Function->getName(); |
1222 | if (!FunctionNameOrErr) { |
1223 | std::string Buf; |
1224 | llvm::raw_string_ostream OS(Buf); |
1225 | logAllUnhandledErrors(E: FunctionNameOrErr.takeError(), OS); |
1226 | report_fatal_error(reason: Twine(OS.str())); |
1227 | } |
1228 | FunctionName = *FunctionNameOrErr; |
1229 | } |
1230 | |
1231 | SW.printString(Label: "Function" , |
1232 | Value: formatSymbol(Name: FunctionName, Address: FunctionAddress, Offset: FunctionOffset)); |
1233 | SW.printBoolean(Label: "Fragment" , |
1234 | Value: RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); |
1235 | SW.printNumber(Label: "FunctionLength" , Value: RF.FunctionLength()); |
1236 | SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; |
1237 | SW.printBoolean(Label: "HomedParameters" , Value: RF.H()); |
1238 | SW.printNumber(Label: "Reg" , Value: RF.Reg()); |
1239 | SW.printNumber(Label: "R" , Value: RF.R()); |
1240 | SW.printBoolean(Label: "LinkRegister" , Value: RF.L()); |
1241 | SW.printBoolean(Label: "Chaining" , Value: RF.C()); |
1242 | SW.printNumber(Label: "StackAdjustment" , Value: StackAdjustment(RF) << 2); |
1243 | |
1244 | { |
1245 | ListScope PS(SW, "Prologue" ); |
1246 | |
1247 | uint16_t GPRMask, VFPMask; |
1248 | std::tie(args&: GPRMask, args&: VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true); |
1249 | |
1250 | if (StackAdjustment(RF) && !PrologueFolding(RF)) |
1251 | SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n" ; |
1252 | if (VFPMask) { |
1253 | SW.startLine() << "vpush " ; |
1254 | printVFPMask(VFPMask); |
1255 | OS << "\n" ; |
1256 | } |
1257 | if (RF.C()) { |
1258 | // Count the number of registers pushed below R11 |
1259 | int FpOffset = 4 * llvm::popcount(Value: GPRMask & ((1U << 11) - 1)); |
1260 | if (FpOffset) |
1261 | SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n" ; |
1262 | else |
1263 | SW.startLine() << "mov r11, sp\n" ; |
1264 | } |
1265 | if (GPRMask) { |
1266 | SW.startLine() << "push " ; |
1267 | printGPRMask(GPRMask); |
1268 | OS << "\n" ; |
1269 | } |
1270 | if (RF.H()) |
1271 | SW.startLine() << "push {r0-r3}\n" ; |
1272 | } |
1273 | |
1274 | if (RF.Ret() != ReturnType::RT_NoEpilogue) { |
1275 | ListScope PS(SW, "Epilogue" ); |
1276 | |
1277 | uint16_t GPRMask, VFPMask; |
1278 | std::tie(args&: GPRMask, args&: VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false); |
1279 | |
1280 | if (StackAdjustment(RF) && !EpilogueFolding(RF)) |
1281 | SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n" ; |
1282 | if (VFPMask) { |
1283 | SW.startLine() << "vpop " ; |
1284 | printVFPMask(VFPMask); |
1285 | OS << "\n" ; |
1286 | } |
1287 | if (GPRMask) { |
1288 | SW.startLine() << "pop " ; |
1289 | printGPRMask(GPRMask); |
1290 | OS << "\n" ; |
1291 | } |
1292 | if (RF.H()) { |
1293 | if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP) |
1294 | SW.startLine() << "add sp, sp, #16\n" ; |
1295 | else |
1296 | SW.startLine() << "ldr pc, [sp], #20\n" ; |
1297 | } |
1298 | if (RF.Ret() != ReturnType::RT_POP) |
1299 | SW.startLine() << RF.Ret() << '\n'; |
1300 | } |
1301 | |
1302 | return true; |
1303 | } |
1304 | |
1305 | bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF, |
1306 | const SectionRef Section, uint64_t Offset, |
1307 | unsigned Index, |
1308 | const RuntimeFunctionARM64 &RF) { |
1309 | assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || |
1310 | RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && |
1311 | "unpacked entry cannot be treated as a packed entry" ); |
1312 | |
1313 | uint64_t FunctionAddress, FunctionOffset; |
1314 | ErrorOr<SymbolRef> Function = getSymbolForLocation( |
1315 | COFF, Section, OffsetInSection: Offset, ImmediateOffset: RF.BeginAddress, SymbolAddress&: FunctionAddress, SymbolOffset&: FunctionOffset, |
1316 | /*FunctionOnly=*/true); |
1317 | |
1318 | StringRef FunctionName; |
1319 | if (Function) { |
1320 | Expected<StringRef> FunctionNameOrErr = Function->getName(); |
1321 | if (!FunctionNameOrErr) { |
1322 | std::string Buf; |
1323 | llvm::raw_string_ostream OS(Buf); |
1324 | logAllUnhandledErrors(E: FunctionNameOrErr.takeError(), OS); |
1325 | report_fatal_error(reason: Twine(OS.str())); |
1326 | } |
1327 | FunctionName = *FunctionNameOrErr; |
1328 | } |
1329 | |
1330 | SW.printString(Label: "Function" , |
1331 | Value: formatSymbol(Name: FunctionName, Address: FunctionAddress, Offset: FunctionOffset)); |
1332 | SW.printBoolean(Label: "Fragment" , |
1333 | Value: RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); |
1334 | SW.printNumber(Label: "FunctionLength" , Value: RF.FunctionLength()); |
1335 | SW.printNumber(Label: "RegF" , Value: RF.RegF()); |
1336 | SW.printNumber(Label: "RegI" , Value: RF.RegI()); |
1337 | SW.printBoolean(Label: "HomedParameters" , Value: RF.H()); |
1338 | SW.printNumber(Label: "CR" , Value: RF.CR()); |
1339 | SW.printNumber(Label: "FrameSize" , Value: RF.FrameSize() << 4); |
1340 | ListScope PS(SW, "Prologue" ); |
1341 | |
1342 | // Synthesize the equivalent prologue according to the documentation |
1343 | // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling, |
1344 | // printed in reverse order compared to the docs, to match how prologues |
1345 | // are printed for the non-packed case. |
1346 | int IntSZ = 8 * RF.RegI(); |
1347 | if (RF.CR() == 1) |
1348 | IntSZ += 8; |
1349 | int FpSZ = 8 * RF.RegF(); |
1350 | if (RF.RegF()) |
1351 | FpSZ += 8; |
1352 | int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf; |
1353 | int LocSZ = (RF.FrameSize() << 4) - SavSZ; |
1354 | |
1355 | if (RF.CR() == 2 || RF.CR() == 3) { |
1356 | SW.startLine() << "mov x29, sp\n" ; |
1357 | if (LocSZ <= 512) { |
1358 | SW.startLine() << format(Fmt: "stp x29, lr, [sp, #-%d]!\n" , Vals: LocSZ); |
1359 | } else { |
1360 | SW.startLine() << "stp x29, lr, [sp, #0]\n" ; |
1361 | } |
1362 | } |
1363 | if (LocSZ > 4080) { |
1364 | SW.startLine() << format(Fmt: "sub sp, sp, #%d\n" , Vals: LocSZ - 4080); |
1365 | SW.startLine() << "sub sp, sp, #4080\n" ; |
1366 | } else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) { |
1367 | SW.startLine() << format(Fmt: "sub sp, sp, #%d\n" , Vals: LocSZ); |
1368 | } |
1369 | if (RF.H()) { |
1370 | SW.startLine() << format(Fmt: "stp x6, x7, [sp, #%d]\n" , Vals: SavSZ - 16); |
1371 | SW.startLine() << format(Fmt: "stp x4, x5, [sp, #%d]\n" , Vals: SavSZ - 32); |
1372 | SW.startLine() << format(Fmt: "stp x2, x3, [sp, #%d]\n" , Vals: SavSZ - 48); |
1373 | if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) { |
1374 | SW.startLine() << format(Fmt: "stp x0, x1, [sp, #%d]\n" , Vals: SavSZ - 64); |
1375 | } else { |
1376 | // This case isn't documented; if neither RegI nor RegF nor CR=1 |
1377 | // have decremented the stack pointer by SavSZ, we need to do it here |
1378 | // (as the final stack adjustment of LocSZ excludes SavSZ). |
1379 | SW.startLine() << format(Fmt: "stp x0, x1, [sp, #-%d]!\n" , Vals: SavSZ); |
1380 | } |
1381 | } |
1382 | int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0; |
1383 | for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) { |
1384 | if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) { |
1385 | // The last register, an odd register without a pair |
1386 | SW.startLine() << format(Fmt: "str d%d, [sp, #%d]\n" , Vals: 8 + 2 * I, |
1387 | Vals: IntSZ + 16 * I); |
1388 | } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) { |
1389 | SW.startLine() << format(Fmt: "stp d%d, d%d, [sp, #-%d]!\n" , Vals: 8 + 2 * I, |
1390 | Vals: 8 + 2 * I + 1, Vals: SavSZ); |
1391 | } else { |
1392 | SW.startLine() << format(Fmt: "stp d%d, d%d, [sp, #%d]\n" , Vals: 8 + 2 * I, |
1393 | Vals: 8 + 2 * I + 1, Vals: IntSZ + 16 * I); |
1394 | } |
1395 | } |
1396 | if (RF.CR() == 1 && (RF.RegI() % 2) == 0) { |
1397 | if (RF.RegI() == 0) |
1398 | SW.startLine() << format(Fmt: "str lr, [sp, #-%d]!\n" , Vals: SavSZ); |
1399 | else |
1400 | SW.startLine() << format(Fmt: "str lr, [sp, #%d]\n" , Vals: IntSZ - 8); |
1401 | } |
1402 | for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) { |
1403 | if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) { |
1404 | // The last register, an odd register without a pair |
1405 | if (RF.CR() == 1) { |
1406 | if (I == 0) { // If this is the only register pair |
1407 | // CR=1 combined with RegI=1 doesn't map to a documented case; |
1408 | // it doesn't map to any regular unwind info opcode, and the |
1409 | // actual unwinder doesn't support it. |
1410 | SW.startLine() << "INVALID!\n" ; |
1411 | } else |
1412 | SW.startLine() << format(Fmt: "stp x%d, lr, [sp, #%d]\n" , Vals: 19 + 2 * I, |
1413 | Vals: 16 * I); |
1414 | } else { |
1415 | if (I == 0) |
1416 | SW.startLine() << format(Fmt: "str x%d, [sp, #-%d]!\n" , Vals: 19 + 2 * I, Vals: SavSZ); |
1417 | else |
1418 | SW.startLine() << format(Fmt: "str x%d, [sp, #%d]\n" , Vals: 19 + 2 * I, Vals: 16 * I); |
1419 | } |
1420 | } else if (I == 0) { |
1421 | // The first register pair |
1422 | SW.startLine() << format(Fmt: "stp x19, x20, [sp, #-%d]!\n" , Vals: SavSZ); |
1423 | } else { |
1424 | SW.startLine() << format(Fmt: "stp x%d, x%d, [sp, #%d]\n" , Vals: 19 + 2 * I, |
1425 | Vals: 19 + 2 * I + 1, Vals: 16 * I); |
1426 | } |
1427 | } |
1428 | // CR=2 is yet undocumented, see |
1429 | // https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream |
1430 | // progress on getting it documented. |
1431 | if (RF.CR() == 2) |
1432 | SW.startLine() << "pacibsp\n" ; |
1433 | SW.startLine() << "end\n" ; |
1434 | |
1435 | return true; |
1436 | } |
1437 | |
1438 | bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, |
1439 | const SectionRef Section, unsigned Index, |
1440 | ArrayRef<uint8_t> Contents) { |
1441 | uint64_t Offset = PDataEntrySize * Index; |
1442 | const ulittle32_t *Data = |
1443 | reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); |
1444 | |
1445 | const RuntimeFunction Entry(Data); |
1446 | DictScope RFS(SW, "RuntimeFunction" ); |
1447 | if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) |
1448 | return dumpUnpackedEntry(COFF, Section, Offset, Index, RF: Entry); |
1449 | if (isAArch64) { |
1450 | const RuntimeFunctionARM64 EntryARM64(Data); |
1451 | return dumpPackedARM64Entry(COFF, Section, Offset, Index, RF: EntryARM64); |
1452 | } |
1453 | return dumpPackedEntry(COFF, Section, Offset, Index, RF: Entry); |
1454 | } |
1455 | |
1456 | void Decoder::dumpProcedureData(const COFFObjectFile &COFF, |
1457 | const SectionRef Section) { |
1458 | ArrayRef<uint8_t> Contents; |
1459 | if (COFF.getSectionContents(Sec: COFF.getCOFFSection(Section), Res&: Contents)) |
1460 | return; |
1461 | |
1462 | if (Contents.size() % PDataEntrySize) { |
1463 | errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n" ; |
1464 | return; |
1465 | } |
1466 | |
1467 | for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) |
1468 | if (!dumpProcedureDataEntry(COFF, Section, Index: EI, Contents)) |
1469 | break; |
1470 | } |
1471 | |
1472 | Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) { |
1473 | for (const auto &Section : COFF.sections()) { |
1474 | Expected<StringRef> NameOrErr = |
1475 | COFF.getSectionName(Sec: COFF.getCOFFSection(Section)); |
1476 | if (!NameOrErr) |
1477 | return NameOrErr.takeError(); |
1478 | |
1479 | if (NameOrErr->starts_with(Prefix: ".pdata" )) |
1480 | dumpProcedureData(COFF, Section); |
1481 | } |
1482 | return Error::success(); |
1483 | } |
1484 | } |
1485 | } |
1486 | } |
1487 | |