diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index bcb39ca7..4a85ab8f 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -387,7 +387,7 @@ template string ReadDebugLink(const char* debuglink, size_t debuglink_size, const string& obj_file, - const string& debug_dir) { + const std::vector& debug_dirs) { size_t debuglink_len = strlen(debuglink) + 5; // '\0' + CRC32. debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round to nearest 4 bytes. @@ -398,13 +398,26 @@ string ReadDebugLink(const char* debuglink, return ""; } - string debuglink_path = debug_dir + "/" + debuglink; - int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); - if (debuglink_fd < 0) { + bool found = false; + int debuglink_fd = -1; + string debuglink_path; + std::vector::const_iterator it; + for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { + const string& debug_dir = *it; + debuglink_path = debug_dir + "/" + debuglink; + debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); + if (debuglink_fd >= 0) { + found = true; + break; + } + } + + if (!found) { fprintf(stderr, "Failed to open debug ELF file '%s' for '%s': %s\n", debuglink_path.c_str(), obj_file.c_str(), strerror(errno)); return ""; } + FDWrapper debuglink_fd_wrapper(debuglink_fd); // TODO(thestig) check the CRC-32 at the end of the .gnu_debuglink // section. @@ -424,8 +437,8 @@ class LoadSymbolsInfo { public: typedef typename ElfClass::Addr Addr; - explicit LoadSymbolsInfo(const string &dbg_dir) : - debug_dir_(dbg_dir), + explicit LoadSymbolsInfo(const std::vector& dbg_dirs) : + debug_dirs_(dbg_dirs), has_loading_addr_(false) {} // Keeps track of which sections have been loaded so sections don't @@ -458,8 +471,8 @@ class LoadSymbolsInfo { } // Setters and getters - const string &debug_dir() const { - return debug_dir_; + const std::vector& debug_dirs() const { + return debug_dirs_; } string debuglink_file() const { @@ -470,7 +483,8 @@ class LoadSymbolsInfo { } private: - const string &debug_dir_; // Directory with the debug ELF file. + const std::vector& debug_dirs_; // Directories in which to + // search for the debug ELF file. string debuglink_file_; // Full path to the debug ELF file. @@ -601,14 +615,14 @@ bool LoadSymbols(const string& obj_file, sections, names, names_end, elf_header->e_shnum); if (gnu_debuglink_section) { - if (!info->debug_dir().empty()) { + if (!info->debug_dirs().empty()) { const char* debuglink_contents = GetOffset(elf_header, gnu_debuglink_section->sh_offset); string debuglink_file = ReadDebugLink(debuglink_contents, gnu_debuglink_section->sh_size, - obj_file, info->debug_dir()); + obj_file, info->debug_dirs()); info->set_debuglink_file(debuglink_file); } else { fprintf(stderr, ".gnu_debuglink section found in '%s', " @@ -712,7 +726,7 @@ string BaseFileName(const string &filename) { template bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, - const string& debug_dir, + const std::vector& debug_dirs, bool cfi, Module** out_module) { typedef typename ElfClass::Ehdr Ehdr; @@ -744,10 +758,10 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, string os = "Linux"; string id = FormatIdentifier(identifier); - LoadSymbolsInfo info(debug_dir); + LoadSymbolsInfo info(debug_dirs); scoped_ptr module(new Module(name, os, architecture, id)); if (!LoadSymbols(obj_filename, big_endian, elf_header, - !debug_dir.empty(), &info, module.get())) { + !debug_dirs.empty(), &info, module.get())) { const string debuglink_file = info.debuglink_file(); if (debuglink_file.empty()) return false; @@ -801,7 +815,7 @@ namespace google_breakpad { // Not explicitly exported, but not static so it can be used in unit tests. bool ReadSymbolDataInternal(const uint8_t* obj_file, const string& obj_filename, - const string& debug_dir, + const std::vector& debug_dirs, bool cfi, Module** module) { @@ -813,12 +827,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, int elfclass = ElfClass(obj_file); if (elfclass == ELFCLASS32) { return ReadSymbolDataElfClass( - reinterpret_cast(obj_file), obj_filename, debug_dir, + reinterpret_cast(obj_file), obj_filename, debug_dirs, cfi, module); } if (elfclass == ELFCLASS64) { return ReadSymbolDataElfClass( - reinterpret_cast(obj_file), obj_filename, debug_dir, + reinterpret_cast(obj_file), obj_filename, debug_dirs, cfi, module); } @@ -826,11 +840,11 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, } bool WriteSymbolFile(const string &obj_file, - const string &debug_dir, + const std::vector& debug_dirs, bool cfi, std::ostream &sym_stream) { Module* module; - if (!ReadSymbolData(obj_file, debug_dir, cfi, &module)) + if (!ReadSymbolData(obj_file, debug_dirs, cfi, &module)) return false; bool result = module->Write(sym_stream, cfi); @@ -839,7 +853,7 @@ bool WriteSymbolFile(const string &obj_file, } bool ReadSymbolData(const string& obj_file, - const string& debug_dir, + const std::vector& debug_dirs, bool cfi, Module** module) { MmapWrapper map_wrapper; @@ -848,7 +862,7 @@ bool ReadSymbolData(const string& obj_file, return false; return ReadSymbolDataInternal(reinterpret_cast(elf_header), - obj_file, debug_dir, cfi, module); + obj_file, debug_dirs, cfi, module); } } // namespace google_breakpad diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h index 9084733e..8765ffdb 100644 --- a/src/common/linux/dump_symbols.h +++ b/src/common/linux/dump_symbols.h @@ -37,6 +37,7 @@ #include #include +#include #include "common/using_std_string.h" @@ -48,10 +49,10 @@ class Module; // or shared library, and write it to SYM_STREAM in the Breakpad symbol // file format. // If OBJ_FILE has been stripped but contains a .gnu_debuglink section, -// then look for the debug file in DEBUG_DIR. +// then look for the debug file in DEBUG_DIRS. // If CFI is set to false, then omit the CFI section. bool WriteSymbolFile(const string &obj_file, - const string &debug_dir, + const std::vector& debug_dirs, bool cfi, std::ostream &sym_stream); @@ -59,7 +60,7 @@ bool WriteSymbolFile(const string &obj_file, // instead of writing it to a stream. The caller owns the resulting // Module object and must delete it when finished. bool ReadSymbolData(const string& obj_file, - const string& debug_dir, + const std::vector& debug_dirs, bool cfi, Module** module); diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 3d9b4a9e..d48512f7 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -46,8 +46,8 @@ namespace google_breakpad { bool ReadSymbolDataInternal(const uint8_t* obj_file, - const string &obj_filename, - const string &debug_dir, + const string& obj_filename, + const std::vector& debug_dir, bool cfi, Module** module); } @@ -84,10 +84,10 @@ TEST_F(DumpSymbols, Invalid) { memset(&header, 0, sizeof(header)); Module* module; EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast(&header), - "foo", - "", - true, - &module)); + "foo", + vector(), + true, + &module)); } TEST_F(DumpSymbols, SimplePublic32) { @@ -117,7 +117,7 @@ TEST_F(DumpSymbols, SimplePublic32) { Module* module; EXPECT_TRUE(ReadSymbolDataInternal(elfdata, "foo", - "", + vector(), true, &module)); @@ -156,7 +156,7 @@ TEST_F(DumpSymbols, SimplePublic64) { Module* module; EXPECT_TRUE(ReadSymbolDataInternal(elfdata, "foo", - "", + vector(), true, &module)); diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index adac216c..aa504589 100644 --- a/src/tools/linux/dump_syms/dump_syms.cc +++ b/src/tools/linux/dump_syms/dump_syms.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include "common/linux/dump_symbols.h" @@ -39,7 +40,7 @@ using google_breakpad::WriteSymbolFile; int usage(const char* self) { fprintf(stderr, "Usage: %s [OPTION] " - "[directory-for-debug-file]\n\n", self); + "[directories-for-debug-file]\n\n", self); fprintf(stderr, "Options:\n"); fprintf(stderr, " -c Do not generate CFI section\n"); return 1; @@ -50,24 +51,24 @@ int main(int argc, char **argv) { return usage(argv[0]); bool cfi = true; - if (strcmp("-c", argv[1]) == 0) + int binary_index = 1; + if (strcmp("-c", argv[1]) == 0) { cfi = false; + ++binary_index; + } if (!cfi && argc == 2) return usage(argv[0]); const char *binary; - std::string debug_dir; - if (cfi) { - binary = argv[1]; - if (argc == 3) - debug_dir = argv[2]; - } else { - binary = argv[2]; - if (argc == 4) - debug_dir = argv[3]; + std::vector debug_dirs; + binary = argv[binary_index]; + for (int debug_dir_index = binary_index + 1; + debug_dir_index < argc; + ++debug_dir_index) { + debug_dirs.push_back(argv[debug_dir_index]); } - if (!WriteSymbolFile(binary, debug_dir, cfi, std::cout)) { + if (!WriteSymbolFile(binary, debug_dirs, cfi, std::cout)) { fprintf(stderr, "Failed to write symbol file.\n"); return 1; }