void COFFDumper::printRelocation(const SectionRef &Section, const RelocationRef &Reloc) { uint64_t Offset; uint64_t RelocType; SmallString<32> RelocName; StringRef SymbolName; StringRef Contents; if (error(Reloc.getOffset(Offset))) return; if (error(Reloc.getType(RelocType))) return; if (error(Reloc.getTypeName(RelocName))) return; symbol_iterator Symbol = Reloc.getSymbol(); if (error(Symbol->getName(SymbolName))) return; if (error(Section.getContents(Contents))) return; if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Offset); W.printNumber("Type", RelocName, RelocType); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); } else { raw_ostream& OS = W.startLine(); OS << W.hex(Offset) << " " << RelocName << " " << (SymbolName.size() > 0 ? SymbolName : "-") << "\n"; } }
void COFFDumper::printCodeViewSection(const SectionRef &Section) { StringRef Data; error(Section.getContents(Data)); SmallVector<StringRef, 10> FunctionNames; StringMap<StringRef> FunctionLineTables; ListScope D(W, "CodeViewDebugInfo"); { // FIXME: Add more offset correctness checks. DataExtractor DE(Data, true, 4); uint32_t Offset = 0, Magic = DE.getU32(&Offset); W.printHex("Magic", Magic); if (Magic != COFF::DEBUG_SECTION_MAGIC) { error(object_error::parse_failed); return; } bool Finished = false; while (DE.isValidOffset(Offset) && !Finished) { // The section consists of a number of subsection in the following format: // |Type|PayloadSize|Payload...| uint32_t SubSectionType = DE.getU32(&Offset), PayloadSize = DE.getU32(&Offset); ListScope S(W, "Subsection"); W.printHex("Type", SubSectionType); W.printHex("PayloadSize", PayloadSize); if (PayloadSize > Data.size() - Offset) { error(object_error::parse_failed); return; } StringRef Contents = Data.substr(Offset, PayloadSize); if (opts::CodeViewSubsectionBytes) { // Print the raw contents to simplify debugging if anything goes wrong // afterwards. W.printBinaryBlock("Contents", Contents); } switch (SubSectionType) { case COFF::DEBUG_SYMBOL_SUBSECTION: printCodeViewSymbolsSubsection(Contents, Section, Offset); break; case COFF::DEBUG_LINE_TABLE_SUBSECTION: { // Holds a PC to file:line table. Some data to parse this subsection is // stored in the other subsections, so just check sanity and store the // pointers for deferred processing. if (PayloadSize < 12) { // There should be at least three words to store two function // relocations and size of the code. error(object_error::parse_failed); return; } StringRef LinkageName; error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, LinkageName)); W.printString("LinkageName", LinkageName); if (FunctionLineTables.count(LinkageName) != 0) { // Saw debug info for this function already? error(object_error::parse_failed); return; } FunctionLineTables[LinkageName] = Contents; FunctionNames.push_back(LinkageName); break; } case COFF::DEBUG_STRING_TABLE_SUBSECTION: if (PayloadSize == 0 || CVStringTable.data() != nullptr || Contents.back() != '\0') { // Empty or duplicate or non-null-terminated subsection. error(object_error::parse_failed); return; } CVStringTable = Contents; break; case COFF::DEBUG_INDEX_SUBSECTION: // Holds the translation table from file indices // to offsets in the string table. if (PayloadSize == 0 || CVFileIndexToStringOffsetTable.data() != nullptr) { // Empty or duplicate subsection. error(object_error::parse_failed); return; } CVFileIndexToStringOffsetTable = Contents; break; } Offset += PayloadSize; // Align the reading pointer by 4. Offset += (-Offset) % 4; } } // Dump the line tables now that we've read all the subsections and know all // the required information. for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) { StringRef Name = FunctionNames[I]; ListScope S(W, "FunctionLineTable"); W.printString("LinkageName", Name); DataExtractor DE(FunctionLineTables[Name], true, 4); uint32_t Offset = 6; // Skip relocations. uint16_t Flags = DE.getU16(&Offset); W.printHex("Flags", Flags); bool HasColumnInformation = Flags & COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS; uint32_t FunctionSize = DE.getU32(&Offset); W.printHex("CodeSize", FunctionSize); while (DE.isValidOffset(Offset)) { // For each range of lines with the same filename, we have a segment // in the line table. The filename string is accessed using double // indirection to the string table subsection using the index subsection. uint32_t OffsetInIndex = DE.getU32(&Offset), SegmentLength = DE.getU32(&Offset), FullSegmentSize = DE.getU32(&Offset); if (FullSegmentSize != 12 + 8 * SegmentLength + (HasColumnInformation ? 4 * SegmentLength : 0)) { error(object_error::parse_failed); return; } uint32_t FilenameOffset; { DataExtractor SDE(CVFileIndexToStringOffsetTable, true, 4); uint32_t OffsetInSDE = OffsetInIndex; if (!SDE.isValidOffset(OffsetInSDE)) { error(object_error::parse_failed); return; } FilenameOffset = SDE.getU32(&OffsetInSDE); } if (FilenameOffset == 0 || FilenameOffset + 1 >= CVStringTable.size() || CVStringTable.data()[FilenameOffset - 1] != '\0') { // Each string in an F3 subsection should be preceded by a null // character. error(object_error::parse_failed); return; } StringRef Filename(CVStringTable.data() + FilenameOffset); ListScope S(W, "FilenameSegment"); W.printString("Filename", Filename); for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset); ++J) { // Then go the (PC, LineNumber) pairs. The line number is stored in the // least significant 31 bits of the respective word in the table. uint32_t PC = DE.getU32(&Offset), LineNumber = DE.getU32(&Offset) & 0x7fffffff; if (PC >= FunctionSize) { error(object_error::parse_failed); return; } char Buffer[32]; format("+0x%X", PC).snprint(Buffer, 32); W.printNumber(Buffer, LineNumber); } if (HasColumnInformation) { for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset); ++J) { uint16_t ColStart = DE.getU16(&Offset); W.printNumber("ColStart", ColStart); uint16_t ColEnd = DE.getU16(&Offset); W.printNumber("ColEnd", ColEnd); } } } } }
static void printMachOCompactUnwindSection(const MachOObjectFile *Obj, std::map<uint64_t, SymbolRef> &Symbols, const SectionRef &CompactUnwind) { assert(Obj->isLittleEndian() && "There should not be a big-endian .o with __compact_unwind"); bool Is64 = Obj->is64Bit(); uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t); uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t); StringRef Contents; CompactUnwind.getContents(Contents); SmallVector<CompactUnwindEntry, 4> CompactUnwinds; // First populate the initial raw offsets, encodings and so on from the entry. for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) { CompactUnwindEntry Entry(Contents.data(), Offset, Is64); CompactUnwinds.push_back(Entry); } // Next we need to look at the relocations to find out what objects are // actually being referred to. for (const RelocationRef &Reloc : CompactUnwind.relocations()) { uint64_t RelocAddress; Reloc.getOffset(RelocAddress); uint32_t EntryIdx = RelocAddress / EntrySize; uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize; CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx]; if (OffsetInEntry == 0) Entry.FunctionReloc = Reloc; else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t)) Entry.PersonalityReloc = Reloc; else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t)) Entry.LSDAReloc = Reloc; else llvm_unreachable("Unexpected relocation in __compact_unwind section"); } // Finally, we're ready to print the data we've gathered. outs() << "Contents of __compact_unwind section:\n"; for (auto &Entry : CompactUnwinds) { outs() << " Entry at offset " << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n"; // 1. Start of the region this entry applies to. outs() << " start: " << format("0x%" PRIx64, Entry.FunctionAddr) << ' '; printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr); outs() << '\n'; // 2. Length of the region this entry applies to. outs() << " length: " << format("0x%" PRIx32, Entry.Length) << '\n'; // 3. The 32-bit compact encoding. outs() << " compact encoding: " << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n'; // 4. The personality function, if present. if (Entry.PersonalityReloc.getObjectFile()) { outs() << " personality function: " << format("0x%" PRIx64, Entry.PersonalityAddr) << ' '; printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc, Entry.PersonalityAddr); outs() << '\n'; } // 5. This entry's language-specific data area. if (Entry.LSDAReloc.getObjectFile()) { outs() << " LSDA: " << format("0x%" PRIx64, Entry.LSDAAddr) << ' '; printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr); outs() << '\n'; } } }
unsigned RuntimeDyldImpl::emitSection(const SectionRef &Section, bool IsCode) { unsigned StubBufSize = 0, StubSize = getMaxStubSize(); error_code err; if (StubSize > 0) { for (relocation_iterator i = Section.begin_relocations(), e = Section.end_relocations(); i != e; i.increment(err), Check(err)) StubBufSize += StubSize; } StringRef data; uint64_t Alignment64; Check(Section.getContents(data)); Check(Section.getAlignment(Alignment64)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; bool IsRequired; bool IsVirtual; bool IsZeroInit; uint64_t DataSize; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); Check(Section.isZeroInit(IsZeroInit)); Check(Section.getSize(DataSize)); unsigned Allocate; unsigned SectionID = Sections.size(); uint8_t *Addr; const char *pData = 0; // Some sections, such as debug info, don't need to be loaded for execution. // Leave those where they are. if (IsRequired) { Allocate = DataSize + StubBufSize; Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID) : MemMgr->allocateDataSection(Allocate, Alignment, SectionID); if (!Addr) report_fatal_error("Unable to allocate section memory!"); // Virtual sections have no data in the object image, so leave pData = 0 if (!IsVirtual) pData = data.data(); // Zero-initialize or copy the data from the image if (IsZeroInit || IsVirtual) memset(Addr, 0, DataSize); else memcpy(Addr, pData, DataSize); DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); } else { // Even if we didn't load the section, we need to record an entry for it // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; Addr = 0; DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); } Sections.push_back(SectionEntry(Addr, Allocate, DataSize,(uintptr_t)pData)); return SectionID; }
static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, std::map<uint64_t, SymbolRef> &Symbols, const SectionRef &UnwindInfo) { assert(Obj->isLittleEndian() && "There should not be a big-endian .o with __unwind_info"); outs() << "Contents of __unwind_info section:\n"; StringRef Contents; UnwindInfo.getContents(Contents); const char *Pos = Contents.data(); //===---------------------------------- // Section header //===---------------------------------- uint32_t Version = readNext<uint32_t>(Pos); outs() << " Version: " << format("0x%" PRIx32, Version) << '\n'; assert(Version == 1 && "only understand version 1"); uint32_t CommonEncodingsStart = readNext<uint32_t>(Pos); outs() << " Common encodings array section offset: " << format("0x%" PRIx32, CommonEncodingsStart) << '\n'; uint32_t NumCommonEncodings = readNext<uint32_t>(Pos); outs() << " Number of common encodings in array: " << format("0x%" PRIx32, NumCommonEncodings) << '\n'; uint32_t PersonalitiesStart = readNext<uint32_t>(Pos); outs() << " Personality function array section offset: " << format("0x%" PRIx32, PersonalitiesStart) << '\n'; uint32_t NumPersonalities = readNext<uint32_t>(Pos); outs() << " Number of personality functions in array: " << format("0x%" PRIx32, NumPersonalities) << '\n'; uint32_t IndicesStart = readNext<uint32_t>(Pos); outs() << " Index array section offset: " << format("0x%" PRIx32, IndicesStart) << '\n'; uint32_t NumIndices = readNext<uint32_t>(Pos); outs() << " Number of indices in array: " << format("0x%" PRIx32, NumIndices) << '\n'; //===---------------------------------- // A shared list of common encodings //===---------------------------------- // These occupy indices in the range [0, N] whenever an encoding is referenced // from a compressed 2nd level index table. In practice the linker only // creates ~128 of these, so that indices are available to embed encodings in // the 2nd level index. SmallVector<uint32_t, 64> CommonEncodings; outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n"; Pos = Contents.data() + CommonEncodingsStart; for (unsigned i = 0; i < NumCommonEncodings; ++i) { uint32_t Encoding = readNext<uint32_t>(Pos); CommonEncodings.push_back(Encoding); outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding) << '\n'; } //===---------------------------------- // Personality functions used in this executable //===---------------------------------- // There should be only a handful of these (one per source language, // roughly). Particularly since they only get 2 bits in the compact encoding. outs() << " Personality functions: (count = " << NumPersonalities << ")\n"; Pos = Contents.data() + PersonalitiesStart; for (unsigned i = 0; i < NumPersonalities; ++i) { uint32_t PersonalityFn = readNext<uint32_t>(Pos); outs() << " personality[" << i + 1 << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n'; } //===---------------------------------- // The level 1 index entries //===---------------------------------- // These specify an approximate place to start searching for the more detailed // information, sorted by PC. struct IndexEntry { uint32_t FunctionOffset; uint32_t SecondLevelPageStart; uint32_t LSDAStart; }; SmallVector<IndexEntry, 4> IndexEntries; outs() << " Top level indices: (count = " << NumIndices << ")\n"; Pos = Contents.data() + IndicesStart; for (unsigned i = 0; i < NumIndices; ++i) { IndexEntry Entry; Entry.FunctionOffset = readNext<uint32_t>(Pos); Entry.SecondLevelPageStart = readNext<uint32_t>(Pos); Entry.LSDAStart = readNext<uint32_t>(Pos); IndexEntries.push_back(Entry); outs() << " [" << i << "]: " << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset) << ", " << "2nd level page offset=" << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", " << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n'; } //===---------------------------------- // Next come the LSDA tables //===---------------------------------- // The LSDA layout is rather implicit: it's a contiguous array of entries from // the first top-level index's LSDAOffset to the last (sentinel). outs() << " LSDA descriptors:\n"; Pos = Contents.data() + IndexEntries[0].LSDAStart; int NumLSDAs = (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / (2 * sizeof(uint32_t)); for (int i = 0; i < NumLSDAs; ++i) { uint32_t FunctionOffset = readNext<uint32_t>(Pos); uint32_t LSDAOffset = readNext<uint32_t>(Pos); outs() << " [" << i << "]: " << "function offset=" << format("0x%08" PRIx32, FunctionOffset) << ", " << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n'; } //===---------------------------------- // Finally, the 2nd level indices //===---------------------------------- // Generally these are 4K in size, and have 2 possible forms: // + Regular stores up to 511 entries with disparate encodings // + Compressed stores up to 1021 entries if few enough compact encoding // values are used. outs() << " Second level indices:\n"; for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) { // The final sentinel top-level index has no associated 2nd level page if (IndexEntries[i].SecondLevelPageStart == 0) break; outs() << " Second level index[" << i << "]: " << "offset in section=" << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart) << ", " << "base function offset=" << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n'; Pos = Contents.data() + IndexEntries[i].SecondLevelPageStart; uint32_t Kind = *reinterpret_cast<const support::ulittle32_t *>(Pos); if (Kind == 2) printRegularSecondLevelUnwindPage(Pos); else if (Kind == 3) printCompressedSecondLevelUnwindPage(Pos, IndexEntries[i].FunctionOffset, CommonEncodings); else llvm_unreachable("Do not know how to print this kind of 2nd level page"); } }
unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, const SectionRef &Section, bool IsCode) { unsigned StubBufSize = 0, StubSize = getMaxStubSize(); error_code err; const ObjectFile *ObjFile = Obj.getObjectFile(); // FIXME: this is an inefficient way to handle this. We should computed the // necessary section allocation size in loadObject by walking all the sections // once. if (StubSize > 0) { for (section_iterator SI = ObjFile->begin_sections(), SE = ObjFile->end_sections(); SI != SE; SI.increment(err), Check(err)) { section_iterator RelSecI = SI->getRelocatedSection(); if (!(RelSecI == Section)) continue; for (relocation_iterator I = SI->begin_relocations(), E = SI->end_relocations(); I != E; I.increment(err), Check(err)) { StubBufSize += StubSize; } } } StringRef data; uint64_t Alignment64; Check(Section.getContents(data)); Check(Section.getAlignment(Alignment64)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; bool IsRequired; bool IsVirtual; bool IsZeroInit; bool IsReadOnly; uint64_t DataSize; StringRef Name; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); Check(Section.isZeroInit(IsZeroInit)); Check(Section.isReadOnlyData(IsReadOnly)); Check(Section.getSize(DataSize)); Check(Section.getName(Name)); if (StubSize > 0) { unsigned StubAlignment = getStubAlignment(); unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); if (StubAlignment > EndAlignment) StubBufSize += StubAlignment - EndAlignment; } unsigned Allocate; unsigned SectionID = Sections.size(); uint8_t *Addr; const char *pData = 0; // Some sections, such as debug info, don't need to be loaded for execution. // Leave those where they are. if (IsRequired) { Allocate = DataSize + StubBufSize; Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID) : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, IsReadOnly); if (!Addr) report_fatal_error("Unable to allocate section memory!"); // Virtual sections have no data in the object image, so leave pData = 0 if (!IsVirtual) pData = data.data(); // Zero-initialize or copy the data from the image if (IsZeroInit || IsVirtual) memset(Addr, 0, DataSize); else memcpy(Addr, pData, DataSize); DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); Obj.updateSectionAddress(Section, (uint64_t)Addr); } else { // Even if we didn't load the section, we need to record an entry for it // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; Addr = 0; DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); } Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); return SectionID; }
unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, const SectionRef &Section, bool IsCode) { StringRef data; uint64_t Alignment64; Check(Section.getContents(data)); Check(Section.getAlignment(Alignment64)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; bool IsRequired; bool IsVirtual; bool IsZeroInit; bool IsReadOnly; uint64_t DataSize; unsigned PaddingSize = 0; unsigned StubBufSize = 0; StringRef Name; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); Check(Section.isZeroInit(IsZeroInit)); Check(Section.isReadOnlyData(IsReadOnly)); Check(Section.getSize(DataSize)); Check(Section.getName(Name)); StubBufSize = computeSectionStubBufSize(Obj, Section); // The .eh_frame section (at least on Linux) needs an extra four bytes padded // with zeroes added at the end. For MachO objects, this section has a // slightly different name, so this won't have any effect for MachO objects. if (Name == ".eh_frame") PaddingSize = 4; uintptr_t Allocate; unsigned SectionID = Sections.size(); uint8_t *Addr; const char *pData = 0; // Some sections, such as debug info, don't need to be loaded for execution. // Leave those where they are. if (IsRequired) { Allocate = DataSize + PaddingSize + StubBufSize; Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID, Name) : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, Name, IsReadOnly); if (!Addr) report_fatal_error("Unable to allocate section memory!"); // Virtual sections have no data in the object image, so leave pData = 0 if (!IsVirtual) pData = data.data(); // Zero-initialize or copy the data from the image if (IsZeroInit || IsVirtual) memset(Addr, 0, DataSize); else memcpy(Addr, pData, DataSize); // Fill in any extra bytes we allocated for padding if (PaddingSize != 0) { memset(Addr + DataSize, 0, PaddingSize); // Update the DataSize variable so that the stub offset is set correctly. DataSize += PaddingSize; } DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); Obj.updateSectionAddress(Section, (uint64_t)Addr); } else { // Even if we didn't load the section, we need to record an entry for it // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; Addr = 0; DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); } Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); return SectionID; }