Skip to content

Commit

Permalink
SymbolVendorELF: Perform build-id lookup even without a debug link
Browse files Browse the repository at this point in the history
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
  • Loading branch information
labath committed Aug 6, 2019
1 parent 1b3718e commit 001ecbd
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 85 deletions.
2 changes: 1 addition & 1 deletion 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
Expand Down
32 changes: 32 additions & 0 deletions 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
...
9 changes: 5 additions & 4 deletions lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
Expand Up @@ -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());
Expand Down
163 changes: 83 additions & 80 deletions lldb/source/Symbol/LocateSymbolFile.cpp
Expand Up @@ -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<std::string> files;
std::string dirname = dirspec.GetPath();
std::vector<std::string> 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;
}
}
}
Expand Down

0 comments on commit 001ecbd

Please sign in to comment.