Skip to content

Commit

Permalink
[llvm-debuginfo-analyzer] (06/09) - Warning and internal options
Browse files Browse the repository at this point in the history
llvm-debuginfo-analyzer is a command line tool that processes debug
info contained in a binary file and produces a debug information
format agnostic “Logical View”, which is a high-level semantic
representation of the debug info, independent of the low-level
format.

The code has been divided into the following patches:

1) Interval tree
2) Driver and documentation
3) Logical elements
4) Locations and ranges
5) Select elements
6) Warning and internal options
7) Compare elements
8) ELF Reader
9) CodeView Reader

Full details:
https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug-information-visual-analyzer/62570

This patch:

Warning and internal options
- Support for '--warning' options.
- Support for '--internal' options.

Reviewed By: psamolysov, probinson

Differential Revision: https://reviews.llvm.org/D125781
  • Loading branch information
CarlosAlbertoEnciso committed Oct 24, 2022
1 parent f3713a9 commit 2c155d3
Show file tree
Hide file tree
Showing 12 changed files with 930 additions and 6 deletions.
1 change: 0 additions & 1 deletion llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
Expand Up @@ -336,7 +336,6 @@ class LVElement : public LVObject {
virtual void resolveReferences() {}
void resolveParents();

public:
static LVElementDispatch &getDispatch() { return Dispatch; }
};

Expand Down
31 changes: 30 additions & 1 deletion llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
Expand Up @@ -168,6 +168,9 @@ class LVObject {
// copy constructor to create that object; it is used to print a reference
// to another object and in the case of templates, to print its encoded args.
LVObject(const LVObject &Object) {
#ifndef NDEBUG
incID();
#endif
Properties = Object.Properties;
Offset = Object.Offset;
LineNumber = Object.LineNumber;
Expand All @@ -176,6 +179,19 @@ class LVObject {
Parent = Object.Parent;
}

#ifndef NDEBUG
// This is an internal ID used for debugging logical elements. It is used
// for cases where an unique offset within the binary input file is not
// available.
static uint64_t GID;
uint64_t ID = 0;

void incID() {
++GID;
ID = GID;
}
#endif

protected:
// Get a string representation for the given number and discriminator.
std::string lineAsString(uint32_t LineNumber, LVHalf Discriminator,
Expand All @@ -190,7 +206,11 @@ class LVObject {
virtual void printFileIndex(raw_ostream &OS, bool Full = true) const {}

public:
LVObject() = default;
LVObject() {
#ifndef NDEBUG
incID();
#endif
};
LVObject &operator=(const LVObject &) = delete;
virtual ~LVObject() = default;

Expand Down Expand Up @@ -308,6 +328,15 @@ class LVObject {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
virtual void dump() const { print(dbgs()); }
#endif

uint64_t getID() const {
return
#ifndef NDEBUG
ID;
#else
0;
#endif
}
};

} // end namespace logicalview
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
Expand Up @@ -161,6 +161,7 @@ class LVReader {
static void setInstance(LVReader *Reader);

void print(raw_ostream &OS) const;
virtual void printRecords(raw_ostream &OS) const {}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void dump() const { print(dbgs()); }
Expand Down
67 changes: 66 additions & 1 deletion llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
Expand Up @@ -17,6 +17,7 @@
#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
#include <list>
#include <map>
#include <set>

Expand Down Expand Up @@ -56,7 +57,12 @@ using LVScopeKindSet = std::set<LVScopeKind>;
using LVScopeDispatch = std::map<LVScopeKind, LVScopeGetFunction>;
using LVScopeRequest = std::vector<LVScopeGetFunction>;

using LVOffsetList = std::list<LVOffset>;
using LVOffsetElementMap = std::map<LVOffset, LVElement *>;
using LVOffsetLinesMap = std::map<LVOffset, LVLines *>;
using LVOffsetLocationsMap = std::map<LVOffset, LVLocations *>;
using LVOffsetSymbolMap = std::map<LVOffset, LVSymbol *>;
using LVTagOffsetsMap = std::map<dwarf::Tag, LVOffsetList *>;

// Class to represent a DWARF Scope.
class LVScope : public LVElement {
Expand Down Expand Up @@ -266,6 +272,7 @@ class LVScope : public LVElement {

void print(raw_ostream &OS, bool Full = true) const override;
void printExtra(raw_ostream &OS, bool Full = true) const override;
virtual void printWarnings(raw_ostream &OS, bool Full = true) const {}
virtual void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) {}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Expand Down Expand Up @@ -358,11 +365,39 @@ class LVScopeCompileUnit final : public LVScope {
using LVAddressToLine = std::map<LVAddress, LVLine *>;
LVAddressToLine AddressToLine;

// DWARF Tags (Tag, Element list).
LVTagOffsetsMap DebugTags;

// Offsets associated with objects being flagged as having invalid data
// (ranges, locations, lines zero or coverages).
LVOffsetElementMap WarningOffsets;

// Symbols with invalid locations. (Symbol, Location List).
LVOffsetLocationsMap InvalidLocations;

// Symbols with invalid coverage values.
LVOffsetSymbolMap InvalidCoverages;

// Scopes with invalid ranges (Scope, Range list).
LVOffsetLocationsMap InvalidRanges;

// Scopes with lines zero (Scope, Line list).
LVOffsetLinesMap LinesZero;

// Record scopes contribution in bytes to the debug information.
using LVSizesMap = std::map<const LVScope *, LVOffset>;
LVSizesMap Sizes;
LVOffset CUContributionSize = 0;

// Helper function to add an invalid location/range.
void addInvalidLocationOrRange(LVLocation *Location, LVElement *Element,
LVOffsetLocationsMap *Map) {
LVOffset Offset = Element->getOffset();
addInvalidOffset(Offset, Element);
addItem<LVOffsetLocationsMap, LVLocations, LVOffset, LVLocation *>(
Map, Offset, Location);
}

// Record scope sizes indexed by lexical level.
// Setting an initial size that will cover a very deep nested scopes.
const size_t TotalInitialSize = 8;
Expand All @@ -388,7 +423,12 @@ class LVScopeCompileUnit final : public LVScope {
}
LVScopeCompileUnit(const LVScopeCompileUnit &) = delete;
LVScopeCompileUnit &operator=(const LVScopeCompileUnit &) = delete;
~LVScopeCompileUnit() = default;
~LVScopeCompileUnit() {
deleteList<LVTagOffsetsMap>(DebugTags);
deleteList<LVOffsetLocationsMap>(InvalidLocations);
deleteList<LVOffsetLocationsMap>(InvalidRanges);
deleteList<LVOffsetLinesMap>(LinesZero);
}

LVScope *getCompileUnitParent() const override {
return static_cast<LVScope *>(const_cast<LVScopeCompileUnit *>(this));
Expand Down Expand Up @@ -417,6 +457,30 @@ class LVScopeCompileUnit final : public LVScope {
ProducerIndex = getStringPool().getIndex(ProducerName);
}

// Record DWARF tags.
void addDebugTag(dwarf::Tag Target, LVOffset Offset);
// Record elements with invalid offsets.
void addInvalidOffset(LVOffset Offset, LVElement *Element);
// Record symbols with invalid coverage values.
void addInvalidCoverage(LVSymbol *Symbol);
// Record symbols with invalid locations.
void addInvalidLocation(LVLocation *Location);
// Record scopes with invalid ranges.
void addInvalidRange(LVLocation *Location);
// Record line zero.
void addLineZero(LVLine *Line);

const LVTagOffsetsMap getDebugTags() const { return DebugTags; }
const LVOffsetElementMap getWarningOffsets() const { return WarningOffsets; }
const LVOffsetLocationsMap getInvalidLocations() const {
return InvalidLocations;
}
const LVOffsetSymbolMap getInvalidCoverages() const {
return InvalidCoverages;
}
const LVOffsetLocationsMap getInvalidRanges() const { return InvalidRanges; }
const LVOffsetLinesMap getLinesZero() const { return LinesZero; }

// Process ranges, locations and calculate coverage.
void processRangeLocationCoverage(
LVValidLocation ValidLocation = &LVLocation::validateRanges);
Expand Down Expand Up @@ -456,6 +520,7 @@ class LVScopeCompileUnit final : public LVScope {

void print(raw_ostream &OS, bool Full = true) const override;
void printExtra(raw_ostream &OS, bool Full = true) const override;
void printWarnings(raw_ostream &OS, bool Full = true) const override;
void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) override;
};

Expand Down
21 changes: 21 additions & 0 deletions llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
Expand Up @@ -142,6 +142,27 @@ std::string formatAttributes(const StringRef First, Args... Others) {
return Stream.str();
}

// Add an item to a map with second being a list.
template <typename MapType, typename ListType, typename KeyType,
typename ValueType>
void addItem(MapType *Map, KeyType Key, ValueType Value) {
ListType *List = nullptr;
typename MapType::const_iterator Iter = Map->find(Key);
if (Iter != Map->end())
List = Iter->second;
else {
List = new ListType();
Map->emplace(Key, List);
}
List->push_back(Value);
}

// Delete the map contained list.
template <typename MapType> void deleteList(MapType &Map) {
for (typename MapType::const_reference Entry : Map)
delete Entry.second;
}

// Unified and flattened pathnames.
std::string transformPath(StringRef Path);
std::string flattenedFilePath(StringRef Path);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
Expand Up @@ -59,6 +59,8 @@ LVLineDispatch LVLine::Dispatch = {

// String used as padding for printing elements with no line number.
std::string LVLine::noLineAsString(bool ShowZero) const {
if (options().getInternalNone())
return LVObject::noLineAsString(ShowZero);
return (ShowZero || options().getAttributeZero()) ? (" 0 ")
: (" - ");
}
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
Expand Up @@ -21,6 +21,10 @@ using namespace llvm::logicalview;

#define DEBUG_TYPE "Object"

#ifndef NDEBUG
uint64_t LVObject::GID = 0;
#endif

StringRef llvm::logicalview::typeNone() { return StringRef(); }
StringRef llvm::logicalview::typeVoid() { return "void"; }
StringRef llvm::logicalview::typeInt() { return "int"; }
Expand Down Expand Up @@ -61,6 +65,9 @@ std::string LVObject::lineAsString(uint32_t LineNumber, LVHalf Discriminator,
} else
Stream << noLineAsString(ShowZero);

if (options().getInternalNone())
Stream.str(noLineAsString(ShowZero));

return Stream.str();
}

Expand Down Expand Up @@ -118,6 +125,10 @@ void LVObject::printAttributes(raw_ostream &OS, bool Full, StringRef Name,
}

void LVObject::printAttributes(raw_ostream &OS, bool Full) const {
#ifndef NDEBUG
if (options().getInternalID())
OS << hexSquareString(getID());
#endif
if (options().getAttributeOffset())
OS << hexSquareString(getOffset());
if (options().getAttributeLevel()) {
Expand Down
88 changes: 88 additions & 0 deletions llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
Expand Up @@ -23,6 +23,90 @@ using namespace llvm::logicalview;

#define DEBUG_TYPE "Reader"

// Detect elements that are inserted more than once at different scopes,
// causing a crash on the reader destruction, as the element is already
// deleted from other scope. Helper for CodeView reader.
bool checkIntegrityScopesTree(LVScope *Root) {
using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>;
using LVDuplicate = std::vector<LVDuplicateEntry>;
LVDuplicate Duplicate;

using LVIntegrity = std::map<LVElement *, LVScope *>;
LVIntegrity Integrity;

// Add the given element to the integrity map.
auto AddElement = [&](LVElement *Element, LVScope *Scope) {
LVIntegrity::iterator Iter = Integrity.find(Element);
if (Iter == Integrity.end())
Integrity.emplace(Element, Scope);
else
// We found a duplicate.
Duplicate.emplace_back(Element, Scope, Iter->second);
};

// Recursively add all the elements in the scope.
std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {
auto Traverse = [&](const auto *Set) {
if (Set)
for (const auto &Entry : *Set)
AddElement(Entry, Parent);
};
if (const LVScopes *Scopes = Parent->getScopes()) {
for (LVScope *Scope : *Scopes) {
AddElement(Scope, Parent);
TraverseScope(Scope);
}
}
Traverse(Parent->getSymbols());
Traverse(Parent->getTypes());
Traverse(Parent->getLines());
};

// Start traversing the scopes root and print any duplicates.
TraverseScope(Root);
bool PassIntegrity = true;
if (Duplicate.size()) {
std::stable_sort(begin(Duplicate), end(Duplicate),
[](const auto &l, const auto &r) {
return std::get<0>(l)->getID() < std::get<0>(r)->getID();
});

auto PrintIndex = [](unsigned Index) {
if (Index)
dbgs() << format("%8d: ", Index);
else
dbgs() << format("%8c: ", ' ');
};
auto PrintElement = [&](LVElement *Element, unsigned Index = 0) {
PrintIndex(Index);
std::string ElementName(Element->getName());
dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(),
Element->getID(), ElementName.c_str());
};

std::string RootName(Root->getName());
dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(),
Duplicate.size());
dbgs() << formatv("{0}\n", fmt_repeat('=', 72));

unsigned Index = 0;
for (const LVDuplicateEntry &Entry : Duplicate) {
LVElement *Element;
LVScope *First;
LVScope *Second;
std::tie(Element, First, Second) = Entry;
dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72));
PrintElement(Element, ++Index);
PrintElement(First);
PrintElement(Second);
dbgs() << formatv("{0}\n", fmt_repeat('-', 72));
}
PassIntegrity = false;
}
return PassIntegrity;
}

//===----------------------------------------------------------------------===//
// Class to represent a split context.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -149,6 +233,10 @@ Error LVReader::doLoad() {
if (Error Err = createScopes())
return Err;

if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root))
return llvm::make_error<StringError>("Duplicated elements in Scopes Tree",
inconvertibleErrorCode());

// Calculate symbol coverage and detect invalid debug locations and ranges.
Root->processRangeInformation();

Expand Down

0 comments on commit 2c155d3

Please sign in to comment.