| OLD | NEW |
| 1 // Copyright (c) 2011 Google Inc. | 1 // Copyright (c) 2011 Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 // dump_symbols.cc: implement google_breakpad::WriteSymbolFile: | 32 // dump_symbols.cc: implement google_breakpad::WriteSymbolFile: |
| 33 // Find all the debugging info in a file and dump it as a Breakpad symbol file. | 33 // Find all the debugging info in a file and dump it as a Breakpad symbol file. |
| 34 | 34 |
| 35 #include "common/linux/dump_symbols.h" | 35 #include "common/linux/dump_symbols.h" |
| 36 | 36 |
| 37 #include <assert.h> | 37 #include <assert.h> |
| 38 #include <elf.h> | 38 #include <elf.h> |
| 39 #include <errno.h> | 39 #include <errno.h> |
| 40 #include <fcntl.h> | 40 #include <fcntl.h> |
| 41 #include <link.h> | 41 #include <link.h> |
| 42 #include <stdint.h> |
| 42 #include <stdio.h> | 43 #include <stdio.h> |
| 43 #include <stdlib.h> | 44 #include <stdlib.h> |
| 44 #include <string.h> | 45 #include <string.h> |
| 45 #include <sys/mman.h> | 46 #include <sys/mman.h> |
| 46 #include <sys/stat.h> | 47 #include <sys/stat.h> |
| 47 #include <unistd.h> | 48 #include <unistd.h> |
| 48 | 49 |
| 49 #include <iostream> | 50 #include <iostream> |
| 50 #include <set> | 51 #include <set> |
| 51 #include <string> | 52 #include <string> |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 // dwarf2reader::LineInfo and populates a Module and a line vector | 214 // dwarf2reader::LineInfo and populates a Module and a line vector |
| 214 // with the results. | 215 // with the results. |
| 215 class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { | 216 class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { |
| 216 public: | 217 public: |
| 217 // Create a line-to-module converter using BYTE_READER. | 218 // Create a line-to-module converter using BYTE_READER. |
| 218 explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader) | 219 explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader) |
| 219 : byte_reader_(byte_reader) { } | 220 : byte_reader_(byte_reader) { } |
| 220 void StartCompilationUnit(const string& compilation_dir) { | 221 void StartCompilationUnit(const string& compilation_dir) { |
| 221 compilation_dir_ = compilation_dir; | 222 compilation_dir_ = compilation_dir; |
| 222 } | 223 } |
| 223 void ReadProgram(const char* program, uint64 length, | 224 void ReadProgram(const uint8_t *program, uint64 length, |
| 224 Module* module, std::vector<Module::Line>* lines) { | 225 Module* module, std::vector<Module::Line>* lines) { |
| 225 DwarfLineToModule handler(module, compilation_dir_, lines); | 226 DwarfLineToModule handler(module, compilation_dir_, lines); |
| 226 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); | 227 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); |
| 227 parser.Start(); | 228 parser.Start(); |
| 228 } | 229 } |
| 229 private: | 230 private: |
| 230 string compilation_dir_; | 231 string compilation_dir_; |
| 231 dwarf2reader::ByteReader *byte_reader_; | 232 dwarf2reader::ByteReader *byte_reader_; |
| 232 }; | 233 }; |
| 233 | 234 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 251 // Build a map of the ELF file's sections. | 252 // Build a map of the ELF file's sections. |
| 252 const Shdr* sections = | 253 const Shdr* sections = |
| 253 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); | 254 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); |
| 254 int num_sections = elf_header->e_shnum; | 255 int num_sections = elf_header->e_shnum; |
| 255 const Shdr* section_names = sections + elf_header->e_shstrndx; | 256 const Shdr* section_names = sections + elf_header->e_shstrndx; |
| 256 for (int i = 0; i < num_sections; i++) { | 257 for (int i = 0; i < num_sections; i++) { |
| 257 const Shdr* section = §ions[i]; | 258 const Shdr* section = §ions[i]; |
| 258 string name = GetOffset<ElfClass, char>(elf_header, | 259 string name = GetOffset<ElfClass, char>(elf_header, |
| 259 section_names->sh_offset) + | 260 section_names->sh_offset) + |
| 260 section->sh_name; | 261 section->sh_name; |
| 261 const char* contents = GetOffset<ElfClass, char>(elf_header, | 262 const uint8_t *contents = GetOffset<ElfClass, uint8_t>(elf_header, |
| 262 section->sh_offset); | 263 section->sh_offset); |
| 263 file_context.AddSectionToSectionMap(name, contents, section->sh_size); | 264 file_context.AddSectionToSectionMap(name, contents, section->sh_size); |
| 264 } | 265 } |
| 265 | 266 |
| 266 // Parse all the compilation units in the .debug_info section. | 267 // Parse all the compilation units in the .debug_info section. |
| 267 DumperLineToModule line_to_module(&byte_reader); | 268 DumperLineToModule line_to_module(&byte_reader); |
| 268 dwarf2reader::SectionMap::const_iterator debug_info_entry = | 269 dwarf2reader::SectionMap::const_iterator debug_info_entry = |
| 269 file_context.section_map().find(".debug_info"); | 270 file_context.section_map().find(".debug_info"); |
| 270 assert(debug_info_entry != file_context.section_map().end()); | 271 assert(debug_info_entry != file_context.section_map().end()); |
| 271 const std::pair<const char*, uint64>& debug_info_section = | 272 const std::pair<const uint8_t *, uint64>& debug_info_section = |
| 272 debug_info_entry->second; | 273 debug_info_entry->second; |
| 273 // This should never have been called if the file doesn't have a | 274 // This should never have been called if the file doesn't have a |
| 274 // .debug_info section. | 275 // .debug_info section. |
| 275 assert(debug_info_section.first); | 276 assert(debug_info_section.first); |
| 276 uint64 debug_info_length = debug_info_section.second; | 277 uint64 debug_info_length = debug_info_section.second; |
| 277 for (uint64 offset = 0; offset < debug_info_length;) { | 278 for (uint64 offset = 0; offset < debug_info_length;) { |
| 278 // Make a handler for the root DIE that populates MODULE with the | 279 // Make a handler for the root DIE that populates MODULE with the |
| 279 // data that was found. | 280 // data that was found. |
| 280 DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); | 281 DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); |
| 281 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter); | 282 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';" | 339 fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';" |
| 339 " cannot convert DWARF call frame information\n", | 340 " cannot convert DWARF call frame information\n", |
| 340 dwarf_filename.c_str(), elf_header->e_machine); | 341 dwarf_filename.c_str(), elf_header->e_machine); |
| 341 return false; | 342 return false; |
| 342 } | 343 } |
| 343 | 344 |
| 344 const dwarf2reader::Endianness endianness = big_endian ? | 345 const dwarf2reader::Endianness endianness = big_endian ? |
| 345 dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; | 346 dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; |
| 346 | 347 |
| 347 // Find the call frame information and its size. | 348 // Find the call frame information and its size. |
| 348 const char* cfi = | 349 const uint8_t *cfi = |
| 349 GetOffset<ElfClass, char>(elf_header, section->sh_offset); | 350 GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset); |
| 350 size_t cfi_size = section->sh_size; | 351 size_t cfi_size = section->sh_size; |
| 351 | 352 |
| 352 // Plug together the parser, handler, and their entourages. | 353 // Plug together the parser, handler, and their entourages. |
| 353 DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name); | 354 DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name); |
| 354 DwarfCFIToModule handler(module, register_names, &module_reporter); | 355 DwarfCFIToModule handler(module, register_names, &module_reporter); |
| 355 dwarf2reader::ByteReader byte_reader(endianness); | 356 dwarf2reader::ByteReader byte_reader(endianness); |
| 356 | 357 |
| 357 byte_reader.SetAddressSize(ElfClass::kAddrSize); | 358 byte_reader.SetAddressSize(ElfClass::kAddrSize); |
| 358 | 359 |
| 359 // Provide the base addresses for .eh_frame encoded pointers, if | 360 // Provide the base addresses for .eh_frame encoded pointers, if |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 // two absolute paths are the same. | 427 // two absolute paths are the same. |
| 427 bool IsSameFile(const char* left_abspath, const string& right_path) { | 428 bool IsSameFile(const char* left_abspath, const string& right_path) { |
| 428 char right_abspath[PATH_MAX]; | 429 char right_abspath[PATH_MAX]; |
| 429 if (!realpath(right_path.c_str(), right_abspath)) | 430 if (!realpath(right_path.c_str(), right_abspath)) |
| 430 return false; | 431 return false; |
| 431 return strcmp(left_abspath, right_abspath) == 0; | 432 return strcmp(left_abspath, right_abspath) == 0; |
| 432 } | 433 } |
| 433 | 434 |
| 434 // Read the .gnu_debuglink and get the debug file name. If anything goes | 435 // Read the .gnu_debuglink and get the debug file name. If anything goes |
| 435 // wrong, return an empty string. | 436 // wrong, return an empty string. |
| 436 string ReadDebugLink(const char* debuglink, | 437 string ReadDebugLink(const uint8_t *debuglink, |
| 437 const size_t debuglink_size, | 438 const size_t debuglink_size, |
| 438 const bool big_endian, | 439 const bool big_endian, |
| 439 const string& obj_file, | 440 const string& obj_file, |
| 440 const std::vector<string>& debug_dirs) { | 441 const std::vector<string>& debug_dirs) { |
| 441 size_t debuglink_len = strlen(debuglink) + 5; // Include '\0' + CRC32. | 442 // Include '\0' + CRC32 (4 bytes). |
| 443 size_t debuglink_len = strlen(reinterpret_cast<const char *>(debuglink)) + 5; |
| 442 debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. | 444 debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. |
| 443 | 445 |
| 444 // Sanity check. | 446 // Sanity check. |
| 445 if (debuglink_len != debuglink_size) { | 447 if (debuglink_len != debuglink_size) { |
| 446 fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " | 448 fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " |
| 447 "%zx %zx\n", debuglink_len, debuglink_size); | 449 "%zx %zx\n", debuglink_len, debuglink_size); |
| 448 return string(); | 450 return string(); |
| 449 } | 451 } |
| 450 | 452 |
| 451 char obj_file_abspath[PATH_MAX]; | 453 char obj_file_abspath[PATH_MAX]; |
| 452 if (!realpath(obj_file.c_str(), obj_file_abspath)) { | 454 if (!realpath(obj_file.c_str(), obj_file_abspath)) { |
| 453 fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str()); | 455 fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str()); |
| 454 return string(); | 456 return string(); |
| 455 } | 457 } |
| 456 | 458 |
| 457 std::vector<string> searched_paths; | 459 std::vector<string> searched_paths; |
| 458 string debuglink_path; | 460 string debuglink_path; |
| 459 std::vector<string>::const_iterator it; | 461 std::vector<string>::const_iterator it; |
| 460 for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { | 462 for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { |
| 461 const string& debug_dir = *it; | 463 const string& debug_dir = *it; |
| 462 debuglink_path = debug_dir + "/" + debuglink; | 464 debuglink_path = debug_dir + "/" + |
| 465 reinterpret_cast<const char *>(debuglink); |
| 463 | 466 |
| 464 // There is the annoying case of /path/to/foo.so having foo.so as the | 467 // There is the annoying case of /path/to/foo.so having foo.so as the |
| 465 // debug link file name. Thus this may end up opening /path/to/foo.so again, | 468 // debug link file name. Thus this may end up opening /path/to/foo.so again, |
| 466 // and there is a small chance of the two files having the same CRC. | 469 // and there is a small chance of the two files having the same CRC. |
| 467 if (IsSameFile(obj_file_abspath, debuglink_path)) | 470 if (IsSameFile(obj_file_abspath, debuglink_path)) |
| 468 continue; | 471 continue; |
| 469 | 472 |
| 470 searched_paths.push_back(debug_dir); | 473 searched_paths.push_back(debug_dir); |
| 471 int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); | 474 int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); |
| 472 if (debuglink_fd < 0) | 475 if (debuglink_fd < 0) |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 obj_file.c_str()); | 765 obj_file.c_str()); |
| 763 | 766 |
| 764 // Failed, but maybe there's a .gnu_debuglink section? | 767 // Failed, but maybe there's a .gnu_debuglink section? |
| 765 if (read_gnu_debug_link) { | 768 if (read_gnu_debug_link) { |
| 766 const Shdr* gnu_debuglink_section | 769 const Shdr* gnu_debuglink_section |
| 767 = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS, | 770 = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS, |
| 768 sections, names, | 771 sections, names, |
| 769 names_end, elf_header->e_shnum); | 772 names_end, elf_header->e_shnum); |
| 770 if (gnu_debuglink_section) { | 773 if (gnu_debuglink_section) { |
| 771 if (!info->debug_dirs().empty()) { | 774 if (!info->debug_dirs().empty()) { |
| 772 const char* debuglink_contents = | 775 const uint8_t *debuglink_contents = |
| 773 GetOffset<ElfClass, char>(elf_header, | 776 GetOffset<ElfClass, uint8_t>(elf_header, |
| 774 gnu_debuglink_section->sh_offset); | 777 gnu_debuglink_section->sh_offset); |
| 775 string debuglink_file = | 778 string debuglink_file = |
| 776 ReadDebugLink(debuglink_contents, | 779 ReadDebugLink(debuglink_contents, |
| 777 gnu_debuglink_section->sh_size, | 780 gnu_debuglink_section->sh_size, |
| 778 big_endian, | 781 big_endian, |
| 779 obj_file, | 782 obj_file, |
| 780 info->debug_dirs()); | 783 info->debug_dirs()); |
| 781 info->set_debuglink_file(debuglink_file); | 784 info->set_debuglink_file(debuglink_file); |
| 782 } else { | 785 } else { |
| 783 fprintf(stderr, ".gnu_debuglink section found in '%s', " | 786 fprintf(stderr, ".gnu_debuglink section found in '%s', " |
| 784 "but no debug path specified.\n", obj_file.c_str()); | 787 "but no debug path specified.\n", obj_file.c_str()); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 MmapWrapper map_wrapper; | 1000 MmapWrapper map_wrapper; |
| 998 void* elf_header = NULL; | 1001 void* elf_header = NULL; |
| 999 if (!LoadELF(obj_file, &map_wrapper, &elf_header)) | 1002 if (!LoadELF(obj_file, &map_wrapper, &elf_header)) |
| 1000 return false; | 1003 return false; |
| 1001 | 1004 |
| 1002 return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header), | 1005 return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header), |
| 1003 obj_file, debug_dirs, options, module); | 1006 obj_file, debug_dirs, options, module); |
| 1004 } | 1007 } |
| 1005 | 1008 |
| 1006 } // namespace google_breakpad | 1009 } // namespace google_breakpad |
| OLD | NEW |