toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // Copyright (c) 2011 Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Restructured in 2009 by: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // dump_symbols.cc: implement google_breakpad::WriteSymbolFile:
michael@0 33 // Find all the debugging info in a file and dump it as a Breakpad symbol file.
michael@0 34
michael@0 35 #include "common/linux/dump_symbols.h"
michael@0 36
michael@0 37 #include <assert.h>
michael@0 38 #include <elf.h>
michael@0 39 #include <errno.h>
michael@0 40 #include <fcntl.h>
michael@0 41 #include <link.h>
michael@0 42 #include <stdio.h>
michael@0 43 #include <stdlib.h>
michael@0 44 #include <string.h>
michael@0 45 #include <sys/mman.h>
michael@0 46 #include <sys/stat.h>
michael@0 47 #include <unistd.h>
michael@0 48
michael@0 49 #include <iostream>
michael@0 50 #include <set>
michael@0 51 #include <string>
michael@0 52 #include <utility>
michael@0 53 #include <vector>
michael@0 54
michael@0 55 #include "common/arm_ex_reader.h"
michael@0 56 #include "common/dwarf/bytereader-inl.h"
michael@0 57 #include "common/dwarf/dwarf2diehandler.h"
michael@0 58 #include "common/dwarf_cfi_to_module.h"
michael@0 59 #include "common/dwarf_cu_to_module.h"
michael@0 60 #include "common/dwarf_line_to_module.h"
michael@0 61 #include "common/linux/elfutils.h"
michael@0 62 #include "common/linux/elfutils-inl.h"
michael@0 63 #include "common/linux/elf_symbols_to_module.h"
michael@0 64 #include "common/linux/file_id.h"
michael@0 65 #include "common/module.h"
michael@0 66 #include "common/scoped_ptr.h"
michael@0 67 #ifndef NO_STABS_SUPPORT
michael@0 68 #include "common/stabs_reader.h"
michael@0 69 #include "common/stabs_to_module.h"
michael@0 70 #endif
michael@0 71 #include "common/using_std_string.h"
michael@0 72 #include "common/logging.h"
michael@0 73
michael@0 74 #ifndef SHT_ARM_EXIDX
michael@0 75 // bionic and older glibc don't define it
michael@0 76 # define SHT_ARM_EXIDX (SHT_LOPROC + 1)
michael@0 77 #endif
michael@0 78
michael@0 79 // This namespace contains helper functions.
michael@0 80 namespace {
michael@0 81
michael@0 82 using google_breakpad::DwarfCFIToModule;
michael@0 83 using google_breakpad::DwarfCUToModule;
michael@0 84 using google_breakpad::DwarfLineToModule;
michael@0 85 using google_breakpad::ElfClass;
michael@0 86 using google_breakpad::ElfClass32;
michael@0 87 using google_breakpad::ElfClass64;
michael@0 88 using google_breakpad::FindElfSectionByName;
michael@0 89 using google_breakpad::GetOffset;
michael@0 90 using google_breakpad::IsValidElf;
michael@0 91 using google_breakpad::Module;
michael@0 92 #ifndef NO_STABS_SUPPORT
michael@0 93 using google_breakpad::StabsToModule;
michael@0 94 #endif
michael@0 95 using google_breakpad::UniqueString;
michael@0 96 using google_breakpad::scoped_ptr;
michael@0 97
michael@0 98 //
michael@0 99 // FDWrapper
michael@0 100 //
michael@0 101 // Wrapper class to make sure opened file is closed.
michael@0 102 //
michael@0 103 class FDWrapper {
michael@0 104 public:
michael@0 105 explicit FDWrapper(int fd) :
michael@0 106 fd_(fd) {}
michael@0 107 ~FDWrapper() {
michael@0 108 if (fd_ != -1)
michael@0 109 close(fd_);
michael@0 110 }
michael@0 111 int get() {
michael@0 112 return fd_;
michael@0 113 }
michael@0 114 int release() {
michael@0 115 int fd = fd_;
michael@0 116 fd_ = -1;
michael@0 117 return fd;
michael@0 118 }
michael@0 119 private:
michael@0 120 int fd_;
michael@0 121 };
michael@0 122
michael@0 123 //
michael@0 124 // MmapWrapper
michael@0 125 //
michael@0 126 // Wrapper class to make sure mapped regions are unmapped.
michael@0 127 //
michael@0 128 class MmapWrapper {
michael@0 129 public:
michael@0 130 MmapWrapper() : is_set_(false) {}
michael@0 131 ~MmapWrapper() {
michael@0 132 if (is_set_ && base_ != NULL) {
michael@0 133 assert(size_ > 0);
michael@0 134 munmap(base_, size_);
michael@0 135 }
michael@0 136 }
michael@0 137 void set(void *mapped_address, size_t mapped_size) {
michael@0 138 is_set_ = true;
michael@0 139 base_ = mapped_address;
michael@0 140 size_ = mapped_size;
michael@0 141 }
michael@0 142 void release() {
michael@0 143 assert(is_set_);
michael@0 144 is_set_ = false;
michael@0 145 base_ = NULL;
michael@0 146 size_ = 0;
michael@0 147 }
michael@0 148
michael@0 149 private:
michael@0 150 bool is_set_;
michael@0 151 void *base_;
michael@0 152 size_t size_;
michael@0 153 };
michael@0 154
michael@0 155 // Find the preferred loading address of the binary.
michael@0 156 template<typename ElfClass>
michael@0 157 typename ElfClass::Addr GetLoadingAddress(
michael@0 158 const typename ElfClass::Phdr* program_headers,
michael@0 159 int nheader) {
michael@0 160 typedef typename ElfClass::Phdr Phdr;
michael@0 161
michael@0 162 for (int i = 0; i < nheader; ++i) {
michael@0 163 const Phdr& header = program_headers[i];
michael@0 164 // For executable, it is the PT_LOAD segment with offset to zero.
michael@0 165 if (header.p_type == PT_LOAD &&
michael@0 166 header.p_offset == 0)
michael@0 167 return header.p_vaddr;
michael@0 168 }
michael@0 169 // For other types of ELF, return 0.
michael@0 170 return 0;
michael@0 171 }
michael@0 172
michael@0 173 #ifndef NO_STABS_SUPPORT
michael@0 174 template<typename ElfClass>
michael@0 175 bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
michael@0 176 const typename ElfClass::Shdr* stab_section,
michael@0 177 const typename ElfClass::Shdr* stabstr_section,
michael@0 178 const bool big_endian,
michael@0 179 Module* module) {
michael@0 180 // A callback object to handle data from the STABS reader.
michael@0 181 StabsToModule handler(module);
michael@0 182 // Find the addresses of the STABS data, and create a STABS reader object.
michael@0 183 // On Linux, STABS entries always have 32-bit values, regardless of the
michael@0 184 // address size of the architecture whose code they're describing, and
michael@0 185 // the strings are always "unitized".
michael@0 186 const uint8_t* stabs =
michael@0 187 GetOffset<ElfClass, uint8_t>(elf_header, stab_section->sh_offset);
michael@0 188 const uint8_t* stabstr =
michael@0 189 GetOffset<ElfClass, uint8_t>(elf_header, stabstr_section->sh_offset);
michael@0 190 google_breakpad::StabsReader reader(stabs, stab_section->sh_size,
michael@0 191 stabstr, stabstr_section->sh_size,
michael@0 192 big_endian, 4, true, &handler);
michael@0 193 // Read the STABS data, and do post-processing.
michael@0 194 if (!reader.Process())
michael@0 195 return false;
michael@0 196 handler.Finalize();
michael@0 197 return true;
michael@0 198 }
michael@0 199 #endif // NO_STABS_SUPPORT
michael@0 200
michael@0 201 // A line-to-module loader that accepts line number info parsed by
michael@0 202 // dwarf2reader::LineInfo and populates a Module and a line vector
michael@0 203 // with the results.
michael@0 204 class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
michael@0 205 public:
michael@0 206 // Create a line-to-module converter using BYTE_READER.
michael@0 207 explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
michael@0 208 : byte_reader_(byte_reader) { }
michael@0 209 void StartCompilationUnit(const string& compilation_dir) {
michael@0 210 compilation_dir_ = compilation_dir;
michael@0 211 }
michael@0 212 void ReadProgram(const char *program, uint64 length,
michael@0 213 Module *module, std::vector<Module::Line> *lines) {
michael@0 214 DwarfLineToModule handler(module, compilation_dir_, lines);
michael@0 215 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
michael@0 216 parser.Start();
michael@0 217 }
michael@0 218 private:
michael@0 219 string compilation_dir_;
michael@0 220 dwarf2reader::ByteReader *byte_reader_;
michael@0 221 };
michael@0 222
michael@0 223 template<typename ElfClass>
michael@0 224 bool LoadDwarf(const string& dwarf_filename,
michael@0 225 const typename ElfClass::Ehdr* elf_header,
michael@0 226 const bool big_endian,
michael@0 227 Module* module) {
michael@0 228 typedef typename ElfClass::Shdr Shdr;
michael@0 229
michael@0 230 const dwarf2reader::Endianness endianness = big_endian ?
michael@0 231 dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
michael@0 232 dwarf2reader::ByteReader byte_reader(endianness);
michael@0 233
michael@0 234 // Construct a context for this file.
michael@0 235 DwarfCUToModule::FileContext file_context(dwarf_filename, module);
michael@0 236
michael@0 237 // Build a map of the ELF file's sections.
michael@0 238 const Shdr* sections =
michael@0 239 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
michael@0 240 int num_sections = elf_header->e_shnum;
michael@0 241 const Shdr* section_names = sections + elf_header->e_shstrndx;
michael@0 242 for (int i = 0; i < num_sections; i++) {
michael@0 243 const Shdr* section = &sections[i];
michael@0 244 string name = GetOffset<ElfClass, char>(elf_header,
michael@0 245 section_names->sh_offset) +
michael@0 246 section->sh_name;
michael@0 247 const char* contents = GetOffset<ElfClass, char>(elf_header,
michael@0 248 section->sh_offset);
michael@0 249 uint64 length = section->sh_size;
michael@0 250 file_context.section_map[name] = std::make_pair(contents, length);
michael@0 251 }
michael@0 252
michael@0 253 // Parse all the compilation units in the .debug_info section.
michael@0 254 DumperLineToModule line_to_module(&byte_reader);
michael@0 255 std::pair<const char *, uint64> debug_info_section
michael@0 256 = file_context.section_map[".debug_info"];
michael@0 257 // This should never have been called if the file doesn't have a
michael@0 258 // .debug_info section.
michael@0 259 assert(debug_info_section.first);
michael@0 260 uint64 debug_info_length = debug_info_section.second;
michael@0 261 for (uint64 offset = 0; offset < debug_info_length;) {
michael@0 262 // Make a handler for the root DIE that populates MODULE with the
michael@0 263 // data that was found.
michael@0 264 DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
michael@0 265 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
michael@0 266 // Make a Dwarf2Handler that drives the DIEHandler.
michael@0 267 dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
michael@0 268 // Make a DWARF parser for the compilation unit at OFFSET.
michael@0 269 dwarf2reader::CompilationUnit reader(file_context.section_map,
michael@0 270 offset,
michael@0 271 &byte_reader,
michael@0 272 &die_dispatcher);
michael@0 273 // Process the entire compilation unit; get the offset of the next.
michael@0 274 offset += reader.Start();
michael@0 275 }
michael@0 276 return true;
michael@0 277 }
michael@0 278
michael@0 279 // Fill REGISTER_NAMES with the register names appropriate to the
michael@0 280 // machine architecture given in HEADER, indexed by the register
michael@0 281 // numbers used in DWARF call frame information. Return true on
michael@0 282 // success, or false if HEADER's machine architecture is not
michael@0 283 // supported.
michael@0 284 template<typename ElfClass>
michael@0 285 bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header,
michael@0 286 std::vector<const UniqueString*>* register_names) {
michael@0 287 switch (elf_header->e_machine) {
michael@0 288 case EM_386:
michael@0 289 *register_names = DwarfCFIToModule::RegisterNames::I386();
michael@0 290 return true;
michael@0 291 case EM_ARM:
michael@0 292 *register_names = DwarfCFIToModule::RegisterNames::ARM();
michael@0 293 return true;
michael@0 294 case EM_X86_64:
michael@0 295 *register_names = DwarfCFIToModule::RegisterNames::X86_64();
michael@0 296 return true;
michael@0 297 default:
michael@0 298 return false;
michael@0 299 }
michael@0 300 }
michael@0 301
michael@0 302 template<typename ElfClass>
michael@0 303 bool LoadDwarfCFI(const string& dwarf_filename,
michael@0 304 const typename ElfClass::Ehdr* elf_header,
michael@0 305 const char* section_name,
michael@0 306 const typename ElfClass::Shdr* section,
michael@0 307 const bool eh_frame,
michael@0 308 const typename ElfClass::Shdr* got_section,
michael@0 309 const typename ElfClass::Shdr* text_section,
michael@0 310 const bool big_endian,
michael@0 311 Module* module) {
michael@0 312 // Find the appropriate set of register names for this file's
michael@0 313 // architecture.
michael@0 314 std::vector<const UniqueString*> register_names;
michael@0 315 if (!DwarfCFIRegisterNames<ElfClass>(elf_header, &register_names)) {
michael@0 316 fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
michael@0 317 " cannot convert DWARF call frame information\n",
michael@0 318 dwarf_filename.c_str(), elf_header->e_machine);
michael@0 319 return false;
michael@0 320 }
michael@0 321
michael@0 322 const dwarf2reader::Endianness endianness = big_endian ?
michael@0 323 dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
michael@0 324
michael@0 325 // Find the call frame information and its size.
michael@0 326 const char* cfi =
michael@0 327 GetOffset<ElfClass, char>(elf_header, section->sh_offset);
michael@0 328 size_t cfi_size = section->sh_size;
michael@0 329
michael@0 330 // Plug together the parser, handler, and their entourages.
michael@0 331 DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
michael@0 332 DwarfCFIToModule handler(module, register_names, &module_reporter);
michael@0 333 dwarf2reader::ByteReader byte_reader(endianness);
michael@0 334
michael@0 335 byte_reader.SetAddressSize(ElfClass::kAddrSize);
michael@0 336
michael@0 337 // Provide the base addresses for .eh_frame encoded pointers, if
michael@0 338 // possible.
michael@0 339 byte_reader.SetCFIDataBase(section->sh_addr, cfi);
michael@0 340 if (got_section)
michael@0 341 byte_reader.SetDataBase(got_section->sh_addr);
michael@0 342 if (text_section)
michael@0 343 byte_reader.SetTextBase(text_section->sh_addr);
michael@0 344
michael@0 345 dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
michael@0 346 section_name);
michael@0 347 dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
michael@0 348 &byte_reader, &handler, &dwarf_reporter,
michael@0 349 eh_frame);
michael@0 350 parser.Start();
michael@0 351 return true;
michael@0 352 }
michael@0 353
michael@0 354 template<typename ElfClass>
michael@0 355 bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header,
michael@0 356 const typename ElfClass::Shdr* exidx_section,
michael@0 357 const typename ElfClass::Shdr* extab_section,
michael@0 358 uint32_t loading_addr,
michael@0 359 Module* module) {
michael@0 360 // To do this properly we need to know:
michael@0 361 // * the bounds of the .ARM.exidx section in the mapped image
michael@0 362 // * the bounds of the .ARM.extab section in the mapped image
michael@0 363 // * the vma of the last byte in the text section associated with the .exidx
michael@0 364 // The first two are easy. The third is a bit tricky. If we can't
michael@0 365 // figure out what it is, just pass in zero.
michael@0 366 const char *exidx_img
michael@0 367 = GetOffset<ElfClass, char>(elf_header, exidx_section->sh_offset);
michael@0 368 size_t exidx_size = exidx_section->sh_size;
michael@0 369 const char *extab_img
michael@0 370 = GetOffset<ElfClass, char>(elf_header, extab_section->sh_offset);
michael@0 371 size_t extab_size = extab_section->sh_size;
michael@0 372
michael@0 373 // The sh_link field of the exidx section gives the section number
michael@0 374 // for the associated text section.
michael@0 375 uint32_t exidx_text_last_svma = 0;
michael@0 376 int exidx_text_sno = exidx_section->sh_link;
michael@0 377 typedef typename ElfClass::Shdr Shdr;
michael@0 378 // |sections| points to the section header table
michael@0 379 const Shdr* sections
michael@0 380 = GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
michael@0 381 const int num_sections = elf_header->e_shnum;
michael@0 382 if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) {
michael@0 383 const Shdr* exidx_text_shdr = &sections[exidx_text_sno];
michael@0 384 if (exidx_text_shdr->sh_size > 0) {
michael@0 385 exidx_text_last_svma
michael@0 386 = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1;
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 arm_ex_to_module::ARMExToModule handler(module);
michael@0 391 arm_ex_reader::ExceptionTableInfo
michael@0 392 parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma,
michael@0 393 &handler,
michael@0 394 reinterpret_cast<const char*>(elf_header),
michael@0 395 loading_addr);
michael@0 396 parser.Start();
michael@0 397 return true;
michael@0 398 }
michael@0 399
michael@0 400 bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper,
michael@0 401 void** elf_header) {
michael@0 402 int obj_fd = open(obj_file.c_str(), O_RDONLY);
michael@0 403 if (obj_fd < 0) {
michael@0 404 fprintf(stderr, "Failed to open ELF file '%s': %s\n",
michael@0 405 obj_file.c_str(), strerror(errno));
michael@0 406 return false;
michael@0 407 }
michael@0 408 FDWrapper obj_fd_wrapper(obj_fd);
michael@0 409 struct stat st;
michael@0 410 if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) {
michael@0 411 fprintf(stderr, "Unable to fstat ELF file '%s': %s\n",
michael@0 412 obj_file.c_str(), strerror(errno));
michael@0 413 return false;
michael@0 414 }
michael@0 415 void *obj_base = mmap(NULL, st.st_size,
michael@0 416 PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
michael@0 417 if (obj_base == MAP_FAILED) {
michael@0 418 fprintf(stderr, "Failed to mmap ELF file '%s': %s\n",
michael@0 419 obj_file.c_str(), strerror(errno));
michael@0 420 return false;
michael@0 421 }
michael@0 422 map_wrapper->set(obj_base, st.st_size);
michael@0 423 *elf_header = obj_base;
michael@0 424 if (!IsValidElf(*elf_header)) {
michael@0 425 fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
michael@0 426 return false;
michael@0 427 }
michael@0 428 return true;
michael@0 429 }
michael@0 430
michael@0 431 // Get the endianness of ELF_HEADER. If it's invalid, return false.
michael@0 432 template<typename ElfClass>
michael@0 433 bool ElfEndianness(const typename ElfClass::Ehdr* elf_header,
michael@0 434 bool* big_endian) {
michael@0 435 if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB) {
michael@0 436 *big_endian = false;
michael@0 437 return true;
michael@0 438 }
michael@0 439 if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB) {
michael@0 440 *big_endian = true;
michael@0 441 return true;
michael@0 442 }
michael@0 443
michael@0 444 fprintf(stderr, "bad data encoding in ELF header: %d\n",
michael@0 445 elf_header->e_ident[EI_DATA]);
michael@0 446 return false;
michael@0 447 }
michael@0 448
michael@0 449 // Read the .gnu_debuglink and get the debug file name. If anything goes
michael@0 450 // wrong, return an empty string.
michael@0 451 template<typename ElfClass>
michael@0 452 string ReadDebugLink(const char* debuglink,
michael@0 453 size_t debuglink_size,
michael@0 454 const string& obj_file,
michael@0 455 const std::vector<string>& debug_dirs) {
michael@0 456 size_t debuglink_len = strlen(debuglink) + 5; // '\0' + CRC32.
michael@0 457 debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round to nearest 4 bytes.
michael@0 458
michael@0 459 // Sanity check.
michael@0 460 if (debuglink_len != debuglink_size) {
michael@0 461 fprintf(stderr, "Mismatched .gnu_debuglink string / section size: "
michael@0 462 "%zx %zx\n", debuglink_len, debuglink_size);
michael@0 463 return "";
michael@0 464 }
michael@0 465
michael@0 466 bool found = false;
michael@0 467 int debuglink_fd = -1;
michael@0 468 string debuglink_path;
michael@0 469 std::vector<string>::const_iterator it;
michael@0 470 for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
michael@0 471 const string& debug_dir = *it;
michael@0 472 debuglink_path = debug_dir + "/" + debuglink;
michael@0 473 debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
michael@0 474 if (debuglink_fd >= 0) {
michael@0 475 found = true;
michael@0 476 break;
michael@0 477 }
michael@0 478 }
michael@0 479
michael@0 480 if (!found) {
michael@0 481 fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n",
michael@0 482 obj_file.c_str());
michael@0 483 for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
michael@0 484 const string debug_dir = *it;
michael@0 485 fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink);
michael@0 486 }
michael@0 487 return "";
michael@0 488 }
michael@0 489
michael@0 490 FDWrapper debuglink_fd_wrapper(debuglink_fd);
michael@0 491 // TODO(thestig) check the CRC-32 at the end of the .gnu_debuglink
michael@0 492 // section.
michael@0 493
michael@0 494 return debuglink_path;
michael@0 495 }
michael@0 496
michael@0 497 //
michael@0 498 // LoadSymbolsInfo
michael@0 499 //
michael@0 500 // Holds the state between the two calls to LoadSymbols() in case it's necessary
michael@0 501 // to follow the .gnu_debuglink section and load debug information from a
michael@0 502 // different file.
michael@0 503 //
michael@0 504 template<typename ElfClass>
michael@0 505 class LoadSymbolsInfo {
michael@0 506 public:
michael@0 507 typedef typename ElfClass::Addr Addr;
michael@0 508
michael@0 509 explicit LoadSymbolsInfo(const std::vector<string>& dbg_dirs) :
michael@0 510 debug_dirs_(dbg_dirs),
michael@0 511 has_loading_addr_(false) {}
michael@0 512
michael@0 513 // Keeps track of which sections have been loaded so sections don't
michael@0 514 // accidentally get loaded twice from two different files.
michael@0 515 void LoadedSection(const string &section) {
michael@0 516 if (loaded_sections_.count(section) == 0) {
michael@0 517 loaded_sections_.insert(section);
michael@0 518 } else {
michael@0 519 fprintf(stderr, "Section %s has already been loaded.\n",
michael@0 520 section.c_str());
michael@0 521 }
michael@0 522 }
michael@0 523
michael@0 524 // The ELF file and linked debug file are expected to have the same preferred
michael@0 525 // loading address.
michael@0 526 void set_loading_addr(Addr addr, const string &filename) {
michael@0 527 if (!has_loading_addr_) {
michael@0 528 loading_addr_ = addr;
michael@0 529 loaded_file_ = filename;
michael@0 530 return;
michael@0 531 }
michael@0 532
michael@0 533 if (addr != loading_addr_) {
michael@0 534 fprintf(stderr,
michael@0 535 "ELF file '%s' and debug ELF file '%s' "
michael@0 536 "have different load addresses.\n",
michael@0 537 loaded_file_.c_str(), filename.c_str());
michael@0 538 assert(false);
michael@0 539 }
michael@0 540 }
michael@0 541
michael@0 542 // Setters and getters
michael@0 543 const std::vector<string>& debug_dirs() const {
michael@0 544 return debug_dirs_;
michael@0 545 }
michael@0 546
michael@0 547 string debuglink_file() const {
michael@0 548 return debuglink_file_;
michael@0 549 }
michael@0 550 void set_debuglink_file(string file) {
michael@0 551 debuglink_file_ = file;
michael@0 552 }
michael@0 553
michael@0 554 private:
michael@0 555 const std::vector<string>& debug_dirs_; // Directories in which to
michael@0 556 // search for the debug ELF file.
michael@0 557
michael@0 558 string debuglink_file_; // Full path to the debug ELF file.
michael@0 559
michael@0 560 bool has_loading_addr_; // Indicate if LOADING_ADDR_ is valid.
michael@0 561
michael@0 562 Addr loading_addr_; // Saves the preferred loading address from the
michael@0 563 // first call to LoadSymbols().
michael@0 564
michael@0 565 string loaded_file_; // Name of the file loaded from the first call to
michael@0 566 // LoadSymbols().
michael@0 567
michael@0 568 std::set<string> loaded_sections_; // Tracks the Loaded ELF sections
michael@0 569 // between calls to LoadSymbols().
michael@0 570 };
michael@0 571
michael@0 572 template<typename ElfClass>
michael@0 573 bool LoadSymbols(const string& obj_file,
michael@0 574 const bool big_endian,
michael@0 575 const typename ElfClass::Ehdr* elf_header,
michael@0 576 const bool read_gnu_debug_link,
michael@0 577 LoadSymbolsInfo<ElfClass>* info,
michael@0 578 SymbolData symbol_data,
michael@0 579 Module* module) {
michael@0 580 typedef typename ElfClass::Addr Addr;
michael@0 581 typedef typename ElfClass::Phdr Phdr;
michael@0 582 typedef typename ElfClass::Shdr Shdr;
michael@0 583
michael@0 584 BPLOG(INFO) << "";
michael@0 585 BPLOG(INFO) << "LoadSymbols: BEGIN " << obj_file;
michael@0 586
michael@0 587 Addr loading_addr = GetLoadingAddress<ElfClass>(
michael@0 588 GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
michael@0 589 elf_header->e_phnum);
michael@0 590 module->SetLoadAddress(loading_addr);
michael@0 591 info->set_loading_addr(loading_addr, obj_file);
michael@0 592
michael@0 593 const Shdr* sections =
michael@0 594 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
michael@0 595 const Shdr* section_names = sections + elf_header->e_shstrndx;
michael@0 596 const char* names =
michael@0 597 GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
michael@0 598 const char *names_end = names + section_names->sh_size;
michael@0 599 bool found_debug_info_section = false;
michael@0 600 bool found_usable_info = false;
michael@0 601
michael@0 602 if (symbol_data != ONLY_CFI) {
michael@0 603 #ifndef NO_STABS_SUPPORT
michael@0 604 // Look for STABS debugging information, and load it if present.
michael@0 605 const Shdr* stab_section =
michael@0 606 FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
michael@0 607 sections, names, names_end,
michael@0 608 elf_header->e_shnum);
michael@0 609 if (stab_section) {
michael@0 610 const Shdr* stabstr_section = stab_section->sh_link + sections;
michael@0 611 if (stabstr_section) {
michael@0 612 found_debug_info_section = true;
michael@0 613 found_usable_info = true;
michael@0 614 info->LoadedSection(".stab");
michael@0 615 if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
michael@0 616 big_endian, module)) {
michael@0 617 fprintf(stderr, "%s: \".stab\" section found, but failed to load"
michael@0 618 " STABS debugging information\n", obj_file.c_str());
michael@0 619 }
michael@0 620 }
michael@0 621 }
michael@0 622 #endif // NO_STABS_SUPPORT
michael@0 623
michael@0 624 // Look for DWARF debugging information, and load it if present.
michael@0 625 const Shdr* dwarf_section =
michael@0 626 FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
michael@0 627 sections, names, names_end,
michael@0 628 elf_header->e_shnum);
michael@0 629 if (dwarf_section) {
michael@0 630 found_debug_info_section = true;
michael@0 631 found_usable_info = true;
michael@0 632 info->LoadedSection(".debug_info");
michael@0 633 if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, module))
michael@0 634 fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
michael@0 635 "DWARF debugging information\n", obj_file.c_str());
michael@0 636 }
michael@0 637 }
michael@0 638
michael@0 639 if (symbol_data != NO_CFI) {
michael@0 640 // Dwarf Call Frame Information (CFI) is actually independent from
michael@0 641 // the other DWARF debugging information, and can be used alone.
michael@0 642 const Shdr* dwarf_cfi_section =
michael@0 643 FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
michael@0 644 sections, names, names_end,
michael@0 645 elf_header->e_shnum);
michael@0 646 if (dwarf_cfi_section) {
michael@0 647 // Ignore the return value of this function; even without call frame
michael@0 648 // information, the other debugging information could be perfectly
michael@0 649 // useful.
michael@0 650 info->LoadedSection(".debug_frame");
michael@0 651 bool result =
michael@0 652 LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
michael@0 653 dwarf_cfi_section, false, 0, 0, big_endian,
michael@0 654 module);
michael@0 655 found_usable_info = found_usable_info || result;
michael@0 656 if (result)
michael@0 657 BPLOG(INFO) << "LoadSymbols: read CFI from .debug_frame";
michael@0 658 }
michael@0 659
michael@0 660 // Linux C++ exception handling information can also provide
michael@0 661 // unwinding data.
michael@0 662 const Shdr* eh_frame_section =
michael@0 663 FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
michael@0 664 sections, names, names_end,
michael@0 665 elf_header->e_shnum);
michael@0 666 if (eh_frame_section) {
michael@0 667 // Pointers in .eh_frame data may be relative to the base addresses of
michael@0 668 // certain sections. Provide those sections if present.
michael@0 669 const Shdr* got_section =
michael@0 670 FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
michael@0 671 sections, names, names_end,
michael@0 672 elf_header->e_shnum);
michael@0 673 const Shdr* text_section =
michael@0 674 FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
michael@0 675 sections, names, names_end,
michael@0 676 elf_header->e_shnum);
michael@0 677 info->LoadedSection(".eh_frame");
michael@0 678 // As above, ignore the return value of this function.
michael@0 679 bool result =
michael@0 680 LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
michael@0 681 eh_frame_section, true,
michael@0 682 got_section, text_section, big_endian, module);
michael@0 683 found_usable_info = found_usable_info || result;
michael@0 684 if (result)
michael@0 685 BPLOG(INFO) << "LoadSymbols: read CFI from .eh_frame";
michael@0 686 }
michael@0 687 }
michael@0 688
michael@0 689 // ARM has special unwind tables that can be used.
michael@0 690 const Shdr* arm_exidx_section =
michael@0 691 FindElfSectionByName<ElfClass>(".ARM.exidx", SHT_ARM_EXIDX,
michael@0 692 sections, names, names_end,
michael@0 693 elf_header->e_shnum);
michael@0 694 const Shdr* arm_extab_section =
michael@0 695 FindElfSectionByName<ElfClass>(".ARM.extab", SHT_PROGBITS,
michael@0 696 sections, names, names_end,
michael@0 697 elf_header->e_shnum);
michael@0 698 // Only load information from this section if there isn't a .debug_info
michael@0 699 // section.
michael@0 700 if (!found_debug_info_section
michael@0 701 && arm_exidx_section && arm_extab_section && symbol_data != NO_CFI) {
michael@0 702 info->LoadedSection(".ARM.exidx");
michael@0 703 info->LoadedSection(".ARM.extab");
michael@0 704 bool result = LoadARMexidx<ElfClass>(elf_header,
michael@0 705 arm_exidx_section, arm_extab_section,
michael@0 706 loading_addr, module);
michael@0 707 found_usable_info = found_usable_info || result;
michael@0 708 if (result)
michael@0 709 BPLOG(INFO) << "LoadSymbols: read EXIDX from .ARM.{exidx,extab}";
michael@0 710 }
michael@0 711
michael@0 712 if (!found_debug_info_section && symbol_data != ONLY_CFI) {
michael@0 713 fprintf(stderr, "%s: file contains no debugging information"
michael@0 714 " (no \".stab\" or \".debug_info\" sections)\n",
michael@0 715 obj_file.c_str());
michael@0 716
michael@0 717 // Failed, but maybe there's a .gnu_debuglink section?
michael@0 718 if (read_gnu_debug_link) {
michael@0 719 const Shdr* gnu_debuglink_section
michael@0 720 = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS,
michael@0 721 sections, names,
michael@0 722 names_end, elf_header->e_shnum);
michael@0 723 if (gnu_debuglink_section) {
michael@0 724 if (!info->debug_dirs().empty()) {
michael@0 725 const char* debuglink_contents =
michael@0 726 GetOffset<ElfClass, char>(elf_header,
michael@0 727 gnu_debuglink_section->sh_offset);
michael@0 728 string debuglink_file
michael@0 729 = ReadDebugLink<ElfClass>(debuglink_contents,
michael@0 730 gnu_debuglink_section->sh_size,
michael@0 731 obj_file, info->debug_dirs());
michael@0 732 info->set_debuglink_file(debuglink_file);
michael@0 733 } else {
michael@0 734 fprintf(stderr, ".gnu_debuglink section found in '%s', "
michael@0 735 "but no debug path specified.\n", obj_file.c_str());
michael@0 736 }
michael@0 737 } else {
michael@0 738 fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
michael@0 739 obj_file.c_str());
michael@0 740 }
michael@0 741 } else {
michael@0 742 if (symbol_data != ONLY_CFI) {
michael@0 743 // The caller doesn't want to consult .gnu_debuglink.
michael@0 744 // See if there are export symbols available.
michael@0 745 const Shdr* dynsym_section =
michael@0 746 FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
michael@0 747 sections, names, names_end,
michael@0 748 elf_header->e_shnum);
michael@0 749 const Shdr* dynstr_section =
michael@0 750 FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
michael@0 751 sections, names, names_end,
michael@0 752 elf_header->e_shnum);
michael@0 753 if (dynsym_section && dynstr_section) {
michael@0 754 info->LoadedSection(".dynsym");
michael@0 755
michael@0 756 const uint8_t* dynsyms =
michael@0 757 GetOffset<ElfClass, uint8_t>(elf_header,
michael@0 758 dynsym_section->sh_offset);
michael@0 759 const uint8_t* dynstrs =
michael@0 760 GetOffset<ElfClass, uint8_t>(elf_header,
michael@0 761 dynstr_section->sh_offset);
michael@0 762 bool result =
michael@0 763 ELFSymbolsToModule(dynsyms,
michael@0 764 dynsym_section->sh_size,
michael@0 765 dynstrs,
michael@0 766 dynstr_section->sh_size,
michael@0 767 big_endian,
michael@0 768 ElfClass::kAddrSize,
michael@0 769 module);
michael@0 770 found_usable_info = found_usable_info || result;
michael@0 771 }
michael@0 772 }
michael@0 773
michael@0 774 // Return true if some usable information was found, since
michael@0 775 // the caller doesn't want to use .gnu_debuglink.
michael@0 776 BPLOG(INFO) << "LoadSymbols: "
michael@0 777 << (found_usable_info ? "SUCCESS " : "FAILURE ")
michael@0 778 << obj_file;
michael@0 779 return found_usable_info;
michael@0 780 }
michael@0 781
michael@0 782 // No debug info was found, let the user try again with .gnu_debuglink
michael@0 783 // if present.
michael@0 784 BPLOG(INFO) << "LoadSymbols: FAILURE " << obj_file;
michael@0 785 return false;
michael@0 786 }
michael@0 787
michael@0 788 BPLOG(INFO) << "LoadSymbols: SUCCESS " << obj_file;
michael@0 789 return true;
michael@0 790 }
michael@0 791
michael@0 792 // Return the breakpad symbol file identifier for the architecture of
michael@0 793 // ELF_HEADER.
michael@0 794 template<typename ElfClass>
michael@0 795 const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
michael@0 796 typedef typename ElfClass::Half Half;
michael@0 797 Half arch = elf_header->e_machine;
michael@0 798 switch (arch) {
michael@0 799 case EM_386: return "x86";
michael@0 800 case EM_ARM: return "arm";
michael@0 801 case EM_MIPS: return "mips";
michael@0 802 case EM_PPC64: return "ppc64";
michael@0 803 case EM_PPC: return "ppc";
michael@0 804 case EM_S390: return "s390";
michael@0 805 case EM_SPARC: return "sparc";
michael@0 806 case EM_SPARCV9: return "sparcv9";
michael@0 807 case EM_X86_64: return "x86_64";
michael@0 808 default: return NULL;
michael@0 809 }
michael@0 810 }
michael@0 811
michael@0 812 // Format the Elf file identifier in IDENTIFIER as a UUID with the
michael@0 813 // dashes removed.
michael@0 814 string FormatIdentifier(unsigned char identifier[16]) {
michael@0 815 char identifier_str[40];
michael@0 816 google_breakpad::FileID::ConvertIdentifierToString(
michael@0 817 identifier,
michael@0 818 identifier_str,
michael@0 819 sizeof(identifier_str));
michael@0 820 string id_no_dash;
michael@0 821 for (int i = 0; identifier_str[i] != '\0'; ++i)
michael@0 822 if (identifier_str[i] != '-')
michael@0 823 id_no_dash += identifier_str[i];
michael@0 824 // Add an extra "0" by the end. PDB files on Windows have an 'age'
michael@0 825 // number appended to the end of the file identifier; this isn't
michael@0 826 // really used or necessary on other platforms, but be consistent.
michael@0 827 id_no_dash += '0';
michael@0 828 return id_no_dash;
michael@0 829 }
michael@0 830
michael@0 831 // Return the non-directory portion of FILENAME: the portion after the
michael@0 832 // last slash, or the whole filename if there are no slashes.
michael@0 833 string BaseFileName(const string &filename) {
michael@0 834 // Lots of copies! basename's behavior is less than ideal.
michael@0 835 char *c_filename = strdup(filename.c_str());
michael@0 836 string base = basename(c_filename);
michael@0 837 free(c_filename);
michael@0 838 return base;
michael@0 839 }
michael@0 840
michael@0 841 template<typename ElfClass>
michael@0 842 bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
michael@0 843 const string& obj_filename,
michael@0 844 const std::vector<string>& debug_dirs,
michael@0 845 SymbolData symbol_data,
michael@0 846 Module** out_module) {
michael@0 847 typedef typename ElfClass::Ehdr Ehdr;
michael@0 848 typedef typename ElfClass::Shdr Shdr;
michael@0 849
michael@0 850 *out_module = NULL;
michael@0 851
michael@0 852 unsigned char identifier[16];
michael@0 853 if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
michael@0 854 identifier)) {
michael@0 855 fprintf(stderr, "%s: unable to generate file identifier\n",
michael@0 856 obj_filename.c_str());
michael@0 857 return false;
michael@0 858 }
michael@0 859
michael@0 860 const char *architecture = ElfArchitecture<ElfClass>(elf_header);
michael@0 861 if (!architecture) {
michael@0 862 fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
michael@0 863 obj_filename.c_str(), elf_header->e_machine);
michael@0 864 return false;
michael@0 865 }
michael@0 866
michael@0 867 // Figure out what endianness this file is.
michael@0 868 bool big_endian;
michael@0 869 if (!ElfEndianness<ElfClass>(elf_header, &big_endian))
michael@0 870 return false;
michael@0 871
michael@0 872 string name = BaseFileName(obj_filename);
michael@0 873 string os = "Linux";
michael@0 874 string id = FormatIdentifier(identifier);
michael@0 875
michael@0 876 LoadSymbolsInfo<ElfClass> info(debug_dirs);
michael@0 877 scoped_ptr<Module> module(new Module(name, os, architecture, id));
michael@0 878 if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
michael@0 879 !debug_dirs.empty(), &info,
michael@0 880 symbol_data, module.get())) {
michael@0 881 const string debuglink_file = info.debuglink_file();
michael@0 882 if (debuglink_file.empty())
michael@0 883 return false;
michael@0 884
michael@0 885 // Load debuglink ELF file.
michael@0 886 fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str());
michael@0 887 MmapWrapper debug_map_wrapper;
michael@0 888 Ehdr* debug_elf_header = NULL;
michael@0 889 if (!LoadELF(debuglink_file, &debug_map_wrapper,
michael@0 890 reinterpret_cast<void**>(&debug_elf_header)))
michael@0 891 return false;
michael@0 892 // Sanity checks to make sure everything matches up.
michael@0 893 const char *debug_architecture =
michael@0 894 ElfArchitecture<ElfClass>(debug_elf_header);
michael@0 895 if (!debug_architecture) {
michael@0 896 fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
michael@0 897 debuglink_file.c_str(), debug_elf_header->e_machine);
michael@0 898 return false;
michael@0 899 }
michael@0 900 if (strcmp(architecture, debug_architecture)) {
michael@0 901 fprintf(stderr, "%s with ELF machine architecture %s does not match "
michael@0 902 "%s with ELF architecture %s\n",
michael@0 903 debuglink_file.c_str(), debug_architecture,
michael@0 904 obj_filename.c_str(), architecture);
michael@0 905 return false;
michael@0 906 }
michael@0 907
michael@0 908 bool debug_big_endian;
michael@0 909 if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
michael@0 910 return false;
michael@0 911 if (debug_big_endian != big_endian) {
michael@0 912 fprintf(stderr, "%s and %s does not match in endianness\n",
michael@0 913 obj_filename.c_str(), debuglink_file.c_str());
michael@0 914 return false;
michael@0 915 }
michael@0 916
michael@0 917 if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
michael@0 918 debug_elf_header, false, &info,
michael@0 919 symbol_data, module.get())) {
michael@0 920 return false;
michael@0 921 }
michael@0 922 }
michael@0 923
michael@0 924 *out_module = module.release();
michael@0 925 return true;
michael@0 926 }
michael@0 927
michael@0 928 } // namespace
michael@0 929
michael@0 930 namespace google_breakpad {
michael@0 931
michael@0 932 // Not explicitly exported, but not static so it can be used in unit tests.
michael@0 933 bool ReadSymbolDataInternal(const uint8_t* obj_file,
michael@0 934 const string& obj_filename,
michael@0 935 const std::vector<string>& debug_dirs,
michael@0 936 SymbolData symbol_data,
michael@0 937 Module** module) {
michael@0 938
michael@0 939 if (!IsValidElf(obj_file)) {
michael@0 940 fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
michael@0 941 return false;
michael@0 942 }
michael@0 943
michael@0 944 int elfclass = ElfClass(obj_file);
michael@0 945 if (elfclass == ELFCLASS32) {
michael@0 946 return ReadSymbolDataElfClass<ElfClass32>(
michael@0 947 reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dirs,
michael@0 948 symbol_data, module);
michael@0 949 }
michael@0 950 if (elfclass == ELFCLASS64) {
michael@0 951 return ReadSymbolDataElfClass<ElfClass64>(
michael@0 952 reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dirs,
michael@0 953 symbol_data, module);
michael@0 954 }
michael@0 955
michael@0 956 return false;
michael@0 957 }
michael@0 958
michael@0 959 bool WriteSymbolFile(const string &obj_file,
michael@0 960 const std::vector<string>& debug_dirs,
michael@0 961 SymbolData symbol_data,
michael@0 962 std::ostream &sym_stream) {
michael@0 963 Module* module;
michael@0 964 if (!ReadSymbolData(obj_file, debug_dirs, symbol_data, &module))
michael@0 965 return false;
michael@0 966
michael@0 967 bool result = module->Write(sym_stream, symbol_data);
michael@0 968 delete module;
michael@0 969 return result;
michael@0 970 }
michael@0 971
michael@0 972 bool ReadSymbolData(const string& obj_file,
michael@0 973 const std::vector<string>& debug_dirs,
michael@0 974 SymbolData symbol_data,
michael@0 975 Module** module) {
michael@0 976 MmapWrapper map_wrapper;
michael@0 977 void* elf_header = NULL;
michael@0 978 if (!LoadELF(obj_file, &map_wrapper, &elf_header))
michael@0 979 return false;
michael@0 980
michael@0 981 return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
michael@0 982 obj_file, debug_dirs, symbol_data, module);
michael@0 983 }
michael@0 984
michael@0 985 } // namespace google_breakpad

mercurial