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 |