diff options
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp')
| -rw-r--r-- | llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp | 821 |
1 files changed, 821 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp new file mode 100644 index 000000000000..b654c624f57c --- /dev/null +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp @@ -0,0 +1,821 @@ +//===-- 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"); +} |
