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" 67#include "llvm/ADT/STLExtras.h" 68#include "llvm/ADT/StringExtras.h" 69#include "llvm/Support/ARMWinEH.h" 70#include "llvm/Support/Format.h" 71 72using namespace llvm; 73using namespace llvm::object; 74using namespace llvm::support; 75 76namespace llvm { 77raw_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 96static 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 114namespace llvm { 115namespace ARM { 116namespace WinEH { 117const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); 118 119// TODO name the uops more appropriately 120const 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 148void 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 186ErrorOr<object::SectionRef> 187Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { 188 for (const auto &Section : COFF.sections()) { 189 uint64_t Address = Section.getAddress(); 190 uint64_t Size = Section.getSize(); 191 192 if (VA >= Address && (VA - Address) <= Size) 193 return Section; 194 } 195 return readobj_error::unknown_symbol; 196} 197 198ErrorOr<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 218ErrorOr<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 231bool 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 242bool 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 261bool 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 273bool 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 290bool 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 307bool 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 321bool 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 334bool 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 348bool 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 364bool 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 380bool 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 395bool 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 410bool 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 423bool 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 438bool 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 451bool 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 466bool 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 473bool 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 480bool 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 487bool 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 494bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, 495 unsigned Length, bool Prologue) { 496 ++Offset; 497 return true; 498} 499 500void 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 516bool 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 523 uint64_t SectionVA = Section.getAddress(); 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 589bool 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 654bool 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 691bool 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 705void 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 721std::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} 736