| //===-- LVBinaryReader.cpp ------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This implements the LVBinaryReader class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h" | |
| #include "llvm/Support/Errc.h" | |
| #include "llvm/Support/FormatAdapters.h" | |
| #include "llvm/Support/FormatVariadic.h" | |
| using namespace llvm; | |
| using namespace llvm::logicalview; | |
| #define DEBUG_TYPE "BinaryReader" | |
| // Function names extracted from the object symbol table. | |
| void LVSymbolTable::add(StringRef Name, LVScope *Function, | |
| LVSectionIndex SectionIndex) { | |
| std::string SymbolName(Name); | |
| if (SymbolNames.find(SymbolName) == SymbolNames.end()) { | |
| SymbolNames.emplace( | |
| std::piecewise_construct, std::forward_as_tuple(SymbolName), | |
| std::forward_as_tuple(Function, 0, SectionIndex, false)); | |
| } else { | |
| // Update a recorded entry with its logical scope and section index. | |
| SymbolNames[SymbolName].Scope = Function; | |
| if (SectionIndex) | |
| SymbolNames[SymbolName].SectionIndex = SectionIndex; | |
| } | |
| if (Function && SymbolNames[SymbolName].IsComdat) | |
| Function->setIsComdat(); | |
| LLVM_DEBUG({ print(dbgs()); }); | |
| } | |
| void LVSymbolTable::add(StringRef Name, LVAddress Address, | |
| LVSectionIndex SectionIndex, bool IsComdat) { | |
| std::string SymbolName(Name); | |
| if (SymbolNames.find(SymbolName) == SymbolNames.end()) | |
| SymbolNames.emplace( | |
| std::piecewise_construct, std::forward_as_tuple(SymbolName), | |
| std::forward_as_tuple(nullptr, Address, SectionIndex, IsComdat)); | |
| else | |
| // Update a recorded symbol name with its logical scope. | |
| SymbolNames[SymbolName].Address = Address; | |
| LVScope *Function = SymbolNames[SymbolName].Scope; | |
| if (Function && IsComdat) | |
| Function->setIsComdat(); | |
| LLVM_DEBUG({ print(dbgs()); }); | |
| } | |
| LVSectionIndex LVSymbolTable::update(LVScope *Function) { | |
| LVSectionIndex SectionIndex = getReader().getDotTextSectionIndex(); | |
| StringRef Name = Function->getLinkageName(); | |
| if (Name.empty()) | |
| Name = Function->getName(); | |
| std::string SymbolName(Name); | |
| if (SymbolName.empty() || (SymbolNames.find(SymbolName) == SymbolNames.end())) | |
| return SectionIndex; | |
| // Update a recorded entry with its logical scope, only if the scope has | |
| // ranges. That is the case when in DWARF there are 2 DIEs connected via | |
| // the DW_AT_specification. | |
| if (Function->getHasRanges()) { | |
| SymbolNames[SymbolName].Scope = Function; | |
| SectionIndex = SymbolNames[SymbolName].SectionIndex; | |
| } else { | |
| SectionIndex = UndefinedSectionIndex; | |
| } | |
| if (SymbolNames[SymbolName].IsComdat) | |
| Function->setIsComdat(); | |
| LLVM_DEBUG({ print(dbgs()); }); | |
| return SectionIndex; | |
| } | |
| const LVSymbolTableEntry &LVSymbolTable::getEntry(StringRef Name) { | |
| static LVSymbolTableEntry Empty = LVSymbolTableEntry(); | |
| LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name)); | |
| return Iter != SymbolNames.end() ? Iter->second : Empty; | |
| } | |
| LVAddress LVSymbolTable::getAddress(StringRef Name) { | |
| LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name)); | |
| return Iter != SymbolNames.end() ? Iter->second.Address : 0; | |
| } | |
| LVSectionIndex LVSymbolTable::getIndex(StringRef Name) { | |
| LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name)); | |
| return Iter != SymbolNames.end() ? Iter->second.SectionIndex | |
| : getReader().getDotTextSectionIndex(); | |
| } | |
| bool LVSymbolTable::getIsComdat(StringRef Name) { | |
| LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name)); | |
| return Iter != SymbolNames.end() ? Iter->second.IsComdat : false; | |
| } | |
| void LVSymbolTable::print(raw_ostream &OS) { | |
| OS << "Symbol Table\n"; | |
| for (LVSymbolNames::reference Entry : SymbolNames) { | |
| LVSymbolTableEntry &SymbolName = Entry.second; | |
| LVScope *Scope = SymbolName.Scope; | |
| LVOffset Offset = Scope ? Scope->getOffset() : 0; | |
| OS << "Index: " << hexValue(SymbolName.SectionIndex, 5) | |
| << " Comdat: " << (SymbolName.IsComdat ? "Y" : "N") | |
| << " Scope: " << hexValue(Offset) | |
| << " Address: " << hexValue(SymbolName.Address) | |
| << " Name: " << Entry.first << "\n"; | |
| } | |
| } | |
| void LVBinaryReader::addToSymbolTable(StringRef Name, LVScope *Function, | |
| LVSectionIndex SectionIndex) { | |
| SymbolTable.add(Name, Function, SectionIndex); | |
| } | |
| void LVBinaryReader::addToSymbolTable(StringRef Name, LVAddress Address, | |
| LVSectionIndex SectionIndex, | |
| bool IsComdat) { | |
| SymbolTable.add(Name, Address, SectionIndex, IsComdat); | |
| } | |
| LVSectionIndex LVBinaryReader::updateSymbolTable(LVScope *Function) { | |
| return SymbolTable.update(Function); | |
| } | |
| const LVSymbolTableEntry &LVBinaryReader::getSymbolTableEntry(StringRef Name) { | |
| return SymbolTable.getEntry(Name); | |
| } | |
| LVAddress LVBinaryReader::getSymbolTableAddress(StringRef Name) { | |
| return SymbolTable.getAddress(Name); | |
| } | |
| LVSectionIndex LVBinaryReader::getSymbolTableIndex(StringRef Name) { | |
| return SymbolTable.getIndex(Name); | |
| } | |
| bool LVBinaryReader::getSymbolTableIsComdat(StringRef Name) { | |
| return SymbolTable.getIsComdat(Name); | |
| } | |
| void LVBinaryReader::mapVirtualAddress(const object::ObjectFile &Obj) { | |
| for (const object::SectionRef &Section : Obj.sections()) { | |
| if (!Section.isText() || Section.isVirtual() || !Section.getSize()) | |
| continue; | |
| // Record section information required for symbol resolution. | |
| // Note: The section index returned by 'getIndex()' is one based. | |
| Sections.emplace(Section.getIndex(), Section); | |
| addSectionAddress(Section); | |
| // Identify the ".text" section. | |
| Expected<StringRef> SectionNameOrErr = Section.getName(); | |
| if (!SectionNameOrErr) { | |
| consumeError(SectionNameOrErr.takeError()); | |
| continue; | |
| } | |
| if ((*SectionNameOrErr).equals(".text") || | |
| (*SectionNameOrErr).equals(".code")) | |
| DotTextSectionIndex = Section.getIndex(); | |
| } | |
| // Process the symbol table. | |
| mapRangeAddress(Obj); | |
| LLVM_DEBUG({ | |
| dbgs() << "\nSections Information:\n"; | |
| for (LVSections::reference Entry : Sections) { | |
| LVSectionIndex SectionIndex = Entry.first; | |
| const object::SectionRef Section = Entry.second; | |
| Expected<StringRef> SectionNameOrErr = Section.getName(); | |
| if (!SectionNameOrErr) | |
| consumeError(SectionNameOrErr.takeError()); | |
| dbgs() << "\nIndex: " << format_decimal(SectionIndex, 3) | |
| << " Name: " << *SectionNameOrErr << "\n" | |
| << "Size: " << hexValue(Section.getSize()) << "\n" | |
| << "VirtualAddress: " << hexValue(VirtualAddress) << "\n" | |
| << "SectionAddress: " << hexValue(Section.getAddress()) << "\n"; | |
| } | |
| dbgs() << "\nObject Section Information:\n"; | |
| for (LVSectionAddresses::const_reference Entry : SectionAddresses) | |
| dbgs() << "[" << hexValue(Entry.first) << ":" | |
| << hexValue(Entry.first + Entry.second.getSize()) | |
| << "] Size: " << hexValue(Entry.second.getSize()) << "\n"; | |
| }); | |
| } | |
| Error LVBinaryReader::loadGenericTargetInfo(StringRef TheTriple, | |
| StringRef TheFeatures) { | |
| std::string TargetLookupError; | |
| const Target *TheTarget = | |
| TargetRegistry::lookupTarget(std::string(TheTriple), TargetLookupError); | |
| if (!TheTarget) | |
| return createStringError(errc::invalid_argument, TargetLookupError.c_str()); | |
| // Register information. | |
| MCRegisterInfo *RegisterInfo = TheTarget->createMCRegInfo(TheTriple); | |
| if (!RegisterInfo) | |
| return createStringError(errc::invalid_argument, | |
| "no register info for target " + TheTriple); | |
| MRI.reset(RegisterInfo); | |
| // Assembler properties and features. | |
| MCTargetOptions MCOptions; | |
| MCAsmInfo *AsmInfo(TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions)); | |
| if (!AsmInfo) | |
| return createStringError(errc::invalid_argument, | |
| "no assembly info for target " + TheTriple); | |
| MAI.reset(AsmInfo); | |
| // Target subtargets. | |
| StringRef CPU; | |
| MCSubtargetInfo *SubtargetInfo( | |
| TheTarget->createMCSubtargetInfo(TheTriple, CPU, TheFeatures)); | |
| if (!SubtargetInfo) | |
| return createStringError(errc::invalid_argument, | |
| "no subtarget info for target " + TheTriple); | |
| STI.reset(SubtargetInfo); | |
| // Instructions Info. | |
| MCInstrInfo *InstructionInfo(TheTarget->createMCInstrInfo()); | |
| if (!InstructionInfo) | |
| return createStringError(errc::invalid_argument, | |
| "no instruction info for target " + TheTriple); | |
| MII.reset(InstructionInfo); | |
| MC = std::make_unique<MCContext>(Triple(TheTriple), MAI.get(), MRI.get(), | |
| STI.get()); | |
| // Assembler. | |
| MCDisassembler *DisAsm(TheTarget->createMCDisassembler(*STI, *MC)); | |
| if (!DisAsm) | |
| return createStringError(errc::invalid_argument, | |
| "no disassembler for target " + TheTriple); | |
| MD.reset(DisAsm); | |
| MCInstPrinter *InstructionPrinter(TheTarget->createMCInstPrinter( | |
| Triple(TheTriple), AsmInfo->getAssemblerDialect(), *MAI, *MII, *MRI)); | |
| if (!InstructionPrinter) | |
| return createStringError(errc::invalid_argument, | |
| "no target assembly language printer for target " + | |
| TheTriple); | |
| MIP.reset(InstructionPrinter); | |
| InstructionPrinter->setPrintImmHex(true); | |
| return Error::success(); | |
| } | |
| Expected<std::pair<uint64_t, object::SectionRef>> | |
| LVBinaryReader::getSection(LVScope *Scope, LVAddress Address, | |
| LVSectionIndex SectionIndex) { | |
| // Return the 'text' section with the code for this logical scope. | |
| // COFF: SectionIndex is zero. Use 'SectionAddresses' data. | |
| // ELF: SectionIndex is the section index in the file. | |
| if (SectionIndex) { | |
| LVSections::iterator Iter = Sections.find(SectionIndex); | |
| if (Iter == Sections.end()) { | |
| return createStringError(errc::invalid_argument, | |
| "invalid section index for: '%s'", | |
| Scope->getName().str().c_str()); | |
| } | |
| const object::SectionRef Section = Iter->second; | |
| return std::make_pair(Section.getAddress(), Section); | |
| } | |
| // Ensure a valid starting address for the public names. | |
| LVSectionAddresses::const_iterator Iter = | |
| SectionAddresses.upper_bound(Address); | |
| if (Iter == SectionAddresses.begin()) | |
| return createStringError(errc::invalid_argument, | |
| "invalid section address for: '%s'", | |
| Scope->getName().str().c_str()); | |
| // Get section that contains the code for this function. | |
| Iter = SectionAddresses.lower_bound(Address); | |
| if (Iter != SectionAddresses.begin()) | |
| --Iter; | |
| return std::make_pair(Iter->first, Iter->second); | |
| } | |
| void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex, | |
| LVScope *Scope) { | |
| LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); | |
| ScopesWithRanges->addEntry(Scope); | |
| } | |
| void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex, | |
| LVScope *Scope, LVAddress LowerAddress, | |
| LVAddress UpperAddress) { | |
| LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); | |
| ScopesWithRanges->addEntry(Scope, LowerAddress, UpperAddress); | |
| } | |
| LVRange *LVBinaryReader::getSectionRanges(LVSectionIndex SectionIndex) { | |
| LVRange *Range = nullptr; | |
| // Check if we already have a mapping for this section index. | |
| LVSectionRanges::iterator IterSection = SectionRanges.find(SectionIndex); | |
| if (IterSection == SectionRanges.end()) { | |
| Range = new LVRange(); | |
| SectionRanges.emplace(SectionIndex, Range); | |
| } else { | |
| Range = IterSection->second; | |
| } | |
| assert(Range && "Range is null."); | |
| return Range; | |
| } | |
| LVBinaryReader::~LVBinaryReader() { | |
| // Delete the lines created by 'createInstructions'. | |
| std::vector<LVLines *> AllInstructionLines = ScopeInstructions.find(); | |
| for (LVLines *Entry : AllInstructionLines) | |
| delete Entry; | |
| // Delete the ranges created by 'getSectionRanges'. | |
| for (LVSectionRanges::reference Entry : SectionRanges) | |
| delete Entry.second; | |
| } | |
| Error LVBinaryReader::createInstructions(LVScope *Scope, | |
| LVSectionIndex SectionIndex, | |
| const LVNameInfo &NameInfo) { | |
| assert(Scope && "Scope is null."); | |
| // Skip stripped functions. | |
| if (Scope->getIsDiscarded()) | |
| return Error::success(); | |
| // Find associated address and size for the given function entry point. | |
| LVAddress Address = NameInfo.first; | |
| uint64_t Size = NameInfo.second; | |
| LLVM_DEBUG({ | |
| dbgs() << "\nPublic Name instructions: '" << Scope->getName() << "' / '" | |
| << Scope->getLinkageName() << "'\n" | |
| << "DIE Offset: " << hexValue(Scope->getOffset()) << " Range: [" | |
| << hexValue(Address) << ":" << hexValue(Address + Size) << "]\n"; | |
| }); | |
| Expected<std::pair<uint64_t, const object::SectionRef>> SectionOrErr = | |
| getSection(Scope, Address, SectionIndex); | |
| if (!SectionOrErr) | |
| return SectionOrErr.takeError(); | |
| const object::SectionRef Section = (*SectionOrErr).second; | |
| uint64_t SectionAddress = (*SectionOrErr).first; | |
| Expected<StringRef> SectionContentsOrErr = Section.getContents(); | |
| if (!SectionContentsOrErr) | |
| return SectionOrErr.takeError(); | |
| // There are cases where the section size is smaller than the [LowPC,HighPC] | |
| // range; it causes us to decode invalid addresses. The recorded size in the | |
| // logical scope is one less than the real size. | |
| LLVM_DEBUG({ | |
| dbgs() << " Size: " << hexValue(Size) | |
| << ", Section Size: " << hexValue(Section.getSize()) << "\n"; | |
| }); | |
| Size = std::min(Size + 1, Section.getSize()); | |
| ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(*SectionContentsOrErr); | |
| uint64_t Offset = Address - SectionAddress; | |
| uint8_t const *Begin = Bytes.data() + Offset; | |
| uint8_t const *End = Bytes.data() + Offset + Size; | |
| LLVM_DEBUG({ | |
| Expected<StringRef> SectionNameOrErr = Section.getName(); | |
| if (!SectionNameOrErr) | |
| consumeError(SectionNameOrErr.takeError()); | |
| else | |
| dbgs() << "Section Index: " << hexValue(Section.getIndex()) << " [" | |
| << hexValue((uint64_t)Section.getAddress()) << ":" | |
| << hexValue((uint64_t)Section.getAddress() + Section.getSize(), 10) | |
| << "] Name: '" << *SectionNameOrErr << "'\n" | |
| << "Begin: " << hexValue((uint64_t)Begin) | |
| << ", End: " << hexValue((uint64_t)End) << "\n"; | |
| }); | |
| // Address for first instruction line. | |
| LVAddress FirstAddress = Address; | |
| LVLines *Instructions = new LVLines(); | |
| while (Begin < End) { | |
| MCInst Instruction; | |
| uint64_t BytesConsumed = 0; | |
| SmallVector<char, 64> InsnStr; | |
| raw_svector_ostream Annotations(InsnStr); | |
| MCDisassembler::DecodeStatus const S = | |
| MD->getInstruction(Instruction, BytesConsumed, | |
| ArrayRef<uint8_t>(Begin, End), Address, outs()); | |
| switch (S) { | |
| case MCDisassembler::Fail: | |
| LLVM_DEBUG({ dbgs() << "Invalid instruction\n"; }); | |
| if (BytesConsumed == 0) | |
| // Skip invalid bytes | |
| BytesConsumed = 1; | |
| break; | |
| case MCDisassembler::SoftFail: | |
| LLVM_DEBUG({ dbgs() << "Potentially undefined instruction:"; }); | |
| LLVM_FALLTHROUGH; | |
| case MCDisassembler::Success: { | |
| std::string Buffer; | |
| raw_string_ostream Stream(Buffer); | |
| StringRef AnnotationsStr = Annotations.str(); | |
| MIP->printInst(&Instruction, Address, AnnotationsStr, *STI, Stream); | |
| LLVM_DEBUG({ | |
| std::string BufferCodes; | |
| raw_string_ostream StreamCodes(BufferCodes); | |
| StreamCodes << format_bytes( | |
| ArrayRef<uint8_t>(Begin, Begin + BytesConsumed), std::nullopt, 16, | |
| 16); | |
| dbgs() << "[" << hexValue((uint64_t)Begin) << "] " | |
| << "Size: " << format_decimal(BytesConsumed, 2) << " (" | |
| << formatv("{0}", | |
| fmt_align(StreamCodes.str(), AlignStyle::Left, 32)) | |
| << ") " << hexValue((uint64_t)Address) << ": " << Stream.str() | |
| << "\n"; | |
| }); | |
| // Here we add logical lines to the Instructions. Later on, | |
| // the 'processLines()' function will move each created logical line | |
| // to its enclosing logical scope, using the debug ranges information | |
| // and they will be released when its scope parent is deleted. | |
| LVLineAssembler *Line = new LVLineAssembler(); | |
| Line->setAddress(Address); | |
| Line->setName(StringRef(Stream.str()).trim()); | |
| Instructions->push_back(Line); | |
| break; | |
| } | |
| } | |
| Address += BytesConsumed; | |
| Begin += BytesConsumed; | |
| } | |
| LLVM_DEBUG({ | |
| size_t Index = 0; | |
| dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3) | |
| << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n" | |
| << "Address: " << hexValue(FirstAddress) | |
| << format(" - Collected instructions lines: %d\n", | |
| Instructions->size()); | |
| for (const LVLine *Line : *Instructions) | |
| dbgs() << format_decimal(++Index, 5) << ": " | |
| << hexValue(Line->getOffset()) << ", (" << Line->getName() | |
| << ")\n"; | |
| }); | |
| // The scope in the assembler names is linked to its own instructions. | |
| ScopeInstructions.add(SectionIndex, Scope, Instructions); | |
| AssemblerMappings.add(SectionIndex, FirstAddress, Scope); | |
| return Error::success(); | |
| } | |
| Error LVBinaryReader::createInstructions(LVScope *Function, | |
| LVSectionIndex SectionIndex) { | |
| if (!options().getPrintInstructions()) | |
| return Error::success(); | |
| LVNameInfo Name = CompileUnit->findPublicName(Function); | |
| if (Name.first != LVAddress(UINT64_MAX)) | |
| return createInstructions(Function, SectionIndex, Name); | |
| return Error::success(); | |
| } | |
| Error LVBinaryReader::createInstructions() { | |
| if (!options().getPrintInstructions()) | |
| return Error::success(); | |
| LLVM_DEBUG({ | |
| size_t Index = 1; | |
| dbgs() << "\nPublic Names (Scope):\n"; | |
| for (LVPublicNames::const_reference Name : CompileUnit->getPublicNames()) { | |
| LVScope *Scope = Name.first; | |
| const LVNameInfo &NameInfo = Name.second; | |
| LVAddress Address = NameInfo.first; | |
| uint64_t Size = NameInfo.second; | |
| dbgs() << format_decimal(Index++, 5) << ": " | |
| << "DIE Offset: " << hexValue(Scope->getOffset()) << " Range: [" | |
| << hexValue(Address) << ":" << hexValue(Address + Size) << "] " | |
| << "Name: '" << Scope->getName() << "' / '" | |
| << Scope->getLinkageName() << "'\n"; | |
| } | |
| }); | |
| // For each public name in the current compile unit, create the line | |
| // records that represent the executable instructions. | |
| for (LVPublicNames::const_reference Name : CompileUnit->getPublicNames()) { | |
| LVScope *Scope = Name.first; | |
| // The symbol table extracted from the object file always contains a | |
| // non-empty name (linkage name). However, the logical scope does not | |
| // guarantee to have a name for the linkage name (main is one case). | |
| // For those cases, set the linkage name the same as the name. | |
| if (!Scope->getLinkageNameIndex()) | |
| Scope->setLinkageName(Scope->getName()); | |
| LVSectionIndex SectionIndex = getSymbolTableIndex(Scope->getLinkageName()); | |
| if (Error Err = createInstructions(Scope, SectionIndex, Name.second)) | |
| return Err; | |
| } | |
| return Error::success(); | |
| } | |
| // During the traversal of the debug information sections, we created the | |
| // logical lines representing the disassembled instructions from the text | |
| // section and the logical lines representing the line records from the | |
| // debug line section. Using the ranges associated with the logical scopes, | |
| // we will allocate those logical lines to their logical scopes. | |
| void LVBinaryReader::processLines(LVLines *DebugLines, | |
| LVSectionIndex SectionIndex, | |
| LVScope *Function) { | |
| assert(DebugLines && "DebugLines is null."); | |
| // Just return if this compilation unit does not have any line records | |
| // and no instruction lines were created. | |
| if (DebugLines->empty() && !options().getPrintInstructions()) | |
| return; | |
| // Merge the debug lines and instruction lines using their text address; | |
| // the logical line representing the debug line record is followed by the | |
| // line(s) representing the disassembled instructions, whose addresses are | |
| // equal or greater that the line address and less than the address of the | |
| // next debug line record. | |
| LLVM_DEBUG({ | |
| size_t Index = 1; | |
| size_t PerLine = 4; | |
| dbgs() << format("\nProcess debug lines: %d\n", DebugLines->size()); | |
| for (const LVLine *Line : *DebugLines) { | |
| dbgs() << format_decimal(Index, 5) << ": " << hexValue(Line->getOffset()) | |
| << ", (" << Line->getLineNumber() << ")" | |
| << ((Index % PerLine) ? " " : "\n"); | |
| ++Index; | |
| } | |
| dbgs() << ((Index % PerLine) ? "\n" : ""); | |
| }); | |
| bool TraverseLines = true; | |
| LVLines::iterator Iter = DebugLines->begin(); | |
| while (TraverseLines && Iter != DebugLines->end()) { | |
| uint64_t DebugAddress = (*Iter)->getAddress(); | |
| // Get the function with an entry point that matches this line and | |
| // its associated assembler entries. In the case of COMDAT, the input | |
| // 'Function' is not null. Use it to find its address ranges. | |
| LVScope *Scope = Function; | |
| if (!Function) { | |
| Scope = AssemblerMappings.find(SectionIndex, DebugAddress); | |
| if (!Scope) { | |
| ++Iter; | |
| continue; | |
| } | |
| } | |
| // Get the associated instructions for the found 'Scope'. | |
| LVLines InstructionLines; | |
| LVLines *Lines = ScopeInstructions.find(SectionIndex, Scope); | |
| if (Lines) | |
| InstructionLines = std::move(*Lines); | |
| LLVM_DEBUG({ | |
| size_t Index = 0; | |
| dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3) | |
| << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n" | |
| << format("Process instruction lines: %d\n", | |
| InstructionLines.size()); | |
| for (const LVLine *Line : InstructionLines) | |
| dbgs() << format_decimal(++Index, 5) << ": " | |
| << hexValue(Line->getOffset()) << ", (" << Line->getName() | |
| << ")\n"; | |
| }); | |
| // Continue with next debug line if there are not instructions lines. | |
| if (InstructionLines.empty()) { | |
| ++Iter; | |
| continue; | |
| } | |
| for (LVLine *InstructionLine : InstructionLines) { | |
| uint64_t InstructionAddress = InstructionLine->getAddress(); | |
| LLVM_DEBUG({ | |
| dbgs() << "Instruction address: " << hexValue(InstructionAddress) | |
| << "\n"; | |
| }); | |
| if (TraverseLines) { | |
| while (Iter != DebugLines->end()) { | |
| DebugAddress = (*Iter)->getAddress(); | |
| LLVM_DEBUG({ | |
| bool IsDebug = (*Iter)->getIsLineDebug(); | |
| dbgs() << "Line " << (IsDebug ? "dbg:" : "ins:") << " [" | |
| << hexValue(DebugAddress) << "]"; | |
| if (IsDebug) | |
| dbgs() << format(" %d", (*Iter)->getLineNumber()); | |
| dbgs() << "\n"; | |
| }); | |
| // Instruction address before debug line. | |
| if (InstructionAddress < DebugAddress) { | |
| LLVM_DEBUG({ | |
| dbgs() << "Inserted instruction address: " | |
| << hexValue(InstructionAddress) << " before line: " | |
| << format("%d", (*Iter)->getLineNumber()) << " [" | |
| << hexValue(DebugAddress) << "]\n"; | |
| }); | |
| Iter = DebugLines->insert(Iter, InstructionLine); | |
| // The returned iterator points to the inserted instruction. | |
| // Skip it and point to the line acting as reference. | |
| ++Iter; | |
| break; | |
| } | |
| ++Iter; | |
| } | |
| if (Iter == DebugLines->end()) { | |
| // We have reached the end of the source lines and the current | |
| // instruction line address is greater than the last source line. | |
| TraverseLines = false; | |
| DebugLines->push_back(InstructionLine); | |
| } | |
| } else { | |
| DebugLines->push_back(InstructionLine); | |
| } | |
| } | |
| } | |
| LLVM_DEBUG({ | |
| dbgs() << format("Lines after merge: %d\n", DebugLines->size()); | |
| size_t Index = 0; | |
| for (const LVLine *Line : *DebugLines) { | |
| dbgs() << format_decimal(++Index, 5) << ": " | |
| << hexValue(Line->getOffset()) << ", (" | |
| << ((Line->getIsLineDebug()) | |
| ? Line->lineNumberAsStringStripped(/*ShowZero=*/true) | |
| : Line->getName()) | |
| << ")\n"; | |
| } | |
| }); | |
| // If this compilation unit does not have line records, traverse its scopes | |
| // and take any collected instruction lines as the working set in order | |
| // to move them to their associated scope. | |
| if (DebugLines->empty()) { | |
| if (const LVScopes *Scopes = CompileUnit->getScopes()) | |
| for (LVScope *Scope : *Scopes) { | |
| LVLines *Lines = ScopeInstructions.find(Scope); | |
| if (Lines) { | |
| LLVM_DEBUG({ | |
| size_t Index = 0; | |
| dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3) | |
| << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n" | |
| << format("Instruction lines: %d\n", Lines->size()); | |
| for (const LVLine *Line : *Lines) | |
| dbgs() << format_decimal(++Index, 5) << ": " | |
| << hexValue(Line->getOffset()) << ", (" << Line->getName() | |
| << ")\n"; | |
| }); | |
| if (Scope->getIsArtificial()) { | |
| // Add the instruction lines to their artificial scope. | |
| for (LVLine *Line : *Lines) | |
| Scope->addElement(Line); | |
| } else { | |
| DebugLines->append(*Lines); | |
| } | |
| Lines->clear(); | |
| } | |
| } | |
| } | |
| LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); | |
| ScopesWithRanges->startSearch(); | |
| // Process collected lines. | |
| LVScope *Scope; | |
| for (LVLine *Line : *DebugLines) { | |
| // Using the current line address, get its associated lexical scope and | |
| // add the line information to it. | |
| Scope = ScopesWithRanges->getEntry(Line->getAddress()); | |
| if (!Scope) { | |
| // If missing scope, use the compile unit. | |
| Scope = CompileUnit; | |
| LLVM_DEBUG({ | |
| dbgs() << "Adding line to CU: " << hexValue(Line->getOffset()) << ", (" | |
| << ((Line->getIsLineDebug()) | |
| ? Line->lineNumberAsStringStripped(/*ShowZero=*/true) | |
| : Line->getName()) | |
| << ")\n"; | |
| }); | |
| } | |
| // Add line object to scope. | |
| Scope->addElement(Line); | |
| // Report any line zero. | |
| if (options().getWarningLines() && Line->getIsLineDebug() && | |
| !Line->getLineNumber()) | |
| CompileUnit->addLineZero(Line); | |
| // Some compilers generate ranges in the compile unit; other compilers | |
| // only DW_AT_low_pc/DW_AT_high_pc. In order to correctly map global | |
| // variables, we need to generate the map ranges for the compile unit. | |
| // If we use the ranges stored at the scope level, there are cases where | |
| // the address referenced by a symbol location, is not in the enclosing | |
| // scope, but in an outer one. By using the ranges stored in the compile | |
| // unit, we can catch all those addresses. | |
| if (Line->getIsLineDebug()) | |
| CompileUnit->addMapping(Line, SectionIndex); | |
| // Resolve any given pattern. | |
| patterns().resolvePatternMatch(Line); | |
| } | |
| ScopesWithRanges->endSearch(); | |
| } | |
| void LVBinaryReader::processLines(LVLines *DebugLines, | |
| LVSectionIndex SectionIndex) { | |
| assert(DebugLines && "DebugLines is null."); | |
| if (DebugLines->empty() && !ScopeInstructions.findMap(SectionIndex)) | |
| return; | |
| // If the Compile Unit does not contain comdat functions, use the whole | |
| // set of debug lines, as the addresses don't have conflicts. | |
| if (!CompileUnit->getHasComdatScopes()) { | |
| processLines(DebugLines, SectionIndex, nullptr); | |
| return; | |
| } | |
| // Find the indexes for the lines whose address is zero. | |
| std::vector<size_t> AddressZero; | |
| LVLines::iterator It = | |
| std::find_if(std::begin(*DebugLines), std::end(*DebugLines), | |
| [](LVLine *Line) { return !Line->getAddress(); }); | |
| while (It != std::end(*DebugLines)) { | |
| AddressZero.emplace_back(std::distance(std::begin(*DebugLines), It)); | |
| It = std::find_if(std::next(It), std::end(*DebugLines), | |
| [](LVLine *Line) { return !Line->getAddress(); }); | |
| } | |
| // If the set of debug lines does not contain any line with address zero, | |
| // use the whole set. It means we are dealing with an initialization | |
| // section from a fully linked binary. | |
| if (AddressZero.empty()) { | |
| processLines(DebugLines, SectionIndex, nullptr); | |
| return; | |
| } | |
| // The Compile unit contains comdat functions. Traverse the collected | |
| // debug lines and identify logical groups based on their start and | |
| // address. Each group starts with a zero address. | |
| // Begin, End, Address, IsDone. | |
| using LVBucket = std::tuple<size_t, size_t, LVAddress, bool>; | |
| std::vector<LVBucket> Buckets; | |
| LVAddress Address; | |
| size_t Begin = 0; | |
| size_t End = 0; | |
| size_t Index = 0; | |
| for (Index = 0; Index < AddressZero.size() - 1; ++Index) { | |
| Begin = AddressZero[Index]; | |
| End = AddressZero[Index + 1] - 1; | |
| Address = (*DebugLines)[End]->getAddress(); | |
| Buckets.emplace_back(Begin, End, Address, false); | |
| } | |
| // Add the last bucket. | |
| if (Index) { | |
| Begin = AddressZero[Index]; | |
| End = DebugLines->size() - 1; | |
| Address = (*DebugLines)[End]->getAddress(); | |
| Buckets.emplace_back(Begin, End, Address, false); | |
| } | |
| LLVM_DEBUG({ | |
| dbgs() << "\nDebug Lines buckets: " << Buckets.size() << "\n"; | |
| for (LVBucket &Bucket : Buckets) { | |
| dbgs() << "Begin: " << format_decimal(std::get<0>(Bucket), 5) << ", " | |
| << "End: " << format_decimal(std::get<1>(Bucket), 5) << ", " | |
| << "Address: " << hexValue(std::get<2>(Bucket)) << "\n"; | |
| } | |
| }); | |
| // Traverse the sections and buckets looking for matches on the section | |
| // sizes. In the unlikely event of different buckets with the same size | |
| // process them in order and mark them as done. | |
| LVLines Group; | |
| for (LVSections::reference Entry : Sections) { | |
| LVSectionIndex SectionIndex = Entry.first; | |
| const object::SectionRef Section = Entry.second; | |
| uint64_t Size = Section.getSize(); | |
| LLVM_DEBUG({ | |
| dbgs() << "\nSection Index: " << format_decimal(SectionIndex, 3) | |
| << " , Section Size: " << hexValue(Section.getSize()) | |
| << " , Section Address: " << hexValue(Section.getAddress()) | |
| << "\n"; | |
| }); | |
| for (LVBucket &Bucket : Buckets) { | |
| if (std::get<3>(Bucket)) | |
| // Already done for previous section. | |
| continue; | |
| if (Size == std::get<2>(Bucket)) { | |
| // We have a match on the section size. | |
| Group.clear(); | |
| LVLines::iterator IterStart = DebugLines->begin() + std::get<0>(Bucket); | |
| LVLines::iterator IterEnd = | |
| DebugLines->begin() + std::get<1>(Bucket) + 1; | |
| for (LVLines::iterator Iter = IterStart; Iter < IterEnd; ++Iter) | |
| Group.push_back(*Iter); | |
| processLines(&Group, SectionIndex, /*Function=*/nullptr); | |
| std::get<3>(Bucket) = true; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void LVBinaryReader::print(raw_ostream &OS) const { | |
| OS << "LVBinaryReader\n"; | |
| LLVM_DEBUG(dbgs() << "PrintReader\n"); | |
| } |