From 001ecbde1112356f7c820037ef1e3ca75f03be3b Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Tue, 6 Aug 2019 08:18:39 +0000 Subject: [PATCH] SymbolVendorELF: Perform build-id lookup even without a debug link Summary: The debug link and build-id lookups are two independent ways one can search for a separate symbol file. However, our implementation in SymbolVendorELF was tying the two together and refusing to look up the symbol file based on a build id if the file did not contain a debug link. This patch makes it possible to search for the symbol file with just one of the two methods available. To demonstrate, I split the build-id-case test into two, so that we test the search using both methods. Reviewers: jankratochvil, mgorny, clayborg, espindola, alexshap Subscribers: emaste, arichardson, MaskRay, lldb-commits Differential Revision: https://reviews.llvm.org/D65561 llvm-svn: 367994 --- lldb/lit/Modules/ELF/build-id-case.yaml | 2 +- lldb/lit/Modules/ELF/gnu-debuglink.yaml | 32 ++++ .../SymbolVendor/ELF/SymbolVendorELF.cpp | 9 +- lldb/source/Symbol/LocateSymbolFile.cpp | 163 +++++++++--------- 4 files changed, 121 insertions(+), 85 deletions(-) create mode 100644 lldb/lit/Modules/ELF/gnu-debuglink.yaml diff --git a/lldb/lit/Modules/ELF/build-id-case.yaml b/lldb/lit/Modules/ELF/build-id-case.yaml index c95ffbd7ffd47..f9786b3754f84 100644 --- a/lldb/lit/Modules/ELF/build-id-case.yaml +++ b/lldb/lit/Modules/ELF/build-id-case.yaml @@ -1,7 +1,7 @@ # RUN: mkdir -p %t/.build-id/1b # RUN: yaml2obj %s > %t/.build-id/1b/8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9.debug # RUN: cd %t -# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=.build-id/1b/8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9.debug %t/.build-id/1b/8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9.debug %t/stripped.out +# RUN: llvm-objcopy --strip-all %t/.build-id/1b/8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9.debug %t/stripped.out # RUN: lldb-test object-file %t/stripped.out | FileCheck %s # CHECK: Name: .debug_frame diff --git a/lldb/lit/Modules/ELF/gnu-debuglink.yaml b/lldb/lit/Modules/ELF/gnu-debuglink.yaml new file mode 100644 index 0000000000000..b39b3187ae9bc --- /dev/null +++ b/lldb/lit/Modules/ELF/gnu-debuglink.yaml @@ -0,0 +1,32 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped +# RUN: lldb-test object-file %t.stripped | FileCheck %s + +# CHECK: Name: .debug_frame +# CHECK-NEXT: Type: dwarf-frame + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x00000000004003D0 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x00000000004003D0 + AddressAlign: 0x0000000000000010 + Content: DEADBEEFBAADF00D + - Name: .debug_frame + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000008 + Content: DEADBEEFBAADF00D +Symbols: + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x00000000004003D0 + Size: 0x0000000000000008 +... diff --git a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index a850a1044cf02..e61e5763fabb9 100644 --- a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -71,16 +71,17 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, if (!uuid) return nullptr; + // If the main object file already contains debug info, then we are done. + if (obj_file->GetSectionList()->FindSectionByType( + lldb::eSectionTypeDWARFDebugInfo, true)) + return nullptr; + // If the module specified a filespec, use that. FileSpec fspec = module_sp->GetSymbolFileFileSpec(); // Otherwise, try gnu_debuglink, if one exists. if (!fspec) fspec = obj_file->GetDebugLink().getValueOr(FileSpec()); - // If we have no debug symbol files, then nothing to do. - if (!fspec) - return nullptr; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "SymbolVendorELF::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); diff --git a/lldb/source/Symbol/LocateSymbolFile.cpp b/lldb/source/Symbol/LocateSymbolFile.cpp index e42ea2fc83b25..0d0e5300668fc 100644 --- a/lldb/source/Symbol/LocateSymbolFile.cpp +++ b/lldb/source/Symbol/LocateSymbolFile.cpp @@ -261,107 +261,110 @@ Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec, FileSystem::Instance().Exists(symbol_file_spec)) return symbol_file_spec; - const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); - if (symbol_filename && symbol_filename[0]) { - FileSpecList debug_file_search_paths = default_search_paths; + FileSpecList debug_file_search_paths = default_search_paths; + + // Add module directory. + FileSpec module_file_spec = module_spec.GetFileSpec(); + // We keep the unresolved pathname if it fails. + FileSystem::Instance().ResolveSymbolicLink(module_file_spec, + module_file_spec); + + ConstString file_dir = module_file_spec.GetDirectory(); + { + FileSpec file_spec(file_dir.AsCString(".")); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } - // Add module directory. - FileSpec module_file_spec = module_spec.GetFileSpec(); - // We keep the unresolved pathname if it fails. - FileSystem::Instance().ResolveSymbolicLink(module_file_spec, - module_file_spec); + if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { - ConstString file_dir = module_file_spec.GetDirectory(); + // Add current working directory. { - FileSpec file_spec(file_dir.AsCString(".")); + FileSpec file_spec("."); FileSystem::Instance().Resolve(file_spec); debug_file_search_paths.AppendIfUnique(file_spec); } - if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { - - // Add current working directory. - { - FileSpec file_spec("."); - FileSystem::Instance().Resolve(file_spec); - debug_file_search_paths.AppendIfUnique(file_spec); - } - #ifndef _WIN32 #if defined(__NetBSD__) - // Add /usr/libdata/debug directory. - { - FileSpec file_spec("/usr/libdata/debug"); - FileSystem::Instance().Resolve(file_spec); - debug_file_search_paths.AppendIfUnique(file_spec); - } + // Add /usr/libdata/debug directory. + { + FileSpec file_spec("/usr/libdata/debug"); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } #else - // Add /usr/lib/debug directory. - { - FileSpec file_spec("/usr/lib/debug"); - FileSystem::Instance().Resolve(file_spec); - debug_file_search_paths.AppendIfUnique(file_spec); - } + // Add /usr/lib/debug directory. + { + FileSpec file_spec("/usr/lib/debug"); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } #endif #endif // _WIN32 - } + } - std::string uuid_str; - const UUID &module_uuid = module_spec.GetUUID(); - if (module_uuid.IsValid()) { - // Some debug files are stored in the .build-id directory like this: - // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug - uuid_str = module_uuid.GetAsString(""); - std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(), - ::tolower); - uuid_str.insert(2, 1, '/'); - uuid_str = uuid_str + ".debug"; - } + std::string uuid_str; + const UUID &module_uuid = module_spec.GetUUID(); + if (module_uuid.IsValid()) { + // Some debug files are stored in the .build-id directory like this: + // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug + uuid_str = module_uuid.GetAsString(""); + std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(), + ::tolower); + uuid_str.insert(2, 1, '/'); + uuid_str = uuid_str + ".debug"; + } - size_t num_directories = debug_file_search_paths.GetSize(); - for (size_t idx = 0; idx < num_directories; ++idx) { - FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); - FileSystem::Instance().Resolve(dirspec); - if (!FileSystem::Instance().IsDirectory(dirspec)) - continue; + size_t num_directories = debug_file_search_paths.GetSize(); + for (size_t idx = 0; idx < num_directories; ++idx) { + FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); + FileSystem::Instance().Resolve(dirspec); + if (!FileSystem::Instance().IsDirectory(dirspec)) + continue; - std::vector files; - std::string dirname = dirspec.GetPath(); + std::vector files; + std::string dirname = dirspec.GetPath(); - files.push_back(dirname + "/" + symbol_filename); - files.push_back(dirname + "/.debug/" + symbol_filename); + if (!uuid_str.empty()) files.push_back(dirname + "/.build-id/" + uuid_str); + if (symbol_file_spec.GetFilename()) { + files.push_back(dirname + "/" + + symbol_file_spec.GetFilename().GetCString()); + files.push_back(dirname + "/.debug/" + + symbol_file_spec.GetFilename().GetCString()); // Some debug files may stored in the module directory like this: // /usr/lib/debug/usr/lib/library.so.debug if (!file_dir.IsEmpty()) - files.push_back(dirname + file_dir.AsCString() + "/" + symbol_filename); - - const uint32_t num_files = files.size(); - for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { - const std::string &filename = files[idx_file]; - FileSpec file_spec(filename); - FileSystem::Instance().Resolve(file_spec); - - if (llvm::sys::fs::equivalent(file_spec.GetPath(), - module_file_spec.GetPath())) - continue; - - if (FileSystem::Instance().Exists(file_spec)) { - lldb_private::ModuleSpecList specs; - const size_t num_specs = - ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); - assert(num_specs <= 1 && - "Symbol Vendor supports only a single architecture"); - if (num_specs == 1) { - ModuleSpec mspec; - if (specs.GetModuleSpecAtIndex(0, mspec)) { - // Skip the uuids check if module_uuid is invalid. For example, - // this happens for *.dwp files since at the moment llvm-dwp - // doesn't output build ids, nor does binutils dwp. - if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID()) - return file_spec; - } + files.push_back(dirname + file_dir.AsCString() + "/" + + symbol_file_spec.GetFilename().GetCString()); + } + + const uint32_t num_files = files.size(); + for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { + const std::string &filename = files[idx_file]; + FileSpec file_spec(filename); + FileSystem::Instance().Resolve(file_spec); + + if (llvm::sys::fs::equivalent(file_spec.GetPath(), + module_file_spec.GetPath())) + continue; + + if (FileSystem::Instance().Exists(file_spec)) { + lldb_private::ModuleSpecList specs; + const size_t num_specs = + ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); + assert(num_specs <= 1 && + "Symbol Vendor supports only a single architecture"); + if (num_specs == 1) { + ModuleSpec mspec; + if (specs.GetModuleSpecAtIndex(0, mspec)) { + // Skip the uuids check if module_uuid is invalid. For example, + // this happens for *.dwp files since at the moment llvm-dwp + // doesn't output build ids, nor does binutils dwp. + if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID()) + return file_spec; } } }