in src/common/linux/dump_symbols.cc [634:866]
bool LoadSymbols(const string& obj_file,
const bool big_endian,
const typename ElfClass::Ehdr* elf_header,
const bool read_gnu_debug_link,
LoadSymbolsInfo<ElfClass>* info,
const DumpOptions& options,
Module* module) {
typedef typename ElfClass::Addr Addr;
typedef typename ElfClass::Phdr Phdr;
typedef typename ElfClass::Shdr Shdr;
Addr loading_addr = GetLoadingAddress<ElfClass>(
GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
elf_header->e_phnum);
module->SetLoadAddress(loading_addr);
info->set_loading_addr(loading_addr, obj_file);
const Shdr* sections =
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
const Shdr* section_names = sections + elf_header->e_shstrndx;
const char* names =
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
const char *names_end = names + section_names->sh_size;
bool found_debug_info_section = false;
bool found_usable_info = false;
if (options.symbol_data != ONLY_CFI) {
#ifndef NO_STABS_SUPPORT
// Look for STABS debugging information, and load it if present.
const Shdr* stab_section =
FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
if (stab_section) {
const Shdr* stabstr_section = stab_section->sh_link + sections;
if (stabstr_section) {
found_debug_info_section = true;
found_usable_info = true;
info->LoadedSection(".stab");
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
big_endian, module)) {
fprintf(stderr, "%s: \".stab\" section found, but failed to load"
" STABS debugging information\n", obj_file.c_str());
}
}
}
#endif // NO_STABS_SUPPORT
// Look for DWARF debugging information, and load it if present.
const Shdr* dwarf_section =
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
// .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains,
// but MIPS_DWARF for regular gnu toolchains, so both need to be checked
if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
dwarf_section =
FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
sections, names, names_end,
elf_header->e_shnum);
}
if (dwarf_section) {
found_debug_info_section = true;
found_usable_info = true;
info->LoadedSection(".debug_info");
if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
options.handle_inter_cu_refs, module)) {
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
"DWARF debugging information\n", obj_file.c_str());
}
}
// See if there are export symbols available.
const Shdr* symtab_section =
FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* strtab_section =
FindElfSectionByName<ElfClass>(".strtab", SHT_STRTAB,
sections, names, names_end,
elf_header->e_shnum);
if (symtab_section && strtab_section) {
info->LoadedSection(".symtab");
const uint8_t* symtab =
GetOffset<ElfClass, uint8_t>(elf_header,
symtab_section->sh_offset);
const uint8_t* strtab =
GetOffset<ElfClass, uint8_t>(elf_header,
strtab_section->sh_offset);
bool result =
ELFSymbolsToModule(symtab,
symtab_section->sh_size,
strtab,
strtab_section->sh_size,
big_endian,
ElfClass::kAddrSize,
module);
found_usable_info = found_usable_info || result;
} else {
// Look in dynsym only if full symbol table was not available.
const Shdr* dynsym_section =
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* dynstr_section =
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
sections, names, names_end,
elf_header->e_shnum);
if (dynsym_section && dynstr_section) {
info->LoadedSection(".dynsym");
const uint8_t* dynsyms =
GetOffset<ElfClass, uint8_t>(elf_header,
dynsym_section->sh_offset);
const uint8_t* dynstrs =
GetOffset<ElfClass, uint8_t>(elf_header,
dynstr_section->sh_offset);
bool result =
ELFSymbolsToModule(dynsyms,
dynsym_section->sh_size,
dynstrs,
dynstr_section->sh_size,
big_endian,
ElfClass::kAddrSize,
module);
found_usable_info = found_usable_info || result;
}
}
}
if (options.symbol_data != NO_CFI) {
// Dwarf Call Frame Information (CFI) is actually independent from
// the other DWARF debugging information, and can be used alone.
const Shdr* dwarf_cfi_section =
FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
// .debug_frame section type is SHT_PROGBITS for mips on pnacl toolchains,
// but MIPS_DWARF for regular gnu toolchains, so both need to be checked
if (elf_header->e_machine == EM_MIPS && !dwarf_cfi_section) {
dwarf_cfi_section =
FindElfSectionByName<ElfClass>(".debug_frame", SHT_MIPS_DWARF,
sections, names, names_end,
elf_header->e_shnum);
}
if (dwarf_cfi_section) {
// Ignore the return value of this function; even without call frame
// information, the other debugging information could be perfectly
// useful.
info->LoadedSection(".debug_frame");
bool result =
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
dwarf_cfi_section, false, 0, 0, big_endian,
module);
found_usable_info = found_usable_info || result;
}
// Linux C++ exception handling information can also provide
// unwinding data.
const Shdr* eh_frame_section =
FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
if (eh_frame_section) {
// Pointers in .eh_frame data may be relative to the base addresses of
// certain sections. Provide those sections if present.
const Shdr* got_section =
FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* text_section =
FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
sections, names, names_end,
elf_header->e_shnum);
info->LoadedSection(".eh_frame");
// As above, ignore the return value of this function.
bool result =
LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
eh_frame_section, true,
got_section, text_section, big_endian, module);
found_usable_info = found_usable_info || result;
}
}
if (!found_debug_info_section) {
fprintf(stderr, "%s: file contains no debugging information"
" (no \".stab\" or \".debug_info\" sections)\n",
obj_file.c_str());
// Failed, but maybe there's a .gnu_debuglink section?
if (read_gnu_debug_link) {
const Shdr* gnu_debuglink_section
= FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS,
sections, names,
names_end, elf_header->e_shnum);
if (gnu_debuglink_section) {
if (!info->debug_dirs().empty()) {
const uint8_t *debuglink_contents =
GetOffset<ElfClass, uint8_t>(elf_header,
gnu_debuglink_section->sh_offset);
string debuglink_file =
ReadDebugLink(debuglink_contents,
gnu_debuglink_section->sh_size,
big_endian,
obj_file,
info->debug_dirs());
info->set_debuglink_file(debuglink_file);
} else {
fprintf(stderr, ".gnu_debuglink section found in '%s', "
"but no debug path specified.\n", obj_file.c_str());
}
} else {
fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
obj_file.c_str());
}
} else {
// Return true if some usable information was found, since the caller
// doesn't want to use .gnu_debuglink.
return found_usable_info;
}
// No debug info was found, let the user try again with .gnu_debuglink
// if present.
return false;
}
return true;
}