[Lldb-commits] [lldb] ccb47b4 - Track .dwo/.dwp loading errors and notify user when viewing variables.
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 22 11:35:37 PDT 2022
Author: Greg Clayton
Date: 2022-09-22T11:35:20-07:00
New Revision: ccb47b41e4936d1d44dfbaf5aac028280c216932
URL: https://github.com/llvm/llvm-project/commit/ccb47b41e4936d1d44dfbaf5aac028280c216932
DIFF: https://github.com/llvm/llvm-project/commit/ccb47b41e4936d1d44dfbaf5aac028280c216932.diff
LOG: Track .dwo/.dwp loading errors and notify user when viewing variables.
When debugging using Fission (-gsplit-dwarf), we can sometimes have issues loading .dwo files if they are missing or if the path was relative and we were unable to locate the file. We can also skip loading due to DWO ID mismatch or if a .dwp file doesn't contain a matching .dwo file. Also .dwo files could be updated due to a recompile and if the user debugs an executable that was linked against the old .dwo file, it could fail to load the information.
This patch adds a m_dwo_error to DWARFUnit that can be get/set and will cause "frame variable" to show errors when there are .dwo/.dwp issues informing the user about the error.
Differential Revision: https://reviews.llvm.org/D134252
Added:
Modified:
lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/test/API/commands/frame/var/TestFrameVar.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 8e258ee0d7bdb..46204ba369ebc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -76,6 +76,7 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() {
return;
m_has_parsed_non_skeleton_unit = true;
+ m_dwo_error.Clear();
if (!m_dwo_id)
return; // No DWO file.
@@ -87,13 +88,24 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() {
DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id);
- if (!dwo_cu)
+ if (!dwo_cu) {
+ SetDwoError(
+ Status("unable to load .dwo file from \"%s\" due to ID (0x%16.16" PRIx64
+ ") mismatch for skeleton DIE at 0x%8.8" PRIx32,
+ dwo_symbol_file->GetObjectFile()->GetFileSpec().GetPath().c_str(),
+ *m_dwo_id, m_first_die.GetOffset()));
return; // Can't fetch the compile unit from the dwo file.
+ }
dwo_cu->SetUserData(this);
DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();
- if (!dwo_cu_die.IsValid())
- return; // Can't fetch the compile unit DIE from the dwo file.
+ if (!dwo_cu_die.IsValid()) {
+ // Can't fetch the compile unit DIE from the dwo file.
+ SetDwoError(
+ Status("unable to extract compile unit DIE from .dwo file for skeleton "
+ "DIE at 0x%8.8" PRIx32, m_first_die.GetOffset()));
+ return;
+ }
// Here for DWO CU we want to use the address base set in the skeleton unit
// (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index c28fee9222caa..26e322059743b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -266,6 +266,25 @@ class DWARFUnit : public lldb_private::UserID {
/// True if any DIEs match any tag in \a tags, false otherwise.
bool HasAny(llvm::ArrayRef<dw_tag_t> tags);
+
+ /// Get the fission .dwo file specific error for this compile unit.
+ ///
+ /// The skeleton compile unit only can have a DWO error. Any other type
+ /// of DWARFUnit will not have a valid DWO error.
+ ///
+ /// \returns
+ /// A valid DWO error if there is a problem with anything in the
+ /// locating or parsing inforamtion in the .dwo file
+ const lldb_private::Status &GetDwoError() const { return m_dwo_error; }
+
+ /// Set the fission .dwo file specific error for this compile unit.
+ ///
+ /// This helps tracks issues that arise when trying to locate or parse a
+ /// .dwo file. Things like a missing .dwo file, DWO ID mismatch, and other
+ /// .dwo errors can be stored in each compile unit so the issues can be
+ /// communicated to the user.
+ void SetDwoError(const lldb_private::Status &error) { m_dwo_error = error; }
+
protected:
DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
@@ -346,6 +365,10 @@ class DWARFUnit : public lldb_private::UserID {
bool m_has_parsed_non_skeleton_unit;
/// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5).
llvm::Optional<uint64_t> m_dwo_id;
+ /// If we get an error when trying to load a .dwo file, save that error here.
+ /// Errors include .dwo/.dwp file not found, or the .dwp/.dwp file was found
+ /// but DWO ID doesn't match, etc.
+ lldb_private::Status m_dwo_error;
private:
void ParseProducerInfo();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 237b3fea716a8..68d86f978da03 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1732,24 +1732,34 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(
return nullptr;
DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(&unit);
- // Only compile units can be split into two parts.
- if (!dwarf_cu)
+ // Only compile units can be split into two parts and we should only
+ // look for a DWO file if there is a valid DWO ID.
+ if (!dwarf_cu || !dwarf_cu->GetDWOId().has_value())
return nullptr;
const char *dwo_name = GetDWOName(*dwarf_cu, cu_die);
- if (!dwo_name)
+ if (!dwo_name) {
+ unit.SetDwoError(Status("missing DWO name in skeleton DIE 0x%8.8" PRIx32,
+ cu_die.GetOffset()));
return nullptr;
+ }
if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile())
return dwp_sp;
+ const char *comp_dir = nullptr;
FileSpec dwo_file(dwo_name);
FileSystem::Instance().Resolve(dwo_file);
if (dwo_file.IsRelative()) {
- const char *comp_dir =
- cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_comp_dir, nullptr);
- if (!comp_dir)
+ comp_dir = cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_comp_dir,
+ nullptr);
+ if (!comp_dir) {
+ unit.SetDwoError(
+ Status("unable to locate relative .dwo debug file \"%s\" for "
+ "skeleton DIE 0x%8.8" PRIx32 " without valid DW_AT_comp_dir "
+ "attribute", dwo_name, cu_die.GetOffset()));
return nullptr;
+ }
dwo_file.SetFile(comp_dir, FileSpec::Style::native);
if (dwo_file.IsRelative()) {
@@ -1764,6 +1774,11 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(
}
if (!FileSystem::Instance().Exists(dwo_file)) {
+ unit.SetDwoError(
+ Status("unable to locate .dwo debug file \"%s\" for skeleton DIE "
+ "0x%8.8" PRIx32, dwo_file.GetPath().c_str(),
+ cu_die.GetOffset()));
+
if (m_dwo_warning_issued.test_and_set(std::memory_order_relaxed) == false) {
GetObjectFile()->GetModule()->ReportWarning(
"unable to locate separate debug file (dwo, dwp). Debugging will be "
@@ -1779,8 +1794,12 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(
GetObjectFile()->GetModule(), &dwo_file, file_offset,
FileSystem::Instance().GetByteSize(dwo_file), dwo_file_data_sp,
dwo_file_data_offset);
- if (dwo_obj_file == nullptr)
+ if (dwo_obj_file == nullptr) {
+ unit.SetDwoError(
+ Status("unable to load object file for .dwo debug file \"%s\" for "
+ "unit DIE 0x%8.8" PRIx32, dwo_name, cu_die.GetOffset()));
return nullptr;
+ }
return std::make_shared<SymbolFileDWARFDwo>(*this, dwo_obj_file,
dwarf_cu->GetID());
@@ -4132,6 +4151,14 @@ Status SymbolFileDWARF::GetFrameVariableError(StackFrame &frame) {
if (!dwarf_cu)
return Status();
+ // Check if we have a skeleton compile unit that had issues trying to load
+ // its .dwo/.dwp file. First pares the Unit DIE to make sure we see any .dwo
+ // related errors.
+ dwarf_cu->ExtractUnitDIEIfNeeded();
+ const Status &dwo_error = dwarf_cu->GetDwoError();
+ if (dwo_error.Fail())
+ return dwo_error;
+
// Don't return an error for assembly files as they typically don't have
// varaible information.
if (dwarf_cu->GetDWARFLanguageType() == DW_LANG_Mips_Assembler)
diff --git a/lldb/test/API/commands/frame/var/TestFrameVar.py b/lldb/test/API/commands/frame/var/TestFrameVar.py
index 4b3674859a283..9e0fb2c2d48b2 100644
--- a/lldb/test/API/commands/frame/var/TestFrameVar.py
+++ b/lldb/test/API/commands/frame/var/TestFrameVar.py
@@ -9,6 +9,7 @@
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
import os
+import shutil
import time
class TestFrameVar(TestBase):
@@ -182,3 +183,59 @@ def test_gline_tables_only(self):
'no variable information is available in debug info for this compile unit'
]
self.check_frame_variable_errors(thread, error_strings)
+
+ @skipUnlessPlatform(["linux", "freebsd"])
+ @add_test_categories(["dwo"])
+ def test_fission_missing_dwo(self):
+ '''
+ Test that if we build a binary with "-gsplit-dwarf" that we can
+ set a file and line breakpoint successfully, and get an error
+ letting us know we were unable to load the .dwo file.
+ '''
+ self.build(dictionary={'CFLAGS_EXTRAS': '-gsplit-dwarf'})
+ exe = self.getBuildArtifact("a.out")
+ main_dwo = self.getBuildArtifact("main.dwo")
+
+ self.assertTrue(os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo))
+ # Delete the main.dwo file that contains the debug info so we force an
+ # error when we run to main and try to get variables.
+ os.unlink(main_dwo)
+
+ # We have to set a named breakpoint because we don't have any debug info
+ # because we deleted the main.o file since the mod times don't match
+ # and debug info won't be loaded
+ (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, 'main')
+ error_strings = [
+ 'unable to locate .dwo debug file "',
+ 'main.dwo" for skeleton DIE 0x'
+ ]
+ self.check_frame_variable_errors(thread, error_strings)
+
+ @skipUnlessPlatform(["linux", "freebsd"])
+ @add_test_categories(["dwo"])
+ def test_fission_invalid_dwo_objectfile(self):
+ '''
+ Test that if we build a binary with "-gsplit-dwarf" that we can
+ set a file and line breakpoint successfully, and get an error
+ letting us know we were unable to load the .dwo file because it
+ existed, but it wasn't a valid object file.
+ '''
+ self.build(dictionary={'CFLAGS_EXTRAS': '-gsplit-dwarf'})
+ exe = self.getBuildArtifact("a.out")
+ main_dwo = self.getBuildArtifact("main.dwo")
+
+ self.assertTrue(os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo))
+ # Overwrite the main.dwo with the main.c source file so that the .dwo
+ # file exists, but it isn't a valid object file as there is an error
+ # for this case.
+ shutil.copyfile(self.getSourcePath('main.c'), main_dwo)
+
+ # We have to set a named breakpoint because we don't have any debug info
+ # because we deleted the main.o file since the mod times don't match
+ # and debug info won't be loaded
+ (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, 'main')
+ error_strings = [
+ 'unable to load object file for .dwo debug file "'
+ 'main.dwo" for unit DIE 0x',
+ ]
+ self.check_frame_variable_errors(thread, error_strings)
More information about the lldb-commits
mailing list