[llvm] [llvm][dwarf][rfc][donotcommit] Enable print of ranges addresses from .debug_info.dwo (PR #65516)

Alexander Yermolovich via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 6 11:52:30 PDT 2023


https://github.com/ayermolo created https://github.com/llvm/llvm-project/pull/65516:

Summary:
For split dwarf some of the sections remain in the main binary. For DWARF4 it's
.debug_ranges, .debug_addr. For DWARF5 it's .debug_addr. When using
llvm-dwarfdump on .dwo/.dwp files this results in not being able to see what ranges
and addresses for DW_AT_low_pc are used in DIEs, and output having "Error: " in it.

I added a new option --main-binary=<binary> that will create a link in
DWARFContext between DWO context and main binary. This allows tool to display
addresses for DW_AT_ranges and DW_AT_low_pc.

Example (DWARF5):

DW_TAG_inlined_subroutine
        DW_AT_abstract_origin (0x00000b21 "flush_RL")
        DW_AT_ranges  (indexed (0x0) rangelist = 0x00000054
          [0x0000000000403fe2, 0x0000000000403ff3)
          [0x0000000000403ff6, 0x0000000000403ffe))

DW_TAG_subprogram
        DW_AT_low_pc  (0x0000000000403940)


>From 6707fd3038b13d6884896dd2b4603e7c55d159ef Mon Sep 17 00:00:00 2001
From: Alexander Yermolovich <ayermolo at meta.com>
Date: Fri, 1 Sep 2023 13:36:43 -0700
Subject: [PATCH] [llvm][dwarf][rfc][donotcommit] Enable print of ranges
 addresses from .debug_info.dwo

Summary:
For split dwarf some of the sections remain in the main binary. For DWARF4 it's
.debug_ranges, .debug_addr. For DWARF5 it's .debug_addr. When using
llvm-dwarfdump on .dwo/.dwp files this results in not being able to see what ranges
and addresses for DW_AT_low_pc are used in DIEs, and output having "Error: " in it.

I added a new option --main-binary=<binary> that will create a link in
DWARFContext between DWO context and main binary. This allows tool to display
addresses for DW_AT_ranges and DW_AT_low_pc.

Example (DWARF5):

DW_TAG_inlined_subroutine
        DW_AT_abstract_origin (0x00000b21 "flush_RL")
        DW_AT_ranges  (indexed (0x0) rangelist = 0x00000054
          [0x0000000000403fe2, 0x0000000000403ff3)
          [0x0000000000403ff6, 0x0000000000403ffe))

DW_TAG_subprogram
        DW_AT_low_pc  (0x0000000000403940)
---
 .../llvm/DebugInfo/DWARF/DWARFContext.h       | 24 ++++++++++
 llvm/lib/DebugInfo/DWARF/DWARFContext.cpp     | 48 +++++++++++++++++--
 llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp        |  7 ++-
 llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp  | 21 ++++++++
 4 files changed, 94 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index 4bd8394e6b4ec82..f05106522c4b554 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -125,6 +125,12 @@ class DWARFContext : public DIContext {
   DWARFUnitVector &getDWOUnits(bool Lazy = false);
 
   std::unique_ptr<const DWARFObject> DObj;
+  /// Can be optionally set by tools that work with .dwo/.dwp files to reference
+  /// main binary debug information. Usefull for accessing .debug_ranges and
+  /// .debug_addr section.
+  std::unique_ptr<const DWARFObject> MainBinaryDObj = nullptr;
+  /// DWARFContext for main binary.
+  std::unique_ptr<DWARFContext> MainBinaryDICtx = nullptr;
 
   // When set parses debug_info.dwo/debug_abbrev.dwo manually and populates CU
   // Index, and TU Index for DWARF5.
@@ -145,6 +151,13 @@ class DWARFContext : public DIContext {
 
   const DWARFObject &getDWARFObj() const { return *DObj; }
 
+  const DWARFObject *getMainBinaryDWARFObj() const {
+    return MainBinaryDObj.get();
+  }
+  const DWARFContext *getDWARFContextMainBinary() const {
+    return MainBinaryDICtx.get();
+  }
+
   static bool classof(const DIContext *DICtx) {
     return DICtx->getKind() == CK_DWARF;
   }
@@ -478,6 +491,17 @@ class DWARFContext : public DIContext {
   /// manually only for DWARF5.
   void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; }
 
+  /// Sets the object corresponding to the main binary to which the .dwo/.dwp
+  /// file belongs.
+  void setMainBinaryObjAndCreateContext(
+      const object::ObjectFile &Obj,
+      ProcessDebugRelocations RelocAction = ProcessDebugRelocations::Process,
+      const LoadedObjectInfo *L = nullptr,
+      std::function<void(Error)> RecoverableErrorHandler =
+          WithColor::defaultErrorHandler,
+      std::function<void(Error)> WarningHandler =
+          WithColor::defaultWarningHandler);
+
 private:
   void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die,
                        std::vector<DILocal> &Result);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index a45ed0e56553d4e..42e414bb9fa6896 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -47,8 +47,8 @@
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Format.h"
-#include "llvm/Support/LEB128.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/LEB128.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
@@ -56,7 +56,9 @@
 #include <cstdint>
 #include <deque>
 #include <map>
+#include <optional>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -1004,21 +1006,47 @@ void DWARFContext::dump(
                  DObj->getAbbrevDWOSection()))
     getDebugAbbrevDWO()->dump(OS);
 
+  std::unordered_map<uint64_t, DWARFUnit *> DwoIDToDUMap;
+  auto SetSections = [&](DWARFUnit &U) -> void {
+    std::optional<uint64_t> DWOID = U.getDWOId();
+    if (U.isDWOUnit() && DWOID) {
+      auto MapIter = DwoIDToDUMap.find(*DWOID);
+      if (MapIter != DwoIDToDUMap.end()) {
+        DWARFDie UnitDie = MapIter->second->getUnitDIE();
+        std::optional<uint64_t> RangeBase = UnitDie.getRangesBaseAttribute();
+        if (U.getVersion() < 5 && RangeBase)
+          U.setRangesSection(&MainBinaryDObj->getRangesSection(), *RangeBase);
+        if (std::optional<uint64_t> AddrBase =
+                MapIter->second->getAddrOffsetSectionBase())
+          U.setAddrOffsetSection(&MainBinaryDObj->getAddrSection(), *AddrBase);
+      }
+    }
+  };
   auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) {
     OS << '\n' << Name << " contents:\n";
     if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo])
-      for (const auto &U : Units)
+      for (const auto &U : Units) {
+        SetSections(*U);
         U->getDIEForOffset(*DumpOffset)
             .dump(OS, 0, DumpOpts.noImplicitRecursion());
+      }
     else
-      for (const auto &U : Units)
+      for (const auto &U : Units) {
+        SetSections(*U);
         U->dump(OS, DumpOpts);
+      }
   };
   if ((DumpType & DIDT_DebugInfo)) {
     if (Explicit || getNumCompileUnits())
       dumpDebugInfo(".debug_info", info_section_units());
-    if (ExplicitDWO || getNumDWOCompileUnits())
+    if (ExplicitDWO || getNumDWOCompileUnits()) {
+      if (MainBinaryDObj) {
+        for (const auto &U : MainBinaryDICtx->compile_units())
+          if (std::optional<uint64_t> DWOID = U->getDWOId())
+            DwoIDToDUMap.insert({*DWOID, U.get()});
+      }
       dumpDebugInfo(".debug_info.dwo", dwo_info_section_units());
+    }
   }
 
   auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) {
@@ -2428,3 +2456,15 @@ uint8_t DWARFContext::getCUAddrSize() {
   auto CUs = compile_units();
   return CUs.empty() ? 0 : (*CUs.begin())->getAddressByteSize();
 }
+
+void DWARFContext::setMainBinaryObjAndCreateContext(
+    const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction,
+    const LoadedObjectInfo *L,
+    std::function<void(Error)> RecoverableErrorHandler,
+    std::function<void(Error)> WarningHandler) {
+  MainBinaryDObj = std::make_unique<DWARFObjInMemory>(
+      Obj, L, RecoverableErrorHandler, WarningHandler, RelocAction);
+  MainBinaryDICtx =
+      DWARFContext::create(Obj, DWARFContext::ProcessDebugRelocations::Process,
+                           nullptr, "", RecoverableErrorHandler);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 387345a4ac2d601..6d6759d892d9396 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -366,8 +366,11 @@ Error DWARFUnit::extractRangeList(uint64_t RangeListOffset,
                                   DWARFDebugRangeList &RangeList) const {
   // Require that compile unit is extracted.
   assert(!DieArray.empty());
-  DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
-                                IsLittleEndian, getAddressByteSize());
+  DWARFDataExtractor RangesData(isDWOUnit() && Context.getMainBinaryDWARFObj()
+                                    ? *Context.getMainBinaryDWARFObj()
+                                    : Context.getDWARFObj(),
+                                *RangeSection, IsLittleEndian,
+                                getAddressByteSize());
   uint64_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
   return RangeList.extract(RangesData, &ActualRangeListOffset);
 }
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 156e10c84dddec9..9e9b258b4758112 100644
--- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -154,6 +154,11 @@ static std::array<std::optional<uint64_t>, (unsigned)DIDT_ID_Count> DumpOffsets;
 static alias DumpDebugFrameAlias("eh-frame", desc("Alias for --debug-frame"),
                                  NotHidden, cat(SectionCategory),
                                  aliasopt(DumpDebugFrame));
+static cl::opt<std::string>
+    MainBinary("main-binary",
+               desc("Specifies the main binary for cases when .dwo/.dwp file "
+                    "is processed."),
+               cl::init(""), cat(DwarfDumpCategory));
 static list<std::string>
     ArchFilters("arch",
                 desc("Dump debug information for the specified CPU "
@@ -714,6 +719,9 @@ static bool handleArchive(StringRef Filename, Archive &Arch,
 static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
                          HandlerFn HandleObj, raw_ostream &OS) {
   Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
+  std::unique_ptr<MemoryBuffer> MainBuffer = nullptr;
+  ErrorOr<std::unique_ptr<MemoryBuffer>> MainBuffOrErr = nullptr;
+  std::unique_ptr<Binary> MainBin = nullptr;
   error(Filename, BinOrErr.takeError());
 
   bool Result = true;
@@ -727,6 +735,19 @@ static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
           *Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
           RecoverableErrorHandler);
       DICtx->setParseCUTUIndexManually(ManuallyGenerateUnitIndex);
+      if (!MainBinary.empty()) {
+        MainBuffOrErr = MemoryBuffer::getFileOrSTDIN(MainBinary);
+        error(MainBinary, MainBuffOrErr.getError());
+        MainBuffer = std::move(MainBuffOrErr.get());
+        Expected<std::unique_ptr<Binary>> MainBinOrErr =
+            object::createBinary(*MainBuffer);
+        error(MainBinary, MainBinOrErr.takeError());
+        MainBin = std::move(MainBinOrErr.get());
+        if (auto *Obj = dyn_cast<ObjectFile>(MainBin.get()))
+          DICtx->setMainBinaryObjAndCreateContext(
+              *Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr,
+              RecoverableErrorHandler);
+      }
       if (!HandleObj(*Obj, *DICtx, Filename, OS))
         Result = false;
     }



More information about the llvm-commits mailing list