blob: b654c624f57c0fee461eb43ba82febbd30a8d730 [file] [log] [blame]
//===-- 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");
}