Skip to content

Add support for verifying .debug_names in split DWARF for CUs and TUs. #101775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 14, 2024

Conversation

clayborg
Copy link
Collaborator

@clayborg clayborg commented Aug 2, 2024

This patch fixes .debug_names verification for split DWARF with no type units. It will print out an error for any name entries where we can't locate the .dwo file. It finds the non skeleton unit and correctly figures out the DIE offset in the .dwo file. If the non skeleton unit is found and yet the skeleton unit has a DWO ID, an error will be emitted showing we couldn't access the non-skeleton compile unit.

This patch fixes .debug_names verification for split DWARF with no type units. It will print out an error for any name entries where we can't locate the .dwo file. It finds the non skeleton unit and correctly figures out the DIE offset in the .dwo file. If the non skeleton unit is found and yet the skeleton unit has a DWO ID, an error will be emitted showing we couldn't access the non-skeleton compile unit.
@clayborg clayborg self-assigned this Aug 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 2, 2024

@llvm/pr-subscribers-debuginfo

Author: Greg Clayton (clayborg)

Changes

This patch fixes .debug_names verification for split DWARF with no type units. It will print out an error for any name entries where we can't locate the .dwo file. It finds the non skeleton unit and correctly figures out the DIE offset in the .dwo file. If the non skeleton unit is found and yet the skeleton unit has a DWO ID, an error will be emitted showing we couldn't access the non-skeleton compile unit.


Full diff: https://github.com/llvm/llvm-project/pull/101775.diff

3 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h (+3)
  • (modified) llvm/lib/DebugInfo/DWARF/DWARFContext.cpp (+5-2)
  • (modified) llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp (+44-3)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
index d800850450eb3..455ccaab74d7e 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -264,6 +264,9 @@ class DWARFContext : public DIContext {
   DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash);
   DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO);
 
+  /// Return the DWARF unit that includes an offset (relative to .debug_info).
+  DWARFUnit *getUnitForOffset(uint64_t Offset);
+
   /// Return the compile unit that includes an offset (relative to .debug_info).
   DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset);
 
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index f36399ed00a6e..045f5e219d34a 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -1510,9 +1510,12 @@ DWARFUnitVector &DWARFContext::getDWOUnits(bool Lazy) {
   return State->getDWOUnits(Lazy);
 }
 
+DWARFUnit *DWARFContext::getUnitForOffset(uint64_t Offset) {
+  return State->getNormalUnits().getUnitForOffset(Offset);
+}
+
 DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) {
-  return dyn_cast_or_null<DWARFCompileUnit>(
-      State->getNormalUnits().getUnitForOffset(Offset));
+  return dyn_cast_or_null<DWARFCompileUnit>(getUnitForOffset(Offset));
 }
 
 DWARFCompileUnit *DWARFContext::getCompileUnitForCodeAddress(uint64_t Address) {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 8ff6ebd230025..7c6da712d1276 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -1626,8 +1626,44 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
       UnitOffset = NI.getCUOffset(*CUIndex);
     if (!UnitOffset)
       continue;
-    uint64_t DIEOffset = *UnitOffset + *EntryOr->getDIEUnitOffset();
-    DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
+    // For split DWARF entries we need to make sure we find the non skeleton
+    // DWARF unit that is needed and use that's DWARF unit offset as the
+    // DIE offset to add the DW_IDX_die_offset to.
+    DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset);
+    if (DU == nullptr || DU->getOffset() != *UnitOffset) {
+      // If we didn't find a DWARF Unit from the UnitOffset, or if the offset
+      // of the unit doesn't match exactly, report an error.
+      ErrorCategory.Report(
+          "Name Index entry contains invalid CU or TU offset", [&]() {
+            error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
+                               "invalid CU or TU offset {1:x}.\n",
+                               NI.getUnitOffset(), EntryID, *UnitOffset);
+          });
+      ++NumErrors;
+      continue;
+    }
+    // This function will try to get the non skeleton unit DIE, but if it is
+    // unable to load the .dwo file from the .dwo or .dwp, it will return the
+    // unit DIE of the DWARFUnit in "DU". So we need to check if the DWARFUnit
+    // has a .dwo file, but we couldn't load it.
+    DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
+    if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {
+      ErrorCategory.Report("Unable to get load .dwo file", [&]() {
+        error() << formatv("Name Index @ {0:x}: Entry @ {1:x} unable to load "
+                           ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n",
+                           NI.getUnitOffset(), EntryID,
+                           dwarf::toString(DU->getUnitDIE().find(
+                               {DW_AT_dwo_name, DW_AT_GNU_dwo_name})),
+                           *UnitOffset);
+      });
+      ++NumErrors;
+      continue;
+    }
+    DWARFUnit *NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit();
+    uint64_t DIEOffset =
+        NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset();
+    DWARFDie DIE = NonSkeletonUnit->getDIEForOffset(DIEOffset);
+
     if (!DIE) {
       ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() {
         error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
@@ -1637,7 +1673,12 @@ unsigned DWARFVerifier::verifyNameIndexEntries(
       ++NumErrors;
       continue;
     }
-    if (DIE.getDwarfUnit()->getOffset() != *UnitOffset) {
+    // Only compare the DIE we found's DWARFUnit offset if the DIE lives in
+    // the DWARFUnit from the DW_IDX_comp_unit or DW_IDX_type_unit. If we are
+    // using split DWARF, then the DIE's DWARFUnit doesn't need to match the
+    // skeleton unit.
+    if (DIE.getDwarfUnit() == DU &&
+        DIE.getDwarfUnit()->getOffset() != *UnitOffset) {
       ErrorCategory.Report("Name index contains mismatched CU of DIE", [&]() {
         error() << formatv(
             "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "

@clayborg
Copy link
Collaborator Author

clayborg commented Aug 2, 2024

I don't have tests yet as I am looking for the right way to create them. If anyone has any input one what I should do, please let me know. I was thinking of having tests that do:

  • yaml executable + yaml .dwo file with the compilation using -ffile-compilation-dir=. so that llvm can find the .dwo file without worrying about paths
  • yaml executable + yaml .dwp file with

Since we can't use clang and or lld in llvm tests, I am basically looking for the best way to add test for this. If anyone can provide guidance on what the best way to do this is, I am all ears.

@dwblaikie
Copy link
Collaborator

You can check the existing dwo/dwp test coverage (one easy way to find test coverage, is to break the code - like just cause the dwp or dwo lookup code to consistently fail to find the dwo/dwp file) - these days I think we go with yaml or assembly for most tests.
For DWP files that's a bit trickier, since there's no way to generate DWP assembly files - hmm, do you need DWP testing, given this feature (split DWARF .debug_names) is orthogonal to DWP files, maybe it's sufficient to test it with DWO files? (or are there DWP-specific code paths to be tested?)

To test for just DWO files, you could checkin assembly or yaml files, maybe using the new https://llvm.org/docs/TestingGuide.html#elaborated-tests functionality to make it easier to regenerate as needed.

@labath
Copy link
Collaborator

labath commented Aug 5, 2024

When I've needed to do that, I just created wrote the dwp section in assembly, the format is pretty simple, so you could probably just take an existing asm output from clang and slap a debug_[ct]u_index section at the back. You can use an existing DWP test as a template (e.g. test/DebugInfo/X86/dwp-v5-tu.s)

Generally I'd recommend assembly instead of yaml as test sources, because they're easier to read in a code review (i.e., without running the input through yaml2obj|dwarfdump)

This adds a test and fixes another test to check for DIE offsets being out of range for a compile unit as this was triggered by some of the changes made for the non skeleton compile unit.
@clayborg
Copy link
Collaborator Author

clayborg commented Aug 7, 2024

This is now fully tested. Before this patch errors would be emitted when verifying .debug_names in split DWARF because the DIE offsets wouldn't match up. This patch makes sure that works and only tests .dwo files as .dwp is just another way to access .dwo files. Let me know if there is anything missing. I have more patches needed to allow us to enable .debug_names with split DWARF, but we can't until we can verify the data is good.

// unit DIE of the DWARFUnit in "DU". So we need to check if the DWARFUnit
// has a .dwo file, but we couldn't load it.
DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE();
if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would this be a more clear check?
DWARFUnit *DWOCU =
DwarfUnit->getNonSkeletonUnitDIE(false, AbsolutePath).getDwarfUnit();
if (!DWOCU->isDWOUnit()) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If the .dwo file isn't found, DU->getNonSkeletonUnitDIE() returns the skeleton compile unit, and then NonSkeletonUnitDie would say that it isn't a DWO file. We need to ask the skeleton unit if it has a DWO ID, and if it does and the DIEs are the same, then we know we didn't find the .dwo file (in a .dwo or .dwp). So for a normal DW_TAG_compile_unit the DU->getNonSkeletonUnitDIE() will return the same DIE and DU won't have a DWO ID.

Copy link
Collaborator

Choose a reason for hiding this comment

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

making getNonSkeletonUnitDIE return a null DWARFDIE if this is a skeleton unit but the split full unit can't be found seems reasonable - I doubt the behavior was intentional/explicitly desired, just falls out by accident

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I believe it is intentional and expected behavior because as it if want all DIEs from a skeleton unit or a normal CU or TU, you call this API to try to get the DIEs regardless of if it is a skeleton unit or not.

  DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true,
                                 StringRef DWOAlternativeLocation = {}) {
    parseDWO(DWOAlternativeLocation);
    return DWO ? DWO->getUnitDIE(ExtractUnitDIEOnly)
               : getUnitDIE(ExtractUnitDIEOnly);
  }

Copy link
Contributor

Choose a reason for hiding this comment

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

It is kind of weird when one calls getNonSkeletonUnitDIE, and gets SkeletonUnitDIE.
Poking around seems like only place this logic is used is in LVDWARFReader::createScopes(), and maybe in dwarfdump::collectStatsForObjectFile.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe it is intentional and expected behavior because as it if want all DIEs from a skeleton unit or a normal CU or TU, you call this API to try to get the DIEs regardless of if it is a skeleton unit or not.

The behavior of returning the non-split unit DIE makes sense given the name, but the behavior of returning the skeleton unit DIE if the split unit can't be found seems surprising/unintentional.

Returning the non-split unit DIE allows the "calling this function regardless of if it is a skeleton unit or not" work out, which seems good - but returning the skeleton unit DIE when the split unit isn't found seems like it'd be bad.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree. So you want me to fix this as part of this commit? Or in a separate commit?

Copy link
Contributor

Choose a reason for hiding this comment

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

Given that it's a current behavior, maybe it's best to discuss it in follow up PR, and not let it block this one? :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sure, leave a FIXME at this call site and on the function itself.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added the FIXME

@clayborg
Copy link
Collaborator Author

clayborg commented Aug 9, 2024

Anything else needed for this PR?

@clayborg
Copy link
Collaborator Author

Ok, I added the FIXME. Anything else needed for this patch?

@clayborg
Copy link
Collaborator Author

Does anyone have time to help move this along? I have more patches coming to finish up the verification of .debug_names.

@clayborg clayborg merged commit 13cc94e into llvm:main Aug 14, 2024
8 checks passed
@clayborg clayborg deleted the debug-names-verify-split-dwarf branch August 14, 2024 05:17
@Michael137
Copy link
Member

Michael137 commented Aug 19, 2024

Sorry for the late ping

Looks like the new verification error triggers in some of the tests on the DWARFv5 x86 macOS bots: https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake-matrix/628/execution/node/79/log/

********************
Unresolved Tests (3):
  lldb-api :: lang/cpp/modules-import/TestCXXModulesImport.py
  lldb-api :: lang/objc/modules-auto-import/TestModulesAutoImport.py
  lldb-api :: lang/objc/modules-objc-property/TestModulesObjCProperty.py

Seeing a bunch of these in the log:

error: Name Index @ 0x0: Entry @ 0xc93e unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc945 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc94c unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc953 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc95a unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc961 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc968 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc96f unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc976 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc97d unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc984 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc98b unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc992 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc999 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: Name Index @ 0x0: Entry @ 0xc9a0 unable to load .dwo file "None" for DWARF unit @ 0x43.
error: output verification failed for x86_64
make: *** [a.out.dSYM] Error 1

Trying to repro this locally now.

This is what one of the clang commands looks like:

"/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/bin/clang"  -std=c++11 -gdwarf-5
-isysroot "/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk" -arch x86_64 
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make/../../../../..//include 
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/tools/lldb/include -I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/test/API/lang/cpp/modules-import
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make -include /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make/test_common.h 
-fno-limit-debug-info  
-nostdlib++ -nostdinc++ -cxx-isystem /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/include/c++/v1
-fmodules -gmodules -fmodules-cache-path=/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/lldb-test-build.noindex/module-cache-clang/lldb-api
-gmodules -fcxx-modules -I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/lldb-test-build.noindex/lang/cpp/modules-import/TestCXXModulesImport.test_expr_failing_import_dsym/include
--driver-mode=g++ -MT main.o -MD -MP -MF main.d -c -o main.o /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/test/API/lang/cpp/modules-import/main.cpp

"/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/bin/clang"  main.o -gdwarf-5
-isysroot "/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk" -arch x86_64 
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make/../../../../..//include -I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/tools/lldb/include
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/test/API/lang/cpp/modules-import
-I/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make
-include /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make/test_common.h 
-fno-limit-debug-info     -L/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/lib
-Wl,-rpath,/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/lib -lc++ --driver-mode=g++ -o "a.out"

ld: warning: ignoring duplicate libraries: '-lc++'

codesign --entitlements /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/packages/Python/lldbsuite/test/make/entitlements-macos.plist -s - "a.out"

"/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/lldb-build/./bin/dsymutil"  -o "a.out.dSYM" "a.out"
Verifying .debug_abbrev...
Verifying .debug_info Unit Header Chain...
Verifying .debug_types Unit Header Chain...
Verifying non-dwo Units...
Verifying unit: 1 / 2, "Foo"
Verifying unit: 2 / 2, "/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake-matrix/llvm-project/lldb/test/API/lang/cpp/modules-import/main.cpp"
Verifying dwo Units...
Verifying .debug_line...
Verifying .debug_str_offsets...
Verifying .debug_names...
error: Name Index @ 0x0: Entry @ 0x9a unable to load .dwo file "None" for DWARF unit @ 0x0.
error: output verification failed for x86_64
make: *** [a.out.dSYM] Error 1

Note how we're compiling with -gdwarf-5 and -gmodules in all of the failing tests. So probably -gmodules related

@Michael137
Copy link
Member

Michael137 commented Aug 20, 2024

So looks like the offending DWARF is this:

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000033, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000037)

0x0000000c: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 20.0.0git (https://github.com/Michael137/llvm-project.git fb326019769e448f9effe3c8b10e6df8e7e9ce71)")
              DW_AT_language    (DW_LANG_C_plus_plus_11)
              DW_AT_name        ("Foo")
              DW_AT_LLVM_sysroot        ("/path/to/sdk")
              DW_AT_APPLE_sdk   ("some.sdk")
              DW_AT_str_offsets_base    (0x00000008)
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/Users/michaelbuch/Git/llvm-worktrees/playground/lldb-test-build.noindex/lang/cpp/modules-import/TestCXXModulesImport.test_expr_dsym")
              DW_AT_GNU_dwo_id  (0xb0d9e392fcae5b5c)
...

0x00000037: Compile Unit: length = 0x0000006c, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x000000a7)

0x00000043: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 20.0.0git (https://github.com/Michael137/llvm-project.git fb326019769e448f9effe3c8b10e6df8e7e9ce71)")
              DW_AT_language    (DW_LANG_C_plus_plus_11)
              DW_AT_name        ("/Users/michaelbuch/Git/llvm-worktrees/playground/lldb/test/API/lang/cpp/modules-import/main.cpp")
              DW_AT_LLVM_sysroot        ("/path/to/sdk")
              DW_AT_APPLE_sdk   ("some.sdk")
              DW_AT_str_offsets_base    (0x00000008)
              DW_AT_stmt_list   (0x0000003d)
              DW_AT_comp_dir    ("/Users/michaelbuch/Git/llvm-worktrees/playground/lldb-test-build.noindex/lang/cpp/modules-import/TestCXXModulesImport.test_expr_dsym")
              DW_AT_low_pc      (0x0000000100003f88)
              DW_AT_high_pc     (0x0000000100003fa8)
              DW_AT_addr_base   (0x00000008)

Note that the first CU has a DW_AT_GNU_dwo_id but there's no associated "DWO file" (which in the gmodules case is a CU with a matching DW_AT_GNU_dwo_id and a path to the .pcm in DW_AT_dwo_name).

AFAIU, this happens when we compile with -gmodules, followed by dsymutil (which, mostly (?), undoes -gmodules). But we're left with a DW_AT_GNU_dwo_id in the main CU. So with the new verifier check added in this PR:

if (DU->getDWOId() && DU->getUnitDIE() == NonSkeletonUnitDie) {

, we do have a getDWOId, but DU->DWO is empty, because there is none. Thus the verifier claims to have failed to load the .dwo file.

Any idea on the best way forward here? @adrian-prantl @clayborg

Maybe dsymutil shouldn't be cloning over the DW_AT_GNU_dwo_id? Locally that fixed things for me.

Michael137 added a commit to Michael137/llvm-project that referenced this pull request Aug 20, 2024
This fixes a verifier error uncovered as a result of llvm#101775.

When compiling with `-gmodules`, Clang will create a skeleton CU
that contains a `DW_AT_dwo_id` and a `DW_AT_dwo_name` corresponding
to the path of the `.pcm` that will contain type definitions referenced
in the non-skeleton CU (see the [gmodules LLDB docs](https://lldb.llvm.org/resources/extensions.html) for more details). The non-skeleton CU will also contain a `DW_AT_dwo_id`
that matches that of the skeleton.

`dsymutil` effectively undoes the `-gmodules` work, replacing all the
module type references with definitions. I.e., we no longer create a
skeleton `.dwo` CU.

Prior to this patch `dsymutil` did not strip out the `DW_AT_dwo_id` on
the non-skeleton CU, now (since llvm#101775) causing verification errors such as:
```
Verifying .debug_names...
error: Name Index @ 0x0: Entry @ 0x9a unable to load .dwo file "None"
for DWARF unit @ 0x0.
error: output verification failed for x86_64
make: *** [a.out.dSYM] Error 1
```
Because the verifier sees the DWO ID but can't find a matching `.dwo`
unit.

This patch simply strips the `DW_AT_dwo_id` from the main CU.
@Michael137
Copy link
Member

Proposed fix in: #105186

Michael137 added a commit that referenced this pull request Aug 21, 2024
This fixes a verifier error uncovered as a result of
#101775.

When compiling with `-gmodules`, Clang will create a skeleton CU that
contains a `DW_AT_dwo_id` and a `DW_AT_dwo_name` corresponding to the
path of the `.pcm` that carries the type definitions referenced in the
non-skeleton CU (see the [gmodules LLDB
docs](https://lldb.llvm.org/resources/extensions.html) for more
details). The non-skeleton CU will also contain a `DW_AT_dwo_id` that
matches that of the skeleton.

`dsymutil` effectively undoes the `-gmodules` work, replacing all the
module type references with definitions. I.e., we no longer create a
skeleton `.dwo` CU.

Prior to this patch `dsymutil` did not strip out the `DW_AT_dwo_id` on
the non-skeleton CU. This now (since
#101775) causes verification
errors such as:
```
Verifying .debug_names...
error: Name Index @ 0x0: Entry @ 0x9a unable to load .dwo file "None"
for DWARF unit @ 0x0.
error: output verification failed for x86_64
make: *** [a.out.dSYM] Error 1
```
...because the verifier sees the DWO ID but can't find a matching `.dwo`
unit.

This patch simply strips the `DW_AT_dwo_id` from the main CU.
cjdb pushed a commit to cjdb/llvm-project that referenced this pull request Aug 23, 2024
This fixes a verifier error uncovered as a result of
llvm#101775.

When compiling with `-gmodules`, Clang will create a skeleton CU that
contains a `DW_AT_dwo_id` and a `DW_AT_dwo_name` corresponding to the
path of the `.pcm` that carries the type definitions referenced in the
non-skeleton CU (see the [gmodules LLDB
docs](https://lldb.llvm.org/resources/extensions.html) for more
details). The non-skeleton CU will also contain a `DW_AT_dwo_id` that
matches that of the skeleton.

`dsymutil` effectively undoes the `-gmodules` work, replacing all the
module type references with definitions. I.e., we no longer create a
skeleton `.dwo` CU.

Prior to this patch `dsymutil` did not strip out the `DW_AT_dwo_id` on
the non-skeleton CU. This now (since
llvm#101775) causes verification
errors such as:
```
Verifying .debug_names...
error: Name Index @ 0x0: Entry @ 0x9a unable to load .dwo file "None"
for DWARF unit @ 0x0.
error: output verification failed for x86_64
make: *** [a.out.dSYM] Error 1
```
...because the verifier sees the DWO ID but can't find a matching `.dwo`
unit.

This patch simply strips the `DW_AT_dwo_id` from the main CU.
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.

6 participants