1 : // Copyright (c) 2010 Google Inc.
2 : // All rights reserved.
3 : //
4 : // Redistribution and use in source and binary forms, with or without
5 : // modification, are permitted provided that the following conditions are
6 : // met:
7 : //
8 : // * Redistributions of source code must retain the above copyright
9 : // notice, this list of conditions and the following disclaimer.
10 : // * Redistributions in binary form must reproduce the above
11 : // copyright notice, this list of conditions and the following disclaimer
12 : // in the documentation and/or other materials provided with the
13 : // distribution.
14 : // * Neither the name of Google Inc. nor the names of its
15 : // contributors may be used to endorse or promote products derived from
16 : // this software without specific prior written permission.
17 : //
18 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 :
30 : // Restructured in 2009 by: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31 :
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.
34 :
35 : #include "common/linux/dump_symbols.h"
36 :
37 : #include <assert.h>
38 : #include <elf.h>
39 : #include <errno.h>
40 : #include <fcntl.h>
41 : #include <link.h>
42 : #include <stdio.h>
43 : #include <stdlib.h>
44 : #include <string.h>
45 : #include <sys/mman.h>
46 : #include <sys/stat.h>
47 : #include <unistd.h>
48 :
49 : #include <set>
50 : #include <string>
51 : #include <utility>
52 : #include <vector>
53 :
54 : #include "common/dwarf/bytereader-inl.h"
55 : #include "common/dwarf/dwarf2diehandler.h"
56 : #include "common/dwarf_cfi_to_module.h"
57 : #include "common/dwarf_cu_to_module.h"
58 : #include "common/dwarf_line_to_module.h"
59 : #include "common/linux/file_id.h"
60 : #include "common/module.h"
61 : #include "common/stabs_reader.h"
62 : #include "common/stabs_to_module.h"
63 :
64 : // This namespace contains helper functions.
65 : namespace {
66 :
67 : using google_breakpad::DwarfCFIToModule;
68 : using google_breakpad::DwarfCUToModule;
69 : using google_breakpad::DwarfLineToModule;
70 : using google_breakpad::Module;
71 : using google_breakpad::StabsToModule;
72 :
73 : //
74 : // FDWrapper
75 : //
76 : // Wrapper class to make sure opened file is closed.
77 : //
78 : class FDWrapper {
79 : public:
80 124 : explicit FDWrapper(int fd) :
81 124 : fd_(fd) {}
82 124 : ~FDWrapper() {
83 124 : if (fd_ != -1)
84 124 : close(fd_);
85 124 : }
86 : int get() {
87 : return fd_;
88 : }
89 : int release() {
90 : int fd = fd_;
91 : fd_ = -1;
92 : return fd;
93 : }
94 : private:
95 : int fd_;
96 : };
97 :
98 : //
99 : // MmapWrapper
100 : //
101 : // Wrapper class to make sure mapped regions are unmapped.
102 : //
103 : class MmapWrapper {
104 : public:
105 124 : MmapWrapper() : is_set_(false) {}
106 124 : ~MmapWrapper() {
107 124 : assert(is_set_);
108 124 : if (base_ != NULL) {
109 124 : assert(size_ > 0);
110 124 : munmap(base_, size_);
111 : }
112 124 : }
113 124 : void set(void *mapped_address, size_t mapped_size) {
114 124 : is_set_ = true;
115 124 : base_ = mapped_address;
116 124 : size_ = mapped_size;
117 124 : }
118 : void release() {
119 : assert(is_set_);
120 : base_ = NULL;
121 : size_ = 0;
122 : }
123 :
124 : private:
125 : bool is_set_;
126 : void *base_;
127 : size_t size_;
128 : };
129 :
130 :
131 : // Fix offset into virtual address by adding the mapped base into offsets.
132 : // Make life easier when want to find something by offset.
133 124 : static void FixAddress(void *obj_base) {
134 124 : ElfW(Addr) base = reinterpret_cast<ElfW(Addr)>(obj_base);
135 124 : ElfW(Ehdr) *elf_header = static_cast<ElfW(Ehdr) *>(obj_base);
136 124 : elf_header->e_phoff += base;
137 124 : elf_header->e_shoff += base;
138 124 : ElfW(Shdr) *sections = reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
139 5103 : for (int i = 0; i < elf_header->e_shnum; ++i)
140 4979 : sections[i].sh_offset += base;
141 124 : }
142 :
143 : // Find the prefered loading address of the binary.
144 124 : static ElfW(Addr) GetLoadingAddress(const ElfW(Phdr) *program_headers,
145 : int nheader) {
146 332 : for (int i = 0; i < nheader; ++i) {
147 332 : const ElfW(Phdr) &header = program_headers[i];
148 : // For executable, it is the PT_LOAD segment with offset to zero.
149 332 : if (header.p_type == PT_LOAD &&
150 : header.p_offset == 0)
151 124 : return header.p_vaddr;
152 : }
153 : // For other types of ELF, return 0.
154 0 : return 0;
155 : }
156 :
157 124 : static bool IsValidElf(const ElfW(Ehdr) *elf_header) {
158 124 : return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
159 : }
160 :
161 744 : static const ElfW(Shdr) *FindSectionByName(const char *name,
162 : const ElfW(Shdr) *sections,
163 : const ElfW(Shdr) *section_names,
164 : int nsection) {
165 744 : assert(name != NULL);
166 744 : assert(sections != NULL);
167 744 : assert(nsection > 0);
168 :
169 744 : int name_len = strlen(name);
170 744 : if (name_len == 0)
171 0 : return NULL;
172 :
173 : // Find the end of the section name section, to make sure that
174 : // comparisons don't run off the end of the section.
175 : const char *names_end =
176 744 : reinterpret_cast<char*>(section_names->sh_offset + section_names->sh_size);
177 :
178 19480 : for (int i = 0; i < nsection; ++i) {
179 : const char *section_name =
180 19356 : reinterpret_cast<char*>(section_names->sh_offset + sections[i].sh_name);
181 38712 : if (names_end - section_name >= name_len + 1 &&
182 19356 : strcmp(name, section_name) == 0) {
183 620 : if (sections[i].sh_type == SHT_NOBITS) {
184 : fprintf(stderr,
185 : "Section %s found, but ignored because type=SHT_NOBITS.\n",
186 0 : name);
187 0 : return NULL;
188 : }
189 620 : return sections + i;
190 : }
191 : }
192 124 : return NULL;
193 : }
194 :
195 0 : static bool LoadStabs(const ElfW(Ehdr) *elf_header,
196 : const ElfW(Shdr) *stab_section,
197 : const ElfW(Shdr) *stabstr_section,
198 : const bool big_endian,
199 : Module *module) {
200 : // A callback object to handle data from the STABS reader.
201 0 : StabsToModule handler(module);
202 : // Find the addresses of the STABS data, and create a STABS reader object.
203 : // On Linux, STABS entries always have 32-bit values, regardless of the
204 : // address size of the architecture whose code they're describing, and
205 : // the strings are always "unitized".
206 0 : uint8_t *stabs = reinterpret_cast<uint8_t *>(stab_section->sh_offset);
207 0 : uint8_t *stabstr = reinterpret_cast<uint8_t *>(stabstr_section->sh_offset);
208 : google_breakpad::StabsReader reader(stabs, stab_section->sh_size,
209 : stabstr, stabstr_section->sh_size,
210 0 : big_endian, 4, true, &handler);
211 : // Read the STABS data, and do post-processing.
212 0 : if (!reader.Process())
213 0 : return false;
214 0 : handler.Finalize();
215 0 : return true;
216 : }
217 :
218 : // A line-to-module loader that accepts line number info parsed by
219 : // dwarf2reader::LineInfo and populates a Module and a line vector
220 : // with the results.
221 124 : class DumperLineToModule: public DwarfCUToModule::LineToModuleFunctor {
222 : public:
223 : // Create a line-to-module converter using BYTE_READER.
224 124 : explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
225 124 : : byte_reader_(byte_reader) { }
226 4723 : void operator()(const char *program, uint64 length,
227 : Module *module, vector<Module::Line> *lines) {
228 9446 : DwarfLineToModule handler(module, lines);
229 9446 : dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
230 4723 : parser.Start();
231 4723 : }
232 : private:
233 : dwarf2reader::ByteReader *byte_reader_;
234 : };
235 :
236 124 : static bool LoadDwarf(const string &dwarf_filename,
237 : const ElfW(Ehdr) *elf_header,
238 : const bool big_endian,
239 : Module *module) {
240 : const dwarf2reader::Endianness endianness = big_endian ?
241 124 : dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
242 248 : dwarf2reader::ByteReader byte_reader(endianness);
243 :
244 : // Construct a context for this file.
245 248 : DwarfCUToModule::FileContext file_context(dwarf_filename, module);
246 :
247 : // Build a map of the ELF file's sections.
248 : const ElfW(Shdr) *sections
249 124 : = reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
250 124 : int num_sections = elf_header->e_shnum;
251 124 : const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
252 5103 : for (int i = 0; i < num_sections; i++) {
253 4979 : const ElfW(Shdr) *section = §ions[i];
254 : string name = reinterpret_cast<const char *>(section_names->sh_offset
255 9958 : + section->sh_name);
256 4979 : const char *contents = reinterpret_cast<const char *>(section->sh_offset);
257 4979 : uint64 length = section->sh_size;
258 4979 : file_context.section_map[name] = std::make_pair(contents, length);
259 : }
260 :
261 : // Parse all the compilation units in the .debug_info section.
262 248 : DumperLineToModule line_to_module(&byte_reader);
263 : std::pair<const char *, uint64> debug_info_section
264 124 : = file_context.section_map[".debug_info"];
265 : // We should never have been called if the file doesn't have a
266 : // .debug_info section.
267 124 : assert(debug_info_section.first);
268 124 : uint64 debug_info_length = debug_info_section.second;
269 5021 : for (uint64 offset = 0; offset < debug_info_length;) {
270 : // Make a handler for the root DIE that populates MODULE with the
271 : // data we find.
272 9546 : DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
273 9546 : DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
274 : // Make a Dwarf2Handler that drives our DIEHandler.
275 9546 : dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
276 : // Make a DWARF parser for the compilation unit at OFFSET.
277 : dwarf2reader::CompilationUnit reader(file_context.section_map,
278 : offset,
279 : &byte_reader,
280 9546 : &die_dispatcher);
281 : // Process the entire compilation unit; get the offset of the next.
282 4773 : offset += reader.Start();
283 : }
284 124 : return true;
285 : }
286 :
287 : // Fill REGISTER_NAMES with the register names appropriate to the
288 : // machine architecture given in HEADER, indexed by the register
289 : // numbers used in DWARF call frame information. Return true on
290 : // success, or false if we don't recognize HEADER's machine
291 : // architecture.
292 248 : static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
293 : vector<string> *register_names) {
294 248 : switch (elf_header->e_machine) {
295 : case EM_386:
296 248 : *register_names = DwarfCFIToModule::RegisterNames::I386();
297 248 : return true;
298 : case EM_ARM:
299 0 : *register_names = DwarfCFIToModule::RegisterNames::ARM();
300 0 : return true;
301 : case EM_X86_64:
302 0 : *register_names = DwarfCFIToModule::RegisterNames::X86_64();
303 0 : return true;
304 : default:
305 0 : return false;
306 : }
307 : }
308 :
309 248 : static bool LoadDwarfCFI(const string &dwarf_filename,
310 : const ElfW(Ehdr) *elf_header,
311 : const char *section_name,
312 : const ElfW(Shdr) *section,
313 : const bool eh_frame,
314 : const ElfW(Shdr) *got_section,
315 : const ElfW(Shdr) *text_section,
316 : const bool big_endian,
317 : Module *module) {
318 : // Find the appropriate set of register names for this file's
319 : // architecture.
320 496 : vector<string> register_names;
321 248 : if (!DwarfCFIRegisterNames(elf_header, ®ister_names)) {
322 : fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
323 : " cannot convert DWARF call frame information\n",
324 0 : dwarf_filename.c_str(), elf_header->e_machine);
325 0 : return false;
326 : }
327 :
328 : const dwarf2reader::Endianness endianness = big_endian ?
329 248 : dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
330 :
331 : // Find the call frame information and its size.
332 248 : const char *cfi = reinterpret_cast<const char *>(section->sh_offset);
333 248 : size_t cfi_size = section->sh_size;
334 :
335 : // Plug together the parser, handler, and their entourages.
336 496 : DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
337 496 : DwarfCFIToModule handler(module, register_names, &module_reporter);
338 496 : dwarf2reader::ByteReader byte_reader(endianness);
339 : // Since we're using the ElfW macro, we're not actually capable of
340 : // processing both ELF32 and ELF64 files with the same program; that
341 : // would take a bit more work. But this will work out well enough.
342 248 : if (elf_header->e_ident[EI_CLASS] == ELFCLASS32)
343 248 : byte_reader.SetAddressSize(4);
344 0 : else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64)
345 0 : byte_reader.SetAddressSize(8);
346 : else {
347 : fprintf(stderr, "%s: bad file class in ELF header: %d\n",
348 0 : dwarf_filename.c_str(), elf_header->e_ident[EI_CLASS]);
349 0 : return false;
350 : }
351 : // Provide the base addresses for .eh_frame encoded pointers, if
352 : // possible.
353 248 : byte_reader.SetCFIDataBase(section->sh_addr, cfi);
354 248 : if (got_section)
355 124 : byte_reader.SetDataBase(got_section->sh_addr);
356 248 : if (text_section)
357 124 : byte_reader.SetTextBase(text_section->sh_addr);
358 :
359 : dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
360 496 : section_name);
361 : dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
362 : &byte_reader, &handler, &dwarf_reporter,
363 496 : eh_frame);
364 248 : parser.Start();
365 248 : return true;
366 : }
367 :
368 124 : bool LoadELF(const std::string &obj_file, MmapWrapper* map_wrapper,
369 : ElfW(Ehdr) **elf_header) {
370 124 : int obj_fd = open(obj_file.c_str(), O_RDONLY);
371 124 : if (obj_fd < 0) {
372 : fprintf(stderr, "Failed to open ELF file '%s': %s\n",
373 0 : obj_file.c_str(), strerror(errno));
374 0 : return false;
375 : }
376 248 : FDWrapper obj_fd_wrapper(obj_fd);
377 : struct stat st;
378 124 : if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) {
379 : fprintf(stderr, "Unable to fstat ELF file '%s': %s\n",
380 0 : obj_file.c_str(), strerror(errno));
381 0 : return false;
382 : }
383 : void *obj_base = mmap(NULL, st.st_size,
384 124 : PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
385 124 : if (obj_base == MAP_FAILED) {
386 : fprintf(stderr, "Failed to mmap ELF file '%s': %s\n",
387 0 : obj_file.c_str(), strerror(errno));
388 0 : return false;
389 : }
390 124 : map_wrapper->set(obj_base, st.st_size);
391 124 : *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_base);
392 124 : if (!IsValidElf(*elf_header)) {
393 0 : fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
394 0 : return false;
395 : }
396 124 : return true;
397 : }
398 :
399 : // Get the endianness of ELF_HEADER. If it's invalid, return false.
400 124 : bool ElfEndianness(const ElfW(Ehdr) *elf_header, bool *big_endian) {
401 124 : if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB) {
402 124 : *big_endian = false;
403 124 : return true;
404 : }
405 0 : if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB) {
406 0 : *big_endian = true;
407 0 : return true;
408 : }
409 :
410 : fprintf(stderr, "bad data encoding in ELF header: %d\n",
411 0 : elf_header->e_ident[EI_DATA]);
412 0 : return false;
413 : }
414 :
415 : // Read the .gnu_debuglink and get the debug file name. If anything goes
416 : // wrong, return an empty string.
417 0 : static std::string ReadDebugLink(const ElfW(Shdr) *debuglink_section,
418 : const std::string &obj_file,
419 : const std::string &debug_dir) {
420 0 : char *debuglink = reinterpret_cast<char *>(debuglink_section->sh_offset);
421 0 : size_t debuglink_len = strlen(debuglink) + 5; // '\0' + CRC32.
422 0 : debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round to nearest 4 bytes.
423 :
424 : // Sanity check.
425 0 : if (debuglink_len != debuglink_section->sh_size) {
426 : fprintf(stderr, "Mismatched .gnu_debuglink string / section size: "
427 0 : "%zx %zx\n", debuglink_len, debuglink_section->sh_size);
428 0 : return "";
429 : }
430 :
431 0 : std::string debuglink_path = debug_dir + "/" + debuglink;
432 0 : int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
433 0 : if (debuglink_fd < 0) {
434 : fprintf(stderr, "Failed to open debug ELF file '%s' for '%s': %s\n",
435 0 : debuglink_path.c_str(), obj_file.c_str(), strerror(errno));
436 0 : return "";
437 : }
438 0 : FDWrapper debuglink_fd_wrapper(debuglink_fd);
439 : // TODO(thestig) check the CRC-32 at the end of the .gnu_debuglink
440 : // section.
441 :
442 0 : return debuglink_path;
443 : }
444 :
445 : //
446 : // LoadSymbolsInfo
447 : //
448 : // Holds the state between the two calls to LoadSymbols() in case we have to
449 : // follow the .gnu_debuglink section and load debug information from a
450 : // different file.
451 : //
452 124 : class LoadSymbolsInfo {
453 : public:
454 124 : explicit LoadSymbolsInfo(const std::string &dbg_dir) :
455 : debug_dir_(dbg_dir),
456 124 : has_loading_addr_(false) {}
457 :
458 : // Keeps track of which sections have been loaded so we don't accidentally
459 : // load it twice from two different files.
460 372 : void LoadedSection(const std::string §ion) {
461 372 : if (loaded_sections_.count(section) == 0) {
462 372 : loaded_sections_.insert(section);
463 : } else {
464 : fprintf(stderr, "Section %s has already been loaded.\n",
465 0 : section.c_str());
466 : }
467 372 : }
468 :
469 : // We expect the ELF file and linked debug file to have the same prefered
470 : // loading address.
471 124 : void set_loading_addr(ElfW(Addr) addr, const std::string &filename) {
472 124 : if (!has_loading_addr_) {
473 124 : loading_addr_ = addr;
474 124 : loaded_file_ = filename;
475 124 : return;
476 : }
477 :
478 0 : if (addr != loading_addr_) {
479 : fprintf(stderr,
480 : "ELF file '%s' and debug ELF file '%s' "
481 : "have different load addresses.\n",
482 0 : loaded_file_.c_str(), filename.c_str());
483 0 : assert(false);
484 : }
485 : }
486 :
487 : // Setters and getters
488 0 : const std::string &debug_dir() const {
489 0 : return debug_dir_;
490 : }
491 :
492 0 : std::string debuglink_file() const {
493 0 : return debuglink_file_;
494 : }
495 0 : void set_debuglink_file(std::string file) {
496 0 : debuglink_file_ = file;
497 0 : }
498 :
499 : private:
500 : const std::string &debug_dir_; // Directory with the debug ELF file.
501 :
502 : std::string debuglink_file_; // Full path to the debug ELF file.
503 :
504 : bool has_loading_addr_; // Indicate if LOADING_ADDR_ is valid.
505 :
506 : ElfW(Addr) loading_addr_; // Saves the prefered loading address from the
507 : // first call to LoadSymbols().
508 :
509 : std::string loaded_file_; // Name of the file loaded from the first call to
510 : // LoadSymbols().
511 :
512 : std::set<std::string> loaded_sections_; // Tracks the Loaded ELF sections
513 : // between calls to LoadSymbols().
514 : };
515 :
516 124 : static bool LoadSymbols(const std::string &obj_file,
517 : const bool big_endian,
518 : ElfW(Ehdr) *elf_header,
519 : const bool read_gnu_debug_link,
520 : LoadSymbolsInfo *info,
521 : Module *module) {
522 : // Translate all offsets in section headers into address.
523 124 : FixAddress(elf_header);
524 : ElfW(Addr) loading_addr = GetLoadingAddress(
525 : reinterpret_cast<ElfW(Phdr) *>(elf_header->e_phoff),
526 124 : elf_header->e_phnum);
527 124 : module->SetLoadAddress(loading_addr);
528 124 : info->set_loading_addr(loading_addr, obj_file);
529 :
530 : const ElfW(Shdr) *sections =
531 124 : reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
532 124 : const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
533 124 : bool found_debug_info_section = false;
534 :
535 : // Look for STABS debugging information, and load it if present.
536 : const ElfW(Shdr) *stab_section
537 : = FindSectionByName(".stab", sections, section_names,
538 124 : elf_header->e_shnum);
539 124 : if (stab_section) {
540 0 : const ElfW(Shdr) *stabstr_section = stab_section->sh_link + sections;
541 0 : if (stabstr_section) {
542 0 : found_debug_info_section = true;
543 0 : info->LoadedSection(".stab");
544 0 : if (!LoadStabs(elf_header, stab_section, stabstr_section, big_endian,
545 0 : module)) {
546 : fprintf(stderr, "%s: \".stab\" section found, but failed to load STABS"
547 0 : " debugging information\n", obj_file.c_str());
548 : }
549 : }
550 : }
551 :
552 : // Look for DWARF debugging information, and load it if present.
553 : const ElfW(Shdr) *dwarf_section
554 : = FindSectionByName(".debug_info", sections, section_names,
555 124 : elf_header->e_shnum);
556 124 : if (dwarf_section) {
557 124 : found_debug_info_section = true;
558 124 : info->LoadedSection(".debug_info");
559 124 : if (!LoadDwarf(obj_file, elf_header, big_endian, module))
560 : fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
561 0 : "DWARF debugging information\n", obj_file.c_str());
562 : }
563 :
564 : // Dwarf Call Frame Information (CFI) is actually independent from
565 : // the other DWARF debugging information, and can be used alone.
566 : const ElfW(Shdr) *dwarf_cfi_section =
567 : FindSectionByName(".debug_frame", sections, section_names,
568 124 : elf_header->e_shnum);
569 124 : if (dwarf_cfi_section) {
570 : // Ignore the return value of this function; even without call frame
571 : // information, the other debugging information could be perfectly
572 : // useful.
573 124 : info->LoadedSection(".debug_frame");
574 : LoadDwarfCFI(obj_file, elf_header, ".debug_frame",
575 124 : dwarf_cfi_section, false, 0, 0, big_endian, module);
576 : }
577 :
578 : // Linux C++ exception handling information can also provide
579 : // unwinding data.
580 : const ElfW(Shdr) *eh_frame_section =
581 : FindSectionByName(".eh_frame", sections, section_names,
582 124 : elf_header->e_shnum);
583 124 : if (eh_frame_section) {
584 : // Pointers in .eh_frame data may be relative to the base addresses of
585 : // certain sections. Provide those sections if present.
586 : const ElfW(Shdr) *got_section =
587 124 : FindSectionByName(".got", sections, section_names, elf_header->e_shnum);
588 : const ElfW(Shdr) *text_section =
589 : FindSectionByName(".text", sections, section_names,
590 124 : elf_header->e_shnum);
591 124 : info->LoadedSection(".eh_frame");
592 : // As above, ignore the return value of this function.
593 : LoadDwarfCFI(obj_file, elf_header, ".eh_frame", eh_frame_section, true,
594 124 : got_section, text_section, big_endian, module);
595 : }
596 :
597 124 : if (!found_debug_info_section) {
598 : fprintf(stderr, "%s: file contains no debugging information"
599 : " (no \".stab\" or \".debug_info\" sections)\n",
600 0 : obj_file.c_str());
601 :
602 : // Failed, but maybe we can find a .gnu_debuglink section?
603 0 : if (read_gnu_debug_link) {
604 : const ElfW(Shdr) *gnu_debuglink_section
605 : = FindSectionByName(".gnu_debuglink", sections, section_names,
606 0 : elf_header->e_shnum);
607 0 : if (gnu_debuglink_section) {
608 0 : if (!info->debug_dir().empty()) {
609 : std::string debuglink_file =
610 0 : ReadDebugLink(gnu_debuglink_section, obj_file, info->debug_dir());
611 0 : info->set_debuglink_file(debuglink_file);
612 : } else {
613 : fprintf(stderr, ".gnu_debuglink section found in '%s', "
614 0 : "but no debug path specified.\n", obj_file.c_str());
615 : }
616 : } else {
617 : fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
618 0 : obj_file.c_str());
619 : }
620 : }
621 0 : return false;
622 : }
623 :
624 124 : return true;
625 : }
626 :
627 : // Return the breakpad symbol file identifier for the architecture of
628 : // ELF_HEADER.
629 124 : const char *ElfArchitecture(const ElfW(Ehdr) *elf_header) {
630 124 : ElfW(Half) arch = elf_header->e_machine;
631 124 : switch (arch) {
632 124 : case EM_386: return "x86";
633 0 : case EM_ARM: return "arm";
634 0 : case EM_MIPS: return "mips";
635 0 : case EM_PPC64: return "ppc64";
636 0 : case EM_PPC: return "ppc";
637 0 : case EM_S390: return "s390";
638 0 : case EM_SPARC: return "sparc";
639 0 : case EM_SPARCV9: return "sparcv9";
640 0 : case EM_X86_64: return "x86_64";
641 0 : default: return NULL;
642 : }
643 : }
644 :
645 : // Format the Elf file identifier in IDENTIFIER as a UUID with the
646 : // dashes removed.
647 124 : std::string FormatIdentifier(unsigned char identifier[16]) {
648 : char identifier_str[40];
649 : google_breakpad::FileID::ConvertIdentifierToString(
650 : identifier,
651 : identifier_str,
652 124 : sizeof(identifier_str));
653 124 : std::string id_no_dash;
654 4588 : for (int i = 0; identifier_str[i] != '\0'; ++i)
655 4464 : if (identifier_str[i] != '-')
656 3968 : id_no_dash += identifier_str[i];
657 : // Add an extra "0" by the end. PDB files on Windows have an 'age'
658 : // number appended to the end of the file identifier; this isn't
659 : // really used or necessary on other platforms, but let's preserve
660 : // the pattern.
661 124 : id_no_dash += '0';
662 : return id_no_dash;
663 : }
664 :
665 : // Return the non-directory portion of FILENAME: the portion after the
666 : // last slash, or the whole filename if there are no slashes.
667 124 : std::string BaseFileName(const std::string &filename) {
668 : // Lots of copies! basename's behavior is less than ideal.
669 124 : char *c_filename = strdup(filename.c_str());
670 124 : std::string base = basename(c_filename);
671 124 : free(c_filename);
672 : return base;
673 : }
674 :
675 : } // namespace
676 :
677 : namespace google_breakpad {
678 :
679 124 : bool WriteSymbolFile(const std::string &obj_file,
680 : const std::string &debug_dir, FILE *sym_file) {
681 248 : MmapWrapper map_wrapper;
682 124 : ElfW(Ehdr) *elf_header = NULL;
683 124 : if (!LoadELF(obj_file, &map_wrapper, &elf_header))
684 0 : return false;
685 :
686 : unsigned char identifier[16];
687 248 : google_breakpad::FileID file_id(obj_file.c_str());
688 124 : if (!file_id.ElfFileIdentifierFromMappedFile(elf_header, identifier)) {
689 : fprintf(stderr, "%s: unable to generate file identifier\n",
690 0 : obj_file.c_str());
691 0 : return false;
692 : }
693 :
694 124 : const char *architecture = ElfArchitecture(elf_header);
695 124 : if (!architecture) {
696 : fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
697 0 : obj_file.c_str(), elf_header->e_machine);
698 0 : return false;
699 : }
700 :
701 : // Figure out what endianness this file is.
702 : bool big_endian;
703 124 : if (!ElfEndianness(elf_header, &big_endian))
704 0 : return false;
705 :
706 248 : std::string name = BaseFileName(obj_file);
707 248 : std::string os = "Linux";
708 248 : std::string id = FormatIdentifier(identifier);
709 :
710 248 : LoadSymbolsInfo info(debug_dir);
711 248 : Module module(name, os, architecture, id);
712 124 : if (!LoadSymbols(obj_file, big_endian, elf_header, true, &info, &module)) {
713 0 : const std::string debuglink_file = info.debuglink_file();
714 0 : if (debuglink_file.empty())
715 0 : return false;
716 :
717 : // Load debuglink ELF file.
718 0 : fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str());
719 0 : MmapWrapper debug_map_wrapper;
720 0 : ElfW(Ehdr) *debug_elf_header = NULL;
721 0 : if (!LoadELF(debuglink_file, &debug_map_wrapper, &debug_elf_header))
722 0 : return false;
723 : // Sanity checks to make sure everything matches up.
724 0 : const char *debug_architecture = ElfArchitecture(debug_elf_header);
725 0 : if (!debug_architecture) {
726 : fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
727 0 : debuglink_file.c_str(), debug_elf_header->e_machine);
728 0 : return false;
729 : }
730 0 : if (strcmp(architecture, debug_architecture)) {
731 : fprintf(stderr, "%s with ELF machine architecture %s does not match "
732 : "%s with ELF architecture %s\n",
733 : debuglink_file.c_str(), debug_architecture,
734 0 : obj_file.c_str(), architecture);
735 0 : return false;
736 : }
737 :
738 : bool debug_big_endian;
739 0 : if (!ElfEndianness(debug_elf_header, &debug_big_endian))
740 0 : return false;
741 0 : if (debug_big_endian != big_endian) {
742 : fprintf(stderr, "%s and %s does not match in endianness\n",
743 0 : obj_file.c_str(), debuglink_file.c_str());
744 0 : return false;
745 : }
746 :
747 0 : if (!LoadSymbols(debuglink_file, debug_big_endian, debug_elf_header,
748 0 : false, &info, &module)) {
749 0 : return false;
750 : }
751 : }
752 124 : if (!module.Write(sym_file))
753 0 : return false;
754 :
755 124 : return true;
756 : }
757 :
758 : } // namespace google_breakpad
|