Skip to content

[llvm-debuginfo-analyzer] Add support for LLVM IR format. - #202120

Merged
CarlosAlbertoEnciso merged 22 commits into
llvm:mainfrom
CarlosAlbertoEnciso:debuginfo-analyzer-ir-reader-reland-2
Jul 1, 2026
Merged

[llvm-debuginfo-analyzer] Add support for LLVM IR format.#202120
CarlosAlbertoEnciso merged 22 commits into
llvm:mainfrom
CarlosAlbertoEnciso:debuginfo-analyzer-ir-reader-reland-2

Conversation

@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member

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.

Add support for the LLVM IR format and be able to generate logical
views. Both textual representation (.ll) and bitcode (.bc) formats
are supported.

This relands #135440,
which was:
reverted in: #199890
relanded in: #200603
reverted in: #201019

It includes the fixes for the buildbots problems.

CarlosAlbertoEnciso and others added 20 commits February 13, 2026 10:50
Add support for the LLVM IR format and be able to generate
logical views.

Both textual representation (.ll) and bitcode (.bc) format
are supported.

Note: This patch requires:

  Add DebugSSAUpdater class to track debug value liveness
  llvm#135349
Add support for the LLVM IR format and be able to generate
logical views.

Both textual representation (.ll) and bitcode (.bc) format
are supported.

Note: This patch requires:

Add DebugSSAUpdater class to track debug value liveness
llvm#135349

Note: Address reviewers comments.
Fixed compilation issues after latest DebugSSAUpdater rebase.
Updated test cases that failed due to an upstream fix related
to the high-pc value being now exclusive.

  llvm#153318
Updated test cases that failed due to the DebugSSAUpdater rebase.
Add a missing space between the offset and 'ptr' for a
better layout.

  [004] 9 {Variable} 'CONSTANT' -> 'const INTEGER'
  [006]     {Location}
  [007]       {Entry} bregx 3 ptr %CONSTANT+0
Fix issue reported by Clang format.
Fix issue with C++98 error:

  extra ';' outside of a function is incompatible with C++98
  [-Werror,-Wc++98-compat-extra-semi]
Changes required after rebase with upstream to include:

  Remove LVScope::Children container.
  llvm#144750
Changes required after rebase with upstream to include:

  [llvm][DebugInfo][NFC] Abstract DICompileUnit::SourceLanguage
  to allow alternate DWARF SourceLanguage encoding (llvm#162255)

  llvm#162255
Rust generates multiple #dbg_declare's.

  %self.dbg.spill = alloca [8 x i8], align 8
  store ptr %self, ptr %self.dbg.spill, align 8
    #dbg_declare(ptr %self.dbg.spill, !892, !DIExpression(), !894)
    #dbg_declare(ptr %self.dbg.spill, !895, !DIExpression(), !905)

Change the assertion for a warning and return, otherwise
the IR Reader will not be able to process Rust IR's.
Add the ability to print basic information about a logical
element. Mainly is used to print information while dealing
with IR.

It uses the current command line arguments to control what
to print. The information is printed in a single line. In
the minimum case it includes name and type.
- Addressed all the reviewers comments.
  * Added test case for multiple compile units.

- Reviewed the inlining functionality issues, found when
  processing IRs produced by the Russ compiler:
  * Incorrect inlined lexical scopes as Clang allocates them
    at the scope of the enclosing function.
  * An assertion produced when in the inlining chain one of
    the original scopes has not been created.

- Fix compilation errors after upstream change:
  Remove DITypeRefArray in favour of DITypeArray
  llvm#177066
As the IR format uses the DWARF symbolic constants,
the setting of the source language must use the DWARF
language definitions.
If the IR parsing fails, print an explanatory error message.
- Addressed the upstream review.
- Renamed the files related to the combined IR test:
    unit.ll, unit-1, unit-2, unit-3
The origin patch was commited at: 6bbbf74

It generated problems with some buildbots:
- Undefined symbols (missing 'Core' library).
- Compile error (missing #include <unordered_map> header).

It was reverted at: 6de9a33

This patch fixes the above issues.
The origin patch was commited at: 6bbbf74

The relanded patch generated problems with some buildbots.
It was reverted at: 9547e0f

- Undefined symbols (missing 'IRReader' and 'TransformUtils'
  libraries).
- Compile error (unused variable) in builds without asserts.
- static assertion failed due to requirement '...':
  Too many types for the available low bits.
- static assertion failed due to requirement '...':
  Variable-width PointerUnion types must be in non-decreasing
  NumLowBitsAvailable order

Use 'std::variant' instead of 'llvm::PointerUnion'.

This patch fixes the above issues.
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-binary-utilities

Author: Carlos Alberto Enciso (CarlosAlbertoEnciso)

Changes

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.

Add support for the LLVM IR format and be able to generate logical
views. Both textual representation (.ll) and bitcode (.bc) formats
are supported.

This relands #135440,
which was:
reverted in: #199890
relanded in: #200603
reverted in: #201019

It includes the fixes for the buildbots problems.


Patch is 240.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/202120.diff

41 Files Affected:

  • (modified) llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst (+79-126)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h (+7)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h (+7)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h (+3)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h (+14-1)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h (+8-2)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h (+1)
  • (added) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h (+303)
  • (modified) llvm/lib/DebugInfo/LogicalView/CMakeLists.txt (+5)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp (+13-4)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp (+5)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp (+29-1)
  • (modified) llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp (+43-14)
  • (added) llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp (+2630)
  • (modified) llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp (+9-2)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test (+121)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test (+78)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test (+151)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test (+60)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test (+131)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test (+144)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test (+113)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test (+121)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test (+48)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test (+168)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-1.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-2.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-3.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit.ll (+34)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll (+49)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll (+92)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll (+98)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll (+44)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll (+87)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll (+83)
  • (modified) llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt (+3)
  • (modified) llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt (+3)
  • (added) llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp (+362)
  • (modified) llvm/unittests/DebugInfo/LogicalView/Inputs/README.md (+12)
  • (added) llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.bc ()
  • (added) llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll (+83)
diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 6fcf8423e8125..221732775e74c 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -13,10 +13,11 @@ SYNOPSIS
 DESCRIPTION
 -----------
 :program:`llvm-debuginfo-analyzer` parses debug and text sections in
-binary object files and prints their contents in a logical view, which
-is a human-readable representation that closely matches the structure
-of the original user source code. Supported object file formats include
-ELF, Mach-O, WebAssembly, PDB and COFF.
+binary object files or LLVM IR textual / bitcode representation and prints
+their contents in a logical view, which is a human readable representation
+that closely matches the structure of the original user source code.
+Supported object file formats include ELF, Mach-O, WebAssembly, PDB,
+COFF and IR (textual representation and bitcode).
 
 The **logical view** abstracts the complexity associated with the
 different low-level representations of the debugging information that
@@ -2131,143 +2132,95 @@ layout and given the number of matches.
   -----------------------------
   Total           71          8
 
-COMPARISON MODE
-^^^^^^^^^^^^^^^
-Given the previous example we found the above debug information issue
-(related to the previous invalid scope location for the **'typedef int
-INTEGER'**) by comparing against another compiler.
-
-Using GCC to generate test-dwarf-gcc.o, we can apply a selection pattern
-with the printing mode to obtain the following logical view output.
-
-.. code-block:: none
-
-  llvm-debuginfo-analyzer --attribute=level
-                          --select-regex --select-nocase --select=INTe
-                          --report=list
-                          --print=symbols,types
-                          test-clang.o test-dwarf-gcc.o
-
-  Logical View:
-  [000]           {File} 'test-clang.o'
-
-  [001]           {CompileUnit} 'test.cpp'
-  [003]     4     {TypeAlias} 'INTEGER' -> 'int'
-  [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
-
-  Logical View:
-  [000]           {File} 'test-dwarf-gcc.o'
-
-  [001]           {CompileUnit} 'test.cpp'
-  [004]     4     {TypeAlias} 'INTEGER' -> 'int'
-  [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
-
-The output shows that both objects contain the same elements. But the
-**'typedef INTEGER'** is located at different scope level. The GCC
-generated object, shows **'4'**, which is the correct value.
+LLVM IR (textual / bitcode representation) SUPPORT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The below example is used to show the IR output generated by
+:program:`llvm-debuginfo-analyzer`. We compiled the example for a
+IR 64-bit target with Clang (-O0 -g --target=x86_64-linux):
 
-There are 2 comparison methods: logical view and logical elements.
+.. code-block:: c++
 
-LOGICAL VIEW
-""""""""""""
-It compares the logical view as a whole unit; for a match, each compared
-logical element must have the same parents and children.
+  1  using INTPTR = const int *;
+  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+  3    if (ParamBool) {
+  4      typedef int INTEGER;
+  5      const INTEGER CONSTANT = 7;
+  6      return CONSTANT;
+  7    }
+  8    return ParamUnsigned;
+  9  }
 
-The output shows in view form the **missing (-), added (+)** elements,
-giving more context by swapping the reference and target object files.
+PRINT BASIC DETAILS
+^^^^^^^^^^^^^^^^^^^
+The following command prints basic details for all the logical elements
+sorted by the debug information internal offset; it includes its lexical
+level and debug info format.
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=view
-                          --print=symbols,types
-                          test-clang.o test-dwarf-gcc.o
-
-  Reference: 'test-clang.o'
-  Target:    'test-dwarf-gcc.o'
-
-  Logical View:
-   [000]           {File} 'test-clang.o'
-
-   [001]             {CompileUnit} 'test.cpp'
-   [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
-   [002]     2         {Function} extern not_inlined 'foo' -> 'int'
-   [003]                 {Block}
-   [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
-  +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
-   [003]     2           {Parameter} 'ParamBool' -> 'bool'
-   [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
-   [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
-  -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
-
-The output shows the merging view path (reference and target) with the
-missing and added elements.
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=scopes,symbols,types,lines,instructions
+                          test-clang.ll
 
-LOGICAL ELEMENTS
-""""""""""""""""
-It compares individual logical elements without considering if their
-parents are the same. For both comparison methods, the equal criteria
-includes the name, source code location, type, lexical scope level.
+or
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=list
-                          --print=symbols,types,summary
-                          test-clang.o test-dwarf-gcc.o
-
-  Reference: 'test-clang.o'
-  Target:    'test-dwarf-gcc.o'
-
-  (1) Missing Types:
-  -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  (1) Added Types:
-  +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  ----------------------------------------
-  Element   Expected    Missing      Added
-  ----------------------------------------
-  Scopes           4          0          0
-  Symbols          0          0          0
-  Types            2          1          1
-  Lines            0          0          0
-  ----------------------------------------
-  Total            6          1          1
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=elements
+                          test-clang.ll
 
-Changing the *Reference* and *Target* order:
+Each row represents an element that is present within the debug
+information. The first column represents the scope level, followed by
+the associated line number (if any), and finally the description of
+the element.
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=list
-                          --print=symbols,types,summary
-                          test-dwarf-gcc.o test-clang.o
-
-  Reference: 'test-dwarf-gcc.o'
-  Target:    'test-clang.o'
-
-  (1) Missing Types:
-  -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  (1) Added Types:
-  +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  ----------------------------------------
-  Element   Expected    Missing      Added
-  ----------------------------------------
-  Scopes           4          0          0
-  Symbols          0          0          0
-  Types            2          1          1
-  Lines            0          0          0
-  ----------------------------------------
-  Total            6          1          1
+  Logical View:
+  [000]           {File} 'test-clang.ll' -> Textual IR
 
-As the *Reference* and *Target* are switched, the *Added Types* from
-the first case now are listed as *Missing Types*.
+  [001]             {CompileUnit} 'test.cpp'
+  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+  [003]                 {Block}
+  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+  [004]     5             {Line}
+  [004]                   {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+  [004]     6             {Line}
+  [004]                   {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+  [004]     6             {Line}
+  [004]                   {Code} 'br label %return, !dbg !33'
+  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+  [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+  [003]     2           {Line}
+  [003]                 {Code} '%retval = alloca i32, align 4'
+  [003]                 {Code} '%ParamPtr.addr = alloca ptr, align 8'
+  [003]                 {Code} '%ParamUnsigned.addr = alloca i32, align 4'
+  [003]                 {Code} '%ParamBool.addr = alloca i8, align 1'
+  [003]                 {Code} '%CONSTANT = alloca i32, align 4'
+  [003]                 {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+  [003]                 {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+  [003]                 {Code} '%storedv = zext i1 %ParamBool to i8'
+  [003]                 {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+  [003]     8           {Line}
+  [003]                 {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+  [003]     8           {Line}
+  [003]                 {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+  [003]     8           {Line}
+  [003]                 {Code} 'br label %return, !dbg !35'
+  [003]     9           {Line}
+  [003]                 {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+  [003]     9           {Line}
+  [003]                 {Code} 'ret i32 %2, !dbg !36'
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]                 {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 
 EXIT STATUS
 -----------
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 34bace886a15f..793a66e40b02b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -374,6 +374,13 @@ class LLVM_ABI LVElement : public LVObject {
   // Report the current element as missing or added during comparison.
   virtual void report(LVComparePass Pass) {}
 
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
+
   static LVElementDispatch &getDispatch() { return Dispatch; }
 };
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
index 090af54cd1b85..6bf7f9d2105f8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -159,6 +159,13 @@ class LLVM_ABI LVLocation : public LVObject {
 
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
 };
 
 class LLVM_ABI LVLocationSymbol final : public LVLocation {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 371bffb2ed163..774318cb3c53e 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -193,6 +193,9 @@ class LLVM_ABI LVReader {
   virtual Error printMatchedElements(bool UseMatchedElements);
   virtual void sortScopes() {}
 
+  void printCollectedElements(LVScope *Root);
+  bool checkIntegrityScopesTree(LVScope *Root);
+
 public:
   LVReader() = delete;
   LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W,
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 058ca2da9a960..89b78042a615f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -119,7 +119,20 @@ template <typename T> class LVProperties {
 #define KIND_3(ENUM, FIELD, F1, F2, F3)                                        \
   BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3)
 
-const int HEX_WIDTH = 12;
+static constexpr int DEC_WIDTH = 8;
+inline FormattedNumber decValue(uint64_t N, unsigned Width = DEC_WIDTH) {
+  return format_decimal(N, Width);
+}
+
+// Output the decimal representation of 'Value'.
+inline std::string decString(uint64_t Value, size_t Width = DEC_WIDTH) {
+  std::string String;
+  raw_string_ostream Stream(String);
+  Stream << decValue(Value, Width);
+  return String;
+}
+
+static constexpr int HEX_WIDTH = 12;
 inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH,
                                 bool Upper = false) {
   return format_hex(N, Width, Upper);
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
index f6dc65f39c7ac..8d65d2e93f5ad 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -17,12 +17,14 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/Object/Archive.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include <string>
+#include <variant>
 #include <vector>
 
 namespace llvm {
@@ -30,7 +32,9 @@ namespace logicalview {
 
 using LVReaders = std::vector<std::unique_ptr<LVReader>>;
 using ArgVector = std::vector<std::string>;
-using PdbOrObj = PointerUnion<object::ObjectFile *, pdb::PDBFile *>;
+using InputHandle =
+    std::variant<StringRef *, MemoryBufferRef *, object::ObjectFile *,
+                 object::IRObjectFile *, pdb::PDBFile *>;
 
 // This class performs the following tasks:
 // - Creates a logical reader for every binary file in the command line,
@@ -61,8 +65,10 @@ class LVReaderHandler {
                      object::Binary &Binary);
   Error handleObject(LVReaders &Readers, StringRef Filename, StringRef Buffer,
                      StringRef ExePath);
+  Error handleObject(LVReaders &Readers, StringRef Filename,
+                     MemoryBufferRef Buffer);
 
-  Error createReader(StringRef Filename, LVReaders &Readers, PdbOrObj &Input,
+  Error createReader(StringRef Filename, LVReaders &Readers, InputHandle &Input,
                      StringRef FileFormatName, StringRef ExePath = {});
 
 public:
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
index cc8dda2f82bee..f4c1245cfb801 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
@@ -25,6 +25,7 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 
 namespace llvm {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
new file mode 100644
index 0000000000000..db2bf8e8ec033
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -0,0 +1,303 @@
+//===-- LVIRReader.h --------------------------------------------*- C++ -*-===//
+//
+// 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 file defines the LVIRReader class, which is used to describe a
+// LLVM IR reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/Transforms/Utils/DebugSSAUpdater.h"
+#include <unordered_map>
+
+namespace llvm {
+class DIFile;
+class DINode;
+class DILocation;
+class DIScope;
+class DISubprogram;
+class DIVariable;
+class BasicBlock;
+class Module;
+
+namespace object {
+class IRObjectFile;
+}
+
+namespace logicalview {
+
+class LVElement;
+class LVLine;
+class LVScopeCompileUnit;
+class LVSymbol;
+class LVType;
+struct LVSourceLanguage;
+
+class LVIRReader final : public LVReader {
+  PointerUnion<MemoryBufferRef *, object::IRObjectFile *> InputFile;
+
+  // Used by the metadata 'dump' functions, so the metadata nodes will be
+  // numbered canonically; otherwise, pointer addresses are substituted.
+  Module *TheModule = nullptr;
+
+  // Symbols with locations for current compile unit.
+  LVSymbols SymbolsWithLocations;
+
+  const DICompileUnit *CUNode = nullptr;
+
+  // The Dwarf version (from the module flags).
+  unsigned DwarfVersion = 0;
+
+  // Location index for global variables.
+  uint64_t PoolAddressIndex = 0;
+
+  // Default lower bound for arrays.
+  int64_t DefaultLowerBound = 0;
+
+  // Whether to emit all linkage names, or just abstract subprograms.
+  bool UseAllLinkageNames = true;
+
+  SSAValueNameMap ValueNameMap;
+  DenseMap<void *, uint64_t> InstrLineAddrMap;
+  std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
+
+  // Record the last assigned file index for each compile unit.
+  // This data structure is to aid mapping DIFiles onto a DWARF-like file table.
+  using LVIndexFiles = std::unordered_map<LVScopeCompileUnit *, size_t>;
+  LVIndexFiles IndexFiles;
+
+  // Store a FileID number for each DIFile seen.
+  using LVCompileUnitFiles = std::unordered_map<const DIFile *, size_t>;
+  LVCompileUnitFiles CompileUnitFiles;
+
+  // Associate the metadata objects to logical elements.
+  using LVMDObjects = std::unordered_map<const MDNode *, LVElement *>;
+  LVMDObjects MDObjects;
+
+  // An anonymous type for index type.
+  LVType *NodeIndexType = nullptr;
+
+  // Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+  // difference is setting the 'DICompileUnit::splitDebugFilename' to the
+  // name of the split filename: "xxx.dwo".
+  bool includeMinimalInlineScopes() const;
+  bool useAllLinkageNames() const { return UseAllLinkageNames; }
+
+  int64_t getDefaultLowerBound() const { return DefaultLowerBound; }
+  void setDefaultLowerBound(LVSourceLanguage *SL);
+
+  // We assume a constant instruction-size increase between instructions.
+  static constexpr unsigned OFFSET_INCREASE = 4;
+  void updateLineOffset() { CurrentOffset += OFFSET_INCREASE; }
+
+  void updateFileIndex(LVScopeCompileUnit *CompileUnit, size_t FileIndex) {
+    auto [Iter, Inserted] = IndexFiles.try_emplace(CompileUnit, FileIndex);
+    if (!Inserted)
+      Iter->second = FileIndex;
+  }
+
+  // Get the current assigned index file for the given compile unit.
+  size_t getFileIndex(LVScopeCompileUnit *CompileUnit) {
+    LVIndexFiles::iterator Iter = IndexFiles.find(CompileUnit);
+    return Iter != IndexFiles.end() ? Iter->second : 0;
+  }
+
+  // For the given 'DIFile', generate a 1-based index to indicate the
+  // source file where the logical element is declared.
+  // The IR reader expects the indexes to be 1-based.
+  // Each compile unit, keeps track of the last assigned index.
+  size_t getOrCreateSourceID(const DIFile *File);
+
+  void addMD(const MDNode *MD, LVElement *Element) {
+    MDObjects.try_emplace(MD, Element);
+  }
+  LVElement *getElementForSeenMD(const MDNode *MD) const {
+    LVMDObjects::const_iterator Iter = MDObjects.find(MD);
+    return Iter != MDObjec...
[truncated]

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-debuginfo

Author: Carlos Alberto Enciso (CarlosAlbertoEnciso)

Changes

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.

Add support for the LLVM IR format and be able to generate logical
views. Both textual representation (.ll) and bitcode (.bc) formats
are supported.

This relands #135440,
which was:
reverted in: #199890
relanded in: #200603
reverted in: #201019

It includes the fixes for the buildbots problems.


Patch is 240.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/202120.diff

41 Files Affected:

  • (modified) llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst (+79-126)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h (+7)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h (+7)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h (+3)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h (+14-1)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h (+8-2)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h (+1)
  • (added) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h (+303)
  • (modified) llvm/lib/DebugInfo/LogicalView/CMakeLists.txt (+5)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp (+13-4)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp (+5)
  • (modified) llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp (+29-1)
  • (modified) llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp (+43-14)
  • (added) llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp (+2630)
  • (modified) llvm/lib/Transforms/Utils/DebugSSAUpdater.cpp (+9-2)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-compare-logical-elements.test (+121)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-print-basic-details.test (+78)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/01-ir-select-logical-elements.test (+151)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/02-ir-logical-lines.test (+60)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/03-ir-incorrect-lexical-scope-typedef.test (+131)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/04-ir-missing-nested-enumerators.test (+144)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/05-ir-incorrect-lexical-scope-variable.test (+113)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/06-ir-full-logical-view.test (+121)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/07-ir-debug-formats.test (+48)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/08-ir-multiple-compile-units.test (+168)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-1.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-2.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit-3.ll (+58)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/compile-unit.ll (+34)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/hello-world-clang.ll (+49)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-43860-clang.ll (+92)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-44884-clang.ll (+98)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/pr-46466-clang.ll (+44)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang-intrinsics.ll (+87)
  • (added) llvm/test/tools/llvm-debuginfo-analyzer/IR/Inputs/test-clang.ll (+83)
  • (modified) llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt (+3)
  • (modified) llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt (+3)
  • (added) llvm/unittests/DebugInfo/LogicalView/IRReaderTest.cpp (+362)
  • (modified) llvm/unittests/DebugInfo/LogicalView/Inputs/README.md (+12)
  • (added) llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.bc ()
  • (added) llvm/unittests/DebugInfo/LogicalView/Inputs/test-clang.ll (+83)
diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 6fcf8423e8125..221732775e74c 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -13,10 +13,11 @@ SYNOPSIS
 DESCRIPTION
 -----------
 :program:`llvm-debuginfo-analyzer` parses debug and text sections in
-binary object files and prints their contents in a logical view, which
-is a human-readable representation that closely matches the structure
-of the original user source code. Supported object file formats include
-ELF, Mach-O, WebAssembly, PDB and COFF.
+binary object files or LLVM IR textual / bitcode representation and prints
+their contents in a logical view, which is a human readable representation
+that closely matches the structure of the original user source code.
+Supported object file formats include ELF, Mach-O, WebAssembly, PDB,
+COFF and IR (textual representation and bitcode).
 
 The **logical view** abstracts the complexity associated with the
 different low-level representations of the debugging information that
@@ -2131,143 +2132,95 @@ layout and given the number of matches.
   -----------------------------
   Total           71          8
 
-COMPARISON MODE
-^^^^^^^^^^^^^^^
-Given the previous example we found the above debug information issue
-(related to the previous invalid scope location for the **'typedef int
-INTEGER'**) by comparing against another compiler.
-
-Using GCC to generate test-dwarf-gcc.o, we can apply a selection pattern
-with the printing mode to obtain the following logical view output.
-
-.. code-block:: none
-
-  llvm-debuginfo-analyzer --attribute=level
-                          --select-regex --select-nocase --select=INTe
-                          --report=list
-                          --print=symbols,types
-                          test-clang.o test-dwarf-gcc.o
-
-  Logical View:
-  [000]           {File} 'test-clang.o'
-
-  [001]           {CompileUnit} 'test.cpp'
-  [003]     4     {TypeAlias} 'INTEGER' -> 'int'
-  [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
-
-  Logical View:
-  [000]           {File} 'test-dwarf-gcc.o'
-
-  [001]           {CompileUnit} 'test.cpp'
-  [004]     4     {TypeAlias} 'INTEGER' -> 'int'
-  [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
-
-The output shows that both objects contain the same elements. But the
-**'typedef INTEGER'** is located at different scope level. The GCC
-generated object, shows **'4'**, which is the correct value.
+LLVM IR (textual / bitcode representation) SUPPORT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The below example is used to show the IR output generated by
+:program:`llvm-debuginfo-analyzer`. We compiled the example for a
+IR 64-bit target with Clang (-O0 -g --target=x86_64-linux):
 
-There are 2 comparison methods: logical view and logical elements.
+.. code-block:: c++
 
-LOGICAL VIEW
-""""""""""""
-It compares the logical view as a whole unit; for a match, each compared
-logical element must have the same parents and children.
+  1  using INTPTR = const int *;
+  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+  3    if (ParamBool) {
+  4      typedef int INTEGER;
+  5      const INTEGER CONSTANT = 7;
+  6      return CONSTANT;
+  7    }
+  8    return ParamUnsigned;
+  9  }
 
-The output shows in view form the **missing (-), added (+)** elements,
-giving more context by swapping the reference and target object files.
+PRINT BASIC DETAILS
+^^^^^^^^^^^^^^^^^^^
+The following command prints basic details for all the logical elements
+sorted by the debug information internal offset; it includes its lexical
+level and debug info format.
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=view
-                          --print=symbols,types
-                          test-clang.o test-dwarf-gcc.o
-
-  Reference: 'test-clang.o'
-  Target:    'test-dwarf-gcc.o'
-
-  Logical View:
-   [000]           {File} 'test-clang.o'
-
-   [001]             {CompileUnit} 'test.cpp'
-   [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
-   [002]     2         {Function} extern not_inlined 'foo' -> 'int'
-   [003]                 {Block}
-   [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
-  +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
-   [003]     2           {Parameter} 'ParamBool' -> 'bool'
-   [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
-   [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
-  -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
-
-The output shows the merging view path (reference and target) with the
-missing and added elements.
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=scopes,symbols,types,lines,instructions
+                          test-clang.ll
 
-LOGICAL ELEMENTS
-""""""""""""""""
-It compares individual logical elements without considering if their
-parents are the same. For both comparison methods, the equal criteria
-includes the name, source code location, type, lexical scope level.
+or
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=list
-                          --print=symbols,types,summary
-                          test-clang.o test-dwarf-gcc.o
-
-  Reference: 'test-clang.o'
-  Target:    'test-dwarf-gcc.o'
-
-  (1) Missing Types:
-  -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  (1) Added Types:
-  +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  ----------------------------------------
-  Element   Expected    Missing      Added
-  ----------------------------------------
-  Scopes           4          0          0
-  Symbols          0          0          0
-  Types            2          1          1
-  Lines            0          0          0
-  ----------------------------------------
-  Total            6          1          1
+  llvm-debuginfo-analyzer --attribute=level,format
+                          --output-sort=offset
+                          --print=elements
+                          test-clang.ll
 
-Changing the *Reference* and *Target* order:
+Each row represents an element that is present within the debug
+information. The first column represents the scope level, followed by
+the associated line number (if any), and finally the description of
+the element.
 
 .. code-block:: none
 
-  llvm-debuginfo-analyzer --attribute=level
-                          --compare=types
-                          --report=list
-                          --print=symbols,types,summary
-                          test-dwarf-gcc.o test-clang.o
-
-  Reference: 'test-dwarf-gcc.o'
-  Target:    'test-clang.o'
-
-  (1) Missing Types:
-  -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  (1) Added Types:
-  +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
-
-  ----------------------------------------
-  Element   Expected    Missing      Added
-  ----------------------------------------
-  Scopes           4          0          0
-  Symbols          0          0          0
-  Types            2          1          1
-  Lines            0          0          0
-  ----------------------------------------
-  Total            6          1          1
+  Logical View:
+  [000]           {File} 'test-clang.ll' -> Textual IR
 
-As the *Reference* and *Target* are switched, the *Added Types* from
-the first case now are listed as *Missing Types*.
+  [001]             {CompileUnit} 'test.cpp'
+  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+  [003]                 {Block}
+  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+  [004]     5             {Line}
+  [004]                   {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32'
+  [004]     6             {Line}
+  [004]                   {Code} 'store i32 7, ptr %retval, align 4, !dbg !33'
+  [004]     6             {Line}
+  [004]                   {Code} 'br label %return, !dbg !33'
+  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+  [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+  [003]     2           {Line}
+  [003]                 {Code} '%retval = alloca i32, align 4'
+  [003]                 {Code} '%ParamPtr.addr = alloca ptr, align 8'
+  [003]                 {Code} '%ParamUnsigned.addr = alloca i32, align 4'
+  [003]                 {Code} '%ParamBool.addr = alloca i8, align 1'
+  [003]                 {Code} '%CONSTANT = alloca i32, align 4'
+  [003]                 {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8'
+  [003]                 {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4'
+  [003]                 {Code} '%storedv = zext i1 %ParamBool to i8'
+  [003]                 {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1'
+  [003]     8           {Line}
+  [003]                 {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34'
+  [003]     8           {Line}
+  [003]                 {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35'
+  [003]     8           {Line}
+  [003]                 {Code} 'br label %return, !dbg !35'
+  [003]     9           {Line}
+  [003]                 {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36'
+  [003]     9           {Line}
+  [003]                 {Code} 'ret i32 %2, !dbg !36'
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]     3           {Line}
+  [003]                 {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26'
+  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 
 EXIT STATUS
 -----------
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index 34bace886a15f..793a66e40b02b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -374,6 +374,13 @@ class LLVM_ABI LVElement : public LVObject {
   // Report the current element as missing or added during comparison.
   virtual void report(LVComparePass Pass) {}
 
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
+
   static LVElementDispatch &getDispatch() { return Dispatch; }
 };
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
index 090af54cd1b85..6bf7f9d2105f8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -159,6 +159,13 @@ class LLVM_ABI LVLocation : public LVObject {
 
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+  // Print the basic and extra information. Used mainly to debug IR.
+  void printCommon(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dumpCommon() const { printCommon(dbgs(), /*Full=*/true); }
+#endif
 };
 
 class LLVM_ABI LVLocationSymbol final : public LVLocation {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 371bffb2ed163..774318cb3c53e 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -193,6 +193,9 @@ class LLVM_ABI LVReader {
   virtual Error printMatchedElements(bool UseMatchedElements);
   virtual void sortScopes() {}
 
+  void printCollectedElements(LVScope *Root);
+  bool checkIntegrityScopesTree(LVScope *Root);
+
 public:
   LVReader() = delete;
   LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W,
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 058ca2da9a960..89b78042a615f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -119,7 +119,20 @@ template <typename T> class LVProperties {
 #define KIND_3(ENUM, FIELD, F1, F2, F3)                                        \
   BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3)
 
-const int HEX_WIDTH = 12;
+static constexpr int DEC_WIDTH = 8;
+inline FormattedNumber decValue(uint64_t N, unsigned Width = DEC_WIDTH) {
+  return format_decimal(N, Width);
+}
+
+// Output the decimal representation of 'Value'.
+inline std::string decString(uint64_t Value, size_t Width = DEC_WIDTH) {
+  std::string String;
+  raw_string_ostream Stream(String);
+  Stream << decValue(Value, Width);
+  return String;
+}
+
+static constexpr int HEX_WIDTH = 12;
 inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH,
                                 bool Upper = false) {
   return format_hex(N, Width, Upper);
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
index f6dc65f39c7ac..8d65d2e93f5ad 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -17,12 +17,14 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/Object/Archive.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include <string>
+#include <variant>
 #include <vector>
 
 namespace llvm {
@@ -30,7 +32,9 @@ namespace logicalview {
 
 using LVReaders = std::vector<std::unique_ptr<LVReader>>;
 using ArgVector = std::vector<std::string>;
-using PdbOrObj = PointerUnion<object::ObjectFile *, pdb::PDBFile *>;
+using InputHandle =
+    std::variant<StringRef *, MemoryBufferRef *, object::ObjectFile *,
+                 object::IRObjectFile *, pdb::PDBFile *>;
 
 // This class performs the following tasks:
 // - Creates a logical reader for every binary file in the command line,
@@ -61,8 +65,10 @@ class LVReaderHandler {
                      object::Binary &Binary);
   Error handleObject(LVReaders &Readers, StringRef Filename, StringRef Buffer,
                      StringRef ExePath);
+  Error handleObject(LVReaders &Readers, StringRef Filename,
+                     MemoryBufferRef Buffer);
 
-  Error createReader(StringRef Filename, LVReaders &Readers, PdbOrObj &Input,
+  Error createReader(StringRef Filename, LVReaders &Readers, InputHandle &Input,
                      StringRef FileFormatName, StringRef ExePath = {});
 
 public:
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
index cc8dda2f82bee..f4c1245cfb801 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
@@ -25,6 +25,7 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Object/COFF.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 
 namespace llvm {
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
new file mode 100644
index 0000000000000..db2bf8e8ec033
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h
@@ -0,0 +1,303 @@
+//===-- LVIRReader.h --------------------------------------------*- C++ -*-===//
+//
+// 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 file defines the LVIRReader class, which is used to describe a
+// LLVM IR reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVIRREADER_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/Transforms/Utils/DebugSSAUpdater.h"
+#include <unordered_map>
+
+namespace llvm {
+class DIFile;
+class DINode;
+class DILocation;
+class DIScope;
+class DISubprogram;
+class DIVariable;
+class BasicBlock;
+class Module;
+
+namespace object {
+class IRObjectFile;
+}
+
+namespace logicalview {
+
+class LVElement;
+class LVLine;
+class LVScopeCompileUnit;
+class LVSymbol;
+class LVType;
+struct LVSourceLanguage;
+
+class LVIRReader final : public LVReader {
+  PointerUnion<MemoryBufferRef *, object::IRObjectFile *> InputFile;
+
+  // Used by the metadata 'dump' functions, so the metadata nodes will be
+  // numbered canonically; otherwise, pointer addresses are substituted.
+  Module *TheModule = nullptr;
+
+  // Symbols with locations for current compile unit.
+  LVSymbols SymbolsWithLocations;
+
+  const DICompileUnit *CUNode = nullptr;
+
+  // The Dwarf version (from the module flags).
+  unsigned DwarfVersion = 0;
+
+  // Location index for global variables.
+  uint64_t PoolAddressIndex = 0;
+
+  // Default lower bound for arrays.
+  int64_t DefaultLowerBound = 0;
+
+  // Whether to emit all linkage names, or just abstract subprograms.
+  bool UseAllLinkageNames = true;
+
+  SSAValueNameMap ValueNameMap;
+  DenseMap<void *, uint64_t> InstrLineAddrMap;
+  std::unique_ptr<DbgValueRangeTable> DbgValueRanges;
+
+  // Record the last assigned file index for each compile unit.
+  // This data structure is to aid mapping DIFiles onto a DWARF-like file table.
+  using LVIndexFiles = std::unordered_map<LVScopeCompileUnit *, size_t>;
+  LVIndexFiles IndexFiles;
+
+  // Store a FileID number for each DIFile seen.
+  using LVCompileUnitFiles = std::unordered_map<const DIFile *, size_t>;
+  LVCompileUnitFiles CompileUnitFiles;
+
+  // Associate the metadata objects to logical elements.
+  using LVMDObjects = std::unordered_map<const MDNode *, LVElement *>;
+  LVMDObjects MDObjects;
+
+  // An anonymous type for index type.
+  LVType *NodeIndexType = nullptr;
+
+  // Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+  // difference is setting the 'DICompileUnit::splitDebugFilename' to the
+  // name of the split filename: "xxx.dwo".
+  bool includeMinimalInlineScopes() const;
+  bool useAllLinkageNames() const { return UseAllLinkageNames; }
+
+  int64_t getDefaultLowerBound() const { return DefaultLowerBound; }
+  void setDefaultLowerBound(LVSourceLanguage *SL);
+
+  // We assume a constant instruction-size increase between instructions.
+  static constexpr unsigned OFFSET_INCREASE = 4;
+  void updateLineOffset() { CurrentOffset += OFFSET_INCREASE; }
+
+  void updateFileIndex(LVScopeCompileUnit *CompileUnit, size_t FileIndex) {
+    auto [Iter, Inserted] = IndexFiles.try_emplace(CompileUnit, FileIndex);
+    if (!Inserted)
+      Iter->second = FileIndex;
+  }
+
+  // Get the current assigned index file for the given compile unit.
+  size_t getFileIndex(LVScopeCompileUnit *CompileUnit) {
+    LVIndexFiles::iterator Iter = IndexFiles.find(CompileUnit);
+    return Iter != IndexFiles.end() ? Iter->second : 0;
+  }
+
+  // For the given 'DIFile', generate a 1-based index to indicate the
+  // source file where the logical element is declared.
+  // The IR reader expects the indexes to be 1-based.
+  // Each compile unit, keeps track of the last assigned index.
+  size_t getOrCreateSourceID(const DIFile *File);
+
+  void addMD(const MDNode *MD, LVElement *Element) {
+    MDObjects.try_emplace(MD, Element);
+  }
+  LVElement *getElementForSeenMD(const MDNode *MD) const {
+    LVMDObjects::const_iterator Iter = MDObjects.find(MD);
+    return Iter != MDObjec...
[truncated]

@jalopezg-git jalopezg-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @CarlosAlbertoEnciso 👍! I have attached a couple of minor comments / suggestions.

Also, there seems to be an spurious build issue on the Windows platform.

Comment thread llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp Outdated
Comment thread llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h Outdated
Comment thread llvm/include/llvm/DebugInfo/LogicalView/Readers/LVIRReader.h Outdated
This patch addresses the following suggestions:

- Restore original order in PointerUnion (LVIRReader.h).
- Use 'std::get_if().
- Remove not required header file (llvm/ADT/PointerUnion.h).
@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member Author

@jalopezg-git Updated the patch to address your suggestions.
Thanks very much for all your reviews.

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the LLVM ABI annotation checker.

@jalopezg-git jalopezg-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @CarlosAlbertoEnciso 👍! I have added a couple of very minor suggestions. I am happy to approve again, but first I'd like to understand why are we getting this message from 'LLVM ABI annotation checker'. Could you please take a quick look?

Comment thread llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp Outdated
Comment thread llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp Outdated
Comment thread llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp Outdated
@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member Author

I'd like to understand why are we getting this message from 'LLVM ABI annotation checker'. Could you please take a quick look?

I am trying to reproduce the issue locally and see if the suggested change solves the warning.

This patch addresses:

Failure by Check LLVM_ABI annotations with ids:
- Add the missing 'LLVM_ABI' in LVIRReader class.

Suggestions:
- Extend the use of 'std::get_if().
- Use constexpr instead of const.
@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member Author

I'd like to understand why are we getting this message from 'LLVM ABI annotation checker'. Could you please take a quick look?

I am trying to reproduce the issue locally and see if the suggested change solves the warning.

The suggested change (add LLVM_ABI to the class) fixes the issue reported by the check LLVM ABI annotations.

@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member Author

@jalopezg-git Thanks very much for all your great feedback and help with the patches. Very much appreciated.

@jalopezg-git
jalopezg-git self-requested a review June 29, 2026 11:02
@jalopezg-git

Copy link
Copy Markdown
Contributor

I'd like to understand why are we getting this message from 'LLVM ABI annotation checker'. Could you please take a quick look?

I am trying to reproduce the issue locally and see if the suggested change solves the warning.

The suggested change (add LLVM_ABI to the class) fixes the issue reported by the check LLVM ABI annotations.

Thank you, @CarlosAlbertoEnciso! The change looks good -- I have also checked that it is consisted w/ the suggested use here. I think this can now be merged 🙂!

@jalopezg-git jalopezg-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM -- Thank you, @CarlosAlbertoEnciso!

@CarlosAlbertoEnciso
CarlosAlbertoEnciso merged commit e7290b1 into llvm:main Jul 1, 2026
12 checks passed
@llvm-ci

llvm-ci commented Jul 1, 2026

Copy link
Copy Markdown

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/24047

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure)
******************** TEST 'libomp :: tasking/issue-94260-2.c' FAILED ********************
Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp   -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic && /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--

********************


@CarlosAlbertoEnciso
CarlosAlbertoEnciso deleted the debuginfo-analyzer-ir-reader-reland-2 branch July 1, 2026 07:43
maarcosrmz pushed a commit to maarcosrmz/llvm-project that referenced this pull request Jul 1, 2026
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.

Add support for the LLVM IR format and be able to generate logical
views. Both textual representation (.ll) and bitcode (.bc) formats
are supported.

This relands llvm#135440,
which was:
reverted in: llvm#199890
relanded in: llvm#200603
reverted in: llvm#201019

It includes the fixes for the buildbots problems.
@CarlosAlbertoEnciso

Copy link
Copy Markdown
Member Author

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/24047

The restarted build now passes:
https://lab.llvm.org/buildbot/#/builders/88/builds/24058

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants