Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: obsolete/breakpad/common/linux/dump_symbols.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <elf.h>
36 #include <fcntl.h>
37 //#include <link.h>
38 //#include <sys/mman.h>
39 #include <sys/stat.h>
40 //#include <unistd.h>
41
42 #include <cassert>
43 #include <cerrno>
44 #include <cstdio>
45 #include <cstdlib>
46 #include <cstring>
47 #include <string>
48
49 #include "common/dwarf/bytereader-inl.h"
50 #include "common/dwarf/dwarf2diehandler.h"
51 #include "common/dump_stabs.h"
52 #include "common/linux/dump_symbols.h"
53 #include "common/dwarf_cfi_to_module.h"
54 #include "common/dwarf_cu_to_module.h"
55 #include "common/dwarf_line_to_module.h"
56 #include "common/linux/file_id.h"
57 #include "common/module.h"
58 #include "common/stabs_reader.h"
59
60 // This namespace contains helper functions.
61 namespace {
62
63 using google_breakpad::DumpStabsHandler;
64 using google_breakpad::DwarfCFIToModule;
65 using google_breakpad::DwarfCUToModule;
66 using google_breakpad::DwarfLineToModule;
67 using google_breakpad::Module;
68
69 // Fix offset into virtual address by adding the mapped base into offsets.
70 // Make life easier when want to find something by offset.
71 static void FixAddress(void *obj_base) {
72 ElfW(Addr) base = reinterpret_cast<ElfW(Addr)>(obj_base);
73 ElfW(Ehdr) *elf_header = static_cast<ElfW(Ehdr) *>(obj_base);
74 elf_header->e_phoff += base;
75 elf_header->e_shoff += base;
76 ElfW(Shdr) *sections = reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
77 for (int i = 0; i < elf_header->e_shnum; ++i)
78 sections[i].sh_offset += base;
79 }
80
81 // Find the prefered loading address of the binary.
82 static ElfW(Addr) GetLoadingAddress(const ElfW(Phdr) *program_headers,
83 int nheader) {
84 for (int i = 0; i < nheader; ++i) {
85 const ElfW(Phdr) &header = program_headers[i];
86 // For executable, it is the PT_LOAD segment with offset to zero.
87 if (header.p_type == PT_LOAD &&
88 header.p_offset == 0)
89 return header.p_vaddr;
90 }
91 // For other types of ELF, return 0.
92 return 0;
93 }
94
95 static bool IsValidElf(const ElfW(Ehdr) *elf_header) {
96 return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
97 }
98
99 static const ElfW(Shdr) *FindSectionByName(const char *name,
100 const ElfW(Shdr) *sections,
101 const ElfW(Shdr) *section_names,
102 int nsection) {
103 assert(name != NULL);
104 assert(sections != NULL);
105 assert(nsection > 0);
106
107 int name_len = strlen(name);
108 if (name_len == 0)
109 return NULL;
110
111 // Find the end of the section name section, to make sure that
112 // comparisons don't run off the end of the section.
113 const char *names_end =
114 reinterpret_cast<char*>(section_names->sh_offset + section_names->sh_size);
115
116 for (int i = 0; i < nsection; ++i) {
117 const char *section_name =
118 reinterpret_cast<char*>(section_names->sh_offset + sections[i].sh_name);
119 if (names_end - section_name >= name_len + 1 &&
120 strcmp(name, section_name) == 0)
121 return sections + i;
122 }
123 return NULL;
124 }
125
126 static bool LoadStabs(const ElfW(Shdr) *stab_section,
127 const ElfW(Shdr) *stabstr_section,
128 Module *module) {
129 // A callback object to handle data from the STABS reader.
130 DumpStabsHandler handler(module);
131 // Find the addresses of the STABS data, and create a STABS reader object.
132 uint8_t *stabs = reinterpret_cast<uint8_t *>(stab_section->sh_offset);
133 uint8_t *stabstr = reinterpret_cast<uint8_t *>(stabstr_section->sh_offset);
134 google_breakpad::StabsReader reader(stabs, stab_section->sh_size,
135 stabstr, stabstr_section->sh_size,
136 &handler);
137 // Read the STABS data, and do post-processing.
138 if (!reader.Process())
139 return false;
140 handler.Finalize();
141 return true;
142 }
143
144 // A line-to-module loader that accepts line number info parsed by
145 // dwarf2reader::LineInfo and populates a Module and a line vector
146 // with the results.
147 class DumperLineToModule: public DwarfCUToModule::LineToModuleFunctor {
148 public:
149 // Create a line-to-module converter using BYTE_READER.
150 DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
151 : byte_reader_(byte_reader) { }
152 void operator()(const char *program, uint64 length,
153 Module *module, vector<Module::Line> *lines) {
154 DwarfLineToModule handler(module, lines);
155 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
156 parser.Start();
157 }
158 private:
159 dwarf2reader::ByteReader *byte_reader_;
160 };
161
162 static bool LoadDwarf(const string &dwarf_filename,
163 const ElfW(Ehdr) *elf_header,
164 Module *module) {
165 // Figure out what endianness this file is.
166 dwarf2reader::Endianness endianness;
167 if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB)
168 endianness = dwarf2reader::ENDIANNESS_LITTLE;
169 else if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB)
170 endianness = dwarf2reader::ENDIANNESS_BIG;
171 else {
172 fprintf(stderr, "%s: bad data encoding in ELF header: %d\n",
173 dwarf_filename.c_str(), elf_header->e_ident[EI_DATA]);
174 return false;
175 }
176 dwarf2reader::ByteReader byte_reader(endianness);
177
178 // Construct a context for this file.
179 DwarfCUToModule::FileContext file_context(dwarf_filename, module);
180
181 // Build a map of the ELF file's sections.
182 const ElfW(Shdr) *sections
183 = reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
184 int num_sections = elf_header->e_shnum;
185 const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
186 for (int i = 0; i < num_sections; i++) {
187 const ElfW(Shdr) *section = &sections[i];
188 string name = reinterpret_cast<const char *>(section_names->sh_offset
189 + section->sh_name);
190 const char *contents = reinterpret_cast<const char *>(section->sh_offset);
191 uint64 length = section->sh_size;
192 file_context.section_map[name] = std::make_pair(contents, length);
193 }
194
195 // Parse all the compilation units in the .debug_info section.
196 DumperLineToModule line_to_module(&byte_reader);
197 std::pair<const char *, uint64> debug_info_section
198 = file_context.section_map[".debug_info"];
199 // We should never have been called if the file doesn't have a
200 // .debug_info section.
201 assert(debug_info_section.first);
202 uint64 debug_info_length = debug_info_section.second;
203 for (uint64 offset = 0; offset < debug_info_length;) {
204 // Make a handler for the root DIE that populates MODULE with the
205 // data we find.
206 DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
207 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
208 // Make a Dwarf2Handler that drives our DIEHandler.
209 dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
210 // Make a DWARF parser for the compilation unit at OFFSET.
211 dwarf2reader::CompilationUnit reader(file_context.section_map,
212 offset,
213 &byte_reader,
214 &die_dispatcher);
215 // Process the entire compilation unit; get the offset of the next.
216 offset += reader.Start();
217 }
218 return true;
219 }
220
221 // Fill REGISTER_NAMES with the register names appropriate to the
222 // machine architecture given in HEADER, indexed by the register
223 // numbers used in DWARF call frame information. Return true on
224 // success, or false if we don't recognize HEADER's machine
225 // architecture.
226 static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
227 vector<string> *register_names)
228 {
229 static const char *const i386_names[] = {
230 "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
231 "$eip", "$eflags", "$unused1",
232 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
233 "$unused2", "$unused3",
234 "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
235 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
236 "$fcw", "$fsw", "$mxcsr",
237 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
238 "$tr", "$ldtr",
239 NULL
240 };
241
242 static const char *const x86_64_names[] = {
243 "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
244 "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
245 "$rip",
246 "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
247 "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
248 "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
249 "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
250 "$rflags",
251 "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
252 "$fs.base", "$gs.base", "$unused3", "$unused4",
253 "$tr", "$ldtr",
254 "$mxcsr", "$fcw", "$fsw",
255 NULL
256 };
257
258 static const char *const arm_names[] = {
259 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
260 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
261 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
262 "fps", "cpsr",
263 NULL
264 };
265
266 const char * const *name_table;
267 switch (elf_header->e_machine) {
268 case EM_386: name_table = i386_names; break;
269 case EM_ARM: name_table = arm_names; break;
270 case EM_X86_64: name_table = x86_64_names; break;
271 default:
272 return false;
273 }
274
275 register_names->clear();
276 for (int i = 0; name_table[i]; i++)
277 register_names->push_back(name_table[i]);
278 return true;
279 }
280
281 static bool LoadDwarfCFI(const string &dwarf_filename,
282 const ElfW(Ehdr) *elf_header,
283 const char *section_name,
284 const ElfW(Shdr) *section,
285 bool eh_frame,
286 const ElfW(Shdr) *got_section,
287 const ElfW(Shdr) *text_section,
288 Module *module) {
289 // Find the appropriate set of register names for this file's
290 // architecture.
291 vector<string> register_names;
292 if (!DwarfCFIRegisterNames(elf_header, &register_names)) {
293 fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
294 " cannot convert DWARF call frame information\n",
295 dwarf_filename.c_str(), elf_header->e_machine);
296 return false;
297 }
298
299 // Figure out what endianness this file is.
300 dwarf2reader::Endianness endianness;
301 if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB)
302 endianness = dwarf2reader::ENDIANNESS_LITTLE;
303 else if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB)
304 endianness = dwarf2reader::ENDIANNESS_BIG;
305 else {
306 fprintf(stderr, "%s: bad data encoding in ELF header: %d\n",
307 dwarf_filename.c_str(), elf_header->e_ident[EI_DATA]);
308 return false;
309 }
310
311 // Find the call frame information and its size.
312 const char *cfi = reinterpret_cast<const char *>(section->sh_offset);
313 size_t cfi_size = section->sh_size;
314
315 // Plug together the parser, handler, and their entourages.
316 DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
317 DwarfCFIToModule handler(module, register_names, &module_reporter);
318 dwarf2reader::ByteReader byte_reader(endianness);
319 // Since we're using the ElfW macro, we're not actually capable of
320 // processing both ELF32 and ELF64 files with the same program; that
321 // would take a bit more work. But this will work out well enough.
322 if (elf_header->e_ident[EI_CLASS] == ELFCLASS32)
323 byte_reader.SetAddressSize(4);
324 else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64)
325 byte_reader.SetAddressSize(8);
326 else {
327 fprintf(stderr, "%s: bad file class in ELF header: %d\n",
328 dwarf_filename.c_str(), elf_header->e_ident[EI_CLASS]);
329 return false;
330 }
331 // Provide the base addresses for .eh_frame encoded pointers, if
332 // possible.
333 byte_reader.SetCFIDataBase(section->sh_addr, cfi);
334 if (got_section)
335 byte_reader.SetDataBase(got_section->sh_addr);
336 if (text_section)
337 byte_reader.SetTextBase(text_section->sh_addr);
338
339 dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
340 section_name);
341 dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
342 &byte_reader, &handler, &dwarf_reporter,
343 eh_frame);
344 parser.Start();
345 return true;
346 }
347
348 static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
349 Module *module) {
350 // Translate all offsets in section headers into address.
351 FixAddress(elf_header);
352 ElfW(Addr) loading_addr = GetLoadingAddress(
353 reinterpret_cast<ElfW(Phdr) *>(elf_header->e_phoff),
354 elf_header->e_phnum);
355 module->SetLoadAddress(loading_addr);
356
357 const ElfW(Shdr) *sections =
358 reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
359 const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
360 bool found_debug_info_section = false;
361
362 // Look for STABS debugging information, and load it if present.
363 const ElfW(Shdr) *stab_section
364 = FindSectionByName(".stab", sections, section_names,
365 elf_header->e_shnum);
366 if (stab_section) {
367 const ElfW(Shdr) *stabstr_section = stab_section->sh_link + sections;
368 if (stabstr_section) {
369 found_debug_info_section = true;
370 if (!LoadStabs(stab_section, stabstr_section, module))
371 fprintf(stderr, "%s: \".stab\" section found, but failed to load STABS"
372 " debugging information\n", obj_file.c_str());
373 }
374 }
375
376 // Look for DWARF debugging information, and load it if present.
377 const ElfW(Shdr) *dwarf_section
378 = FindSectionByName(".debug_info", sections, section_names,
379 elf_header->e_shnum);
380 if (dwarf_section) {
381 found_debug_info_section = true;
382 if (!LoadDwarf(obj_file, elf_header, module))
383 fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
384 "DWARF debugging information\n", obj_file.c_str());
385 }
386
387 // Dwarf Call Frame Information (CFI) is actually independent from
388 // the other DWARF debugging information, and can be used alone.
389 const ElfW(Shdr) *dwarf_cfi_section =
390 FindSectionByName(".debug_frame", sections, section_names,
391 elf_header->e_shnum);
392 if (dwarf_cfi_section) {
393 // Ignore the return value of this function; even without call frame
394 // information, the other debugging information could be perfectly
395 // useful.
396 LoadDwarfCFI(obj_file, elf_header, ".debug_frame",
397 dwarf_cfi_section, false, 0, 0, module);
398 }
399
400 // Linux C++ exception handling information can also provide
401 // unwinding data.
402 const ElfW(Shdr) *eh_frame_section =
403 FindSectionByName(".eh_frame", sections, section_names,
404 elf_header->e_shnum);
405 if (eh_frame_section) {
406 // Pointers in .eh_frame data may be relative to the base addresses of
407 // certain sections. Provide those sections if present.
408 const ElfW(Shdr) *got_section =
409 FindSectionByName(".got", sections, section_names, elf_header->e_shnum);
410 const ElfW(Shdr) *text_section =
411 FindSectionByName(".text", sections, section_names,
412 elf_header->e_shnum);
413 // As above, ignore the return value of this function.
414 LoadDwarfCFI(obj_file, elf_header, ".eh_frame",
415 eh_frame_section, true, got_section, text_section, module);
416 }
417
418 if (!found_debug_info_section) {
419 fprintf(stderr, "%s: file contains no debugging information"
420 " (no \".stab\" or \".debug_info\" sections)\n",
421 obj_file.c_str());
422 return false;
423 }
424 return true;
425 }
426
427 //
428 // FDWrapper
429 //
430 // Wrapper class to make sure opened file is closed.
431 //
432 class FDWrapper {
433 public:
434 explicit FDWrapper(int fd) :
435 fd_(fd) {
436 }
437 ~FDWrapper() {
438 if (fd_ != -1)
439 close(fd_);
440 }
441 int get() {
442 return fd_;
443 }
444 int release() {
445 int fd = fd_;
446 fd_ = -1;
447 return fd;
448 }
449 private:
450 int fd_;
451 };
452
453 //
454 // MmapWrapper
455 //
456 // Wrapper class to make sure mapped regions are unmapped.
457 //
458 class MmapWrapper {
459 public:
460 MmapWrapper(void *mapped_address, size_t mapped_size) :
461 base_(mapped_address), size_(mapped_size) {
462 }
463 ~MmapWrapper() {
464 if (base_ != NULL) {
465 assert(size_ > 0);
466 munmap(base_, size_);
467 }
468 }
469 void release() {
470 base_ = NULL;
471 size_ = 0;
472 }
473
474 private:
475 void *base_;
476 size_t size_;
477 };
478
479 // Return the breakpad symbol file identifier for the architecture of
480 // ELF_HEADER.
481 const char *ElfArchitecture(const ElfW(Ehdr) *elf_header) {
482 ElfW(Half) arch = elf_header->e_machine;
483 switch (arch) {
484 case EM_386: return "x86";
485 case EM_ARM: return "arm";
486 case EM_MIPS: return "mips";
487 case EM_PPC64: return "ppc64";
488 case EM_PPC: return "ppc";
489 case EM_S390: return "s390";
490 case EM_SPARC: return "sparc";
491 case EM_SPARCV9: return "sparcv9";
492 case EM_X86_64: return "x86_64";
493 default: return NULL;
494 }
495 }
496
497 // Format the Elf file identifier in IDENTIFIER as a UUID with the
498 // dashes removed.
499 std::string FormatIdentifier(unsigned char identifier[16]) {
500 char identifier_str[40];
501 google_breakpad::FileID::ConvertIdentifierToString(
502 identifier,
503 identifier_str,
504 sizeof(identifier_str));
505 std::string id_no_dash;
506 for (int i = 0; identifier_str[i] != '\0'; ++i)
507 if (identifier_str[i] != '-')
508 id_no_dash += identifier_str[i];
509 // Add an extra "0" by the end. PDB files on Windows have an 'age'
510 // number appended to the end of the file identifier; this isn't
511 // really used or necessary on other platforms, but let's preserve
512 // the pattern.
513 id_no_dash += '0';
514 return id_no_dash;
515 }
516
517 // Return the non-directory portion of FILENAME: the portion after the
518 // last slash, or the whole filename if there are no slashes.
519 std::string BaseFileName(const std::string &filename) {
520 // Lots of copies! basename's behavior is less than ideal.
521 char *c_filename = strdup(filename.c_str());
522 std::string base = basename(c_filename);
523 free(c_filename);
524 return base;
525 }
526
527 } // namespace
528
529 namespace google_breakpad {
530
531 bool WriteSymbolFile(const std::string &obj_file, FILE *sym_file) {
532 int obj_fd = open(obj_file.c_str(), O_RDONLY);
533 if (obj_fd < 0) {
534 fprintf(stderr, "Failed to open ELF file '%s': %s\n",
535 obj_file.c_str(), strerror(errno));
536 return false;
537 }
538 FDWrapper obj_fd_wrapper(obj_fd);
539 struct stat st;
540 if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) {
541 fprintf(stderr, "Unable to fstat ELF file '%s': %s\n",
542 obj_file.c_str(), strerror(errno));
543 return false;
544 }
545 void *obj_base = mmap(NULL, st.st_size,
546 PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
547 if (obj_base == MAP_FAILED) {
548 fprintf(stderr, "Failed to mmap ELF file '%s': %s\n",
549 obj_file.c_str(), strerror(errno));
550 return false;
551 }
552 MmapWrapper map_wrapper(obj_base, st.st_size);
553 ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_base);
554 if (!IsValidElf(elf_header)) {
555 fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
556 return false;
557 }
558
559 unsigned char identifier[16];
560 google_breakpad::FileID file_id(obj_file.c_str());
561 if (!file_id.ElfFileIdentifier(identifier)) {
562 fprintf(stderr, "%s: unable to generate file identifier\n",
563 obj_file.c_str());
564 return false;
565 }
566
567 const char *architecture = ElfArchitecture(elf_header);
568 if (!architecture) {
569 fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
570 obj_file.c_str(), elf_header->e_machine);
571 return false;
572 }
573
574 std::string name = BaseFileName(obj_file);
575 std::string os = "Linux";
576 std::string id = FormatIdentifier(identifier);
577
578 Module module(name, os, architecture, id);
579 if (!LoadSymbols(obj_file, elf_header, &module))
580 return false;
581 if (!module.Write(sym_file))
582 return false;
583
584 return true;
585 }
586
587 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « obsolete/breakpad/common/linux/dump_symbols.h ('k') | obsolete/breakpad/common/linux/eintr_wrapper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698