summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp')
-rw-r--r--llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp821
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");
+}