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

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

Issue 113893: Fork breakpad's dump_syms and related code. Generate XOR of first page of mem... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix nits, code style changes Created 11 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « breakpad/linux/dump_symbols.h ('k') | breakpad/linux/dump_syms.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006, 2009, 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 #include "breakpad/linux/dump_symbols.h"
31
32 #include <a.out.h>
33 #include <assert.h>
34 #include <cxxabi.h>
35 #include <elf.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <link.h>
39 #include <stab.h>
40 #include <string.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45
46 #include <algorithm>
47 #include <cstdarg>
48 #include <cstdio>
49 #include <cstdlib>
50 #include <functional>
51 #include <list>
52 #include <vector>
53
54 #include "breakpad/linux/file_id.h"
55 #include "common/linux/guid_creator.h"
56
57 // This namespace contains helper functions.
58 namespace {
59
60 // Infomation of a line.
61 struct LineInfo {
62 // The index into string table for the name of the source file which
63 // this line belongs to.
64 // Load from stab symbol.
65 uint32_t source_name_index;
66 // Offset from start of the function.
67 // Load from stab symbol.
68 ElfW(Off) rva_to_func;
69 // Offset from base of the loading binary.
70 ElfW(Off) rva_to_base;
71 // Size of the line.
72 // It is the difference of the starting address of the line and starting
73 // address of the next N_SLINE, N_FUN or N_SO.
74 uint32_t size;
75 // Line number.
76 uint32_t line_num;
77 // Id of the source file for this line.
78 int source_id;
79 };
80
81 typedef std::list<struct LineInfo> LineInfoList;
82
83 // Information of a function.
84 struct FuncInfo {
85 // Name of the function.
86 const char* name;
87 // Offset from the base of the loading address.
88 ElfW(Off) rva_to_base;
89 // Virtual address of the function.
90 // Load from stab symbol.
91 ElfW(Addr) addr;
92 // Size of the function.
93 // It is the difference of the starting address of the function and starting
94 // address of the next N_FUN or N_SO.
95 uint32_t size;
96 // Total size of stack parameters.
97 uint32_t stack_param_size;
98 // Is there any lines included from other files?
99 bool has_sol;
100 // Line information array.
101 LineInfoList line_info;
102 };
103
104 typedef std::list<struct FuncInfo> FuncInfoList;
105
106 // Information of a source file.
107 struct SourceFileInfo {
108 // Name string index into the string table.
109 uint32_t name_index;
110 // Name of the source file.
111 const char* name;
112 // Starting address of the source file.
113 ElfW(Addr) addr;
114 // Id of the source file.
115 int source_id;
116 // Functions information.
117 FuncInfoList func_info;
118 };
119
120 typedef std::list<struct SourceFileInfo> SourceFileInfoList;
121
122 // Information of a symbol table.
123 // This is the root of all types of symbol.
124 struct SymbolInfo {
125 SourceFileInfoList source_file_info;
126
127 // The next source id for newly found source file.
128 int next_source_id;
129 };
130
131 // Stab section name.
132 static const char* kStabName = ".stab";
133
134 // Demangle using abi call.
135 // Older GCC may not support it.
136 static std::string Demangle(const char* mangled) {
137 int status = 0;
138 char* demangled = abi::__cxa_demangle(mangled, NULL, NULL, &status);
139 if (status == 0 && demangled != NULL) {
140 std::string str(demangled);
141 free(demangled);
142 return str;
143 }
144 return std::string(mangled);
145 }
146
147 // Fix offset into virtual address by adding the mapped base into offsets.
148 // Make life easier when want to find something by offset.
149 static void FixAddress(void* obj_base) {
150 ElfW(Word) base = reinterpret_cast<ElfW(Word)>(obj_base);
151 ElfW(Ehdr)* elf_header = static_cast<ElfW(Ehdr)* >(obj_base);
152 elf_header->e_phoff += base;
153 elf_header->e_shoff += base;
154 ElfW(Shdr)* sections = reinterpret_cast<ElfW(Shdr)* >(elf_header->e_shoff);
155 for (int i = 0; i < elf_header->e_shnum; ++i)
156 sections[i].sh_offset += base;
157 }
158
159 // Find the prefered loading address of the binary.
160 static ElfW(Addr) GetLoadingAddress(const ElfW(Phdr)* program_headers,
161 int nheader) {
162 for (int i = 0; i < nheader; ++i) {
163 const ElfW(Phdr)& header = program_headers[i];
164 // For executable, it is the PT_LOAD segment with offset to zero.
165 if (header.p_type == PT_LOAD &&
166 header.p_offset == 0)
167 return header.p_vaddr;
168 }
169 // For other types of ELF, return 0.
170 return 0;
171 }
172
173 static bool WriteFormat(int fd, const char* fmt, ...) {
174 va_list list;
175 char buffer[4096];
176 ssize_t expected, written;
177 va_start(list, fmt);
178 vsnprintf(buffer, sizeof(buffer), fmt, list);
179 expected = strlen(buffer);
180 written = write(fd, buffer, strlen(buffer));
181 va_end(list);
182 return expected == written;
183 }
184
185 static bool IsValidElf(const ElfW(Ehdr)* elf_header) {
186 return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
187 }
188
189 static const ElfW(Shdr)* FindSectionByName(const char* name,
190 const ElfW(Shdr)* sections,
191 const ElfW(Shdr)* strtab,
192 int nsection) {
193 assert(name != NULL);
194 assert(sections != NULL);
195 assert(nsection > 0);
196
197 int name_len = strlen(name);
198 if (name_len == 0)
199 return NULL;
200
201 for (int i = 0; i < nsection; ++i) {
202 const char* section_name =
203 reinterpret_cast<char*>(strtab->sh_offset + sections[i].sh_name);
204 if (!strncmp(name, section_name, name_len))
205 return sections + i;
206 }
207 return NULL;
208 }
209
210 // TODO(liuli): Computer the stack parameter size.
211 // Expect parameter variables are immediately following the N_FUN symbol.
212 // Will need to parse the type information to get a correct size.
213 static int LoadStackParamSize(struct nlist* list,
214 struct nlist* list_end,
215 struct FuncInfo* func_info) {
216 struct nlist* cur_list = list;
217 assert(cur_list->n_type == N_FUN);
218 ++cur_list;
219 int step = 1;
220 while (cur_list < list_end && cur_list->n_type == N_PSYM) {
221 ++cur_list;
222 ++step;
223 }
224 func_info->stack_param_size = 0;
225 return step;
226 }
227
228 static int LoadLineInfo(struct nlist* list,
229 struct nlist* list_end,
230 const struct SourceFileInfo& source_file_info,
231 struct FuncInfo* func_info) {
232 struct nlist* cur_list = list;
233 func_info->has_sol = false;
234 // Records which source file the following lines belongs. Default
235 // to the file we are handling. This helps us handling inlined source.
236 // When encountering N_SOL, we will change this to the source file
237 // specified by N_SOL.
238 int current_source_name_index = source_file_info.name_index;
239 do {
240 // Skip non line information.
241 while (cur_list < list_end && cur_list->n_type != N_SLINE) {
242 // Only exit when got another function, or source file.
243 if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO)
244 return cur_list - list;
245 // N_SOL means source lines following it will be from
246 // another source file.
247 if (cur_list->n_type == N_SOL) {
248 func_info->has_sol = true;
249
250 if (cur_list->n_un.n_strx > 0 &&
251 cur_list->n_un.n_strx != current_source_name_index) {
252 // The following lines will be from this source file.
253 current_source_name_index = cur_list->n_un.n_strx;
254 }
255 }
256 ++cur_list;
257 }
258 struct LineInfo line;
259 while (cur_list < list_end && cur_list->n_type == N_SLINE) {
260 line.source_name_index = current_source_name_index;
261 line.rva_to_func = cur_list->n_value;
262 // n_desc is a signed short
263 line.line_num = (unsigned short)cur_list->n_desc;
264 // Don't set it here.
265 // Will be processed in later pass.
266 line.source_id = -1;
267 func_info->line_info.push_back(line);
268 ++cur_list;
269 }
270 } while (list < list_end);
271
272 return cur_list - list;
273 }
274
275 static int LoadFuncSymbols(struct nlist* list,
276 struct nlist* list_end,
277 const ElfW(Shdr)* stabstr_section,
278 struct SourceFileInfo* source_file_info) {
279 struct nlist* cur_list = list;
280 assert(cur_list->n_type == N_SO);
281 ++cur_list;
282 source_file_info->func_info.clear();
283 while (cur_list < list_end) {
284 // Go until the function symbol.
285 while (cur_list < list_end && cur_list->n_type != N_FUN) {
286 if (cur_list->n_type == N_SO) {
287 return cur_list - list;
288 }
289 ++cur_list;
290 continue;
291 }
292 if (cur_list->n_type == N_FUN) {
293 struct FuncInfo func_info;
294 func_info.name =
295 reinterpret_cast<char* >(cur_list->n_un.n_strx +
296 stabstr_section->sh_offset);
297 func_info.addr = cur_list->n_value;
298 func_info.rva_to_base = 0;
299 func_info.size = 0;
300 func_info.stack_param_size = 0;
301 func_info.has_sol = 0;
302
303 // Stack parameter size.
304 cur_list += LoadStackParamSize(cur_list, list_end, &func_info);
305 // Line info.
306 cur_list += LoadLineInfo(cur_list,
307 list_end,
308 *source_file_info,
309 &func_info);
310
311 // Functions in this module should have address bigger than the module
312 // startring address.
313 // There maybe a lot of duplicated entry for a function in the symbol,
314 // only one of them can met this.
315 if (func_info.addr >= source_file_info->addr) {
316 source_file_info->func_info.push_back(func_info);
317 }
318 }
319 }
320 return cur_list - list;
321 }
322
323 // Comapre the address.
324 // The argument should have a memeber named "addr"
325 template<class T1, class T2>
326 static bool CompareAddress(T1* a, T2* b) {
327 return a->addr < b->addr;
328 }
329
330 // Sort the array into increasing ordered array based on the virtual address.
331 // Return vector of pointers to the elements in the incoming array. So caller
332 // should make sure the returned vector lives longer than the incoming vector.
333 template<class Container>
334 static std::vector<typename Container::value_type* > SortByAddress(
335 Container* container) {
336 typedef typename Container::iterator It;
337 typedef typename Container::value_type T;
338 std::vector<T* > sorted_array_ptr;
339 sorted_array_ptr.reserve(container->size());
340 for (It it = container->begin(); it != container->end(); it++)
341 sorted_array_ptr.push_back(&(*it));
342 std::sort(sorted_array_ptr.begin(),
343 sorted_array_ptr.end(),
344 std::ptr_fun(CompareAddress<T, T>));
345
346 return sorted_array_ptr;
347 }
348
349 // Find the address of the next function or source file symbol in the symbol
350 // table. The address should be bigger than the current function's address.
351 static ElfW(Addr) NextAddress(
352 std::vector<struct FuncInfo* >* sorted_functions,
353 std::vector<struct SourceFileInfo* >* sorted_files,
354 const struct FuncInfo& func_info) {
355 std::vector<struct FuncInfo* >::iterator next_func_iter =
356 std::find_if(sorted_functions->begin(),
357 sorted_functions->end(),
358 std::bind1st(
359 std::ptr_fun(
360 CompareAddress<struct FuncInfo,
361 struct FuncInfo>),
362 &func_info));
363 if (next_func_iter != sorted_functions->end())
364 return (*next_func_iter)->addr;
365
366 std::vector<struct SourceFileInfo* >::iterator next_file_iter =
367 std::find_if(sorted_files->begin(),
368 sorted_files->end(),
369 std::bind1st(
370 std::ptr_fun(
371 CompareAddress<struct FuncInfo,
372 struct SourceFileInfo>),
373 &func_info));
374 if (next_file_iter != sorted_files->end()) {
375 return (*next_file_iter)->addr;
376 }
377 return 0;
378 }
379
380 static int FindFileByNameIdx(uint32_t name_index,
381 SourceFileInfoList& files) {
382 for (SourceFileInfoList::iterator it = files.begin();
383 it != files.end(); it++) {
384 if (it->name_index == name_index)
385 return it->source_id;
386 }
387
388 return -1;
389 }
390
391 // Add included file information.
392 // Also fix the source id for the line info.
393 static void AddIncludedFiles(struct SymbolInfo* symbols,
394 const ElfW(Shdr)* stabstr_section) {
395 for (SourceFileInfoList::iterator source_file_it =
396 symbols->source_file_info.begin();
397 source_file_it != symbols->source_file_info.end();
398 ++source_file_it) {
399 struct SourceFileInfo& source_file = *source_file_it;
400
401 for (FuncInfoList::iterator func_info_it = source_file.func_info.begin();
402 func_info_it != source_file.func_info.end();
403 ++func_info_it) {
404 struct FuncInfo& func_info = *func_info_it;
405
406 for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
407 line_info_it != func_info.line_info.end(); ++line_info_it) {
408 struct LineInfo& line_info = *line_info_it;
409
410 assert(line_info.source_name_index > 0);
411 assert(source_file.name_index > 0);
412
413 // Check if the line belongs to the source file by comparing the
414 // name index into string table.
415 if (line_info.source_name_index != source_file.name_index) {
416 // This line is not from the current source file, check if this
417 // source file has been added before.
418 int found_source_id = FindFileByNameIdx(line_info.source_name_index,
419 symbols->source_file_info);
420 if (found_source_id < 0) {
421 // Got a new included file.
422 // Those included files don't have address or line information.
423 SourceFileInfo new_file;
424 new_file.name_index = line_info.source_name_index;
425 new_file.name =
426 reinterpret_cast<char* >(new_file.name_index +
427 stabstr_section->sh_offset);
428 new_file.addr = 0;
429 new_file.source_id = symbols->next_source_id++;
430 line_info.source_id = new_file.source_id;
431 symbols->source_file_info.push_back(new_file);
432 } else {
433 // The file has been added.
434 line_info.source_id = found_source_id;
435 }
436 } else {
437 // The line belongs to the file.
438 line_info.source_id = source_file.source_id;
439 }
440 } // for each line.
441 } // for each function.
442 } // for each source file.
443 }
444
445 // Compute size and rva information based on symbols loaded from stab section.
446 static bool ComputeSizeAndRVA(ElfW(Addr) loading_addr,
447 struct SymbolInfo* symbols) {
448 std::vector<struct SourceFileInfo* > sorted_files =
449 SortByAddress(&(symbols->source_file_info));
450 for (size_t i = 0; i < sorted_files.size(); ++i) {
451 struct SourceFileInfo& source_file =* sorted_files[i];
452 std::vector<struct FuncInfo* > sorted_functions =
453 SortByAddress(&(source_file.func_info));
454 for (size_t j = 0; j < sorted_functions.size(); ++j) {
455 struct FuncInfo& func_info = *sorted_functions[j];
456 assert(func_info.addr >= loading_addr);
457 func_info.rva_to_base = func_info.addr - loading_addr;
458 func_info.size = 0;
459 ElfW(Addr) next_addr = NextAddress(&sorted_functions,
460 &sorted_files,
461 func_info);
462 // I've noticed functions with an address bigger than any other functions
463 // and source files modules, this is probably the last function in the
464 // module, due to limitions of Linux stab symbol, it is impossible to get
465 // the exact size of this kind of function, thus we give it a default
466 // very big value. This should be safe since this is the last function.
467 // But it is a ugly hack.....
468 // The following code can reproduce the case:
469 // template<class T>
470 // void Foo(T value) {
471 // }
472 //
473 // int main(void) {
474 // Foo(10);
475 // Foo(std::string("hello"));
476 // return 0;
477 // }
478 // TODO(liuli): Find a better solution.
479 static const int kDefaultSize = 0x10000000;
480 static int no_next_addr_count = 0;
481 if (next_addr != 0) {
482 func_info.size = next_addr - func_info.addr;
483 } else {
484 if (no_next_addr_count > 1) {
485 fprintf(stderr, "Got more than one function without the following ");
486 fprintf(stderr, "symbol. Ignore this function.\n");
487 fprintf(stderr, "The dumped symbol may not correct.\n");
488 assert(!"This should not happen!\n");
489 func_info.size = 0;
490 continue;
491 }
492
493 no_next_addr_count++;
494 func_info.size = kDefaultSize;
495 }
496 // Compute line size.
497 for (LineInfoList::iterator line_info_it = func_info.line_info.begin();
498 line_info_it != func_info.line_info.end(); line_info_it++) {
499 struct LineInfo& line_info = *line_info_it;
500 LineInfoList::iterator next_line_info_it = line_info_it;
501 next_line_info_it++;
502 line_info.size = 0;
503 if (next_line_info_it != func_info.line_info.end()) {
504 line_info.size =
505 next_line_info_it->rva_to_func - line_info.rva_to_func;
506 } else {
507 // The last line in the function.
508 // If we can find a function or source file symbol immediately
509 // following the line, we can get the size of the line by computing
510 // the difference of the next address to the starting address of this
511 // line.
512 // Otherwise, we need to set a default big enough value. This occurs
513 // mostly because the this function is the last one in the module.
514 if (next_addr != 0) {
515 ElfW(Off) next_addr_offset = next_addr - func_info.addr;
516 line_info.size = next_addr_offset - line_info.rva_to_func;
517 } else {
518 line_info.size = kDefaultSize;
519 }
520 }
521 line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
522 } // for each line.
523 } // for each function.
524 } // for each source file.
525 return true;
526 }
527
528 static bool LoadSymbols(const ElfW(Shdr)* stab_section,
529 const ElfW(Shdr)* stabstr_section,
530 ElfW(Addr) loading_addr,
531 struct SymbolInfo* symbols) {
532 if (stab_section == NULL || stabstr_section == NULL)
533 return false;
534
535 struct nlist* lists =
536 reinterpret_cast<struct nlist* >(stab_section->sh_offset);
537 int nstab = stab_section->sh_size / sizeof(struct nlist);
538 // First pass, load all symbols from the object file.
539 for (int i = 0; i < nstab;) {
540 int step = 1;
541 struct nlist* cur_list = lists + i;
542 if (cur_list->n_type == N_SO) {
543 // FUNC <address> <length> <param_stack_size> <function>
544 struct SourceFileInfo source_file_info;
545 source_file_info.name_index = cur_list->n_un.n_strx;
546 source_file_info.name = reinterpret_cast<char* >(cur_list->n_un.n_strx +
547 stabstr_section->sh_offset);
548 source_file_info.addr = cur_list->n_value;
549 if (strchr(source_file_info.name, '.'))
550 source_file_info.source_id = symbols->next_source_id++;
551 else
552 source_file_info.source_id = -1;
553 step = LoadFuncSymbols(cur_list, lists + nstab,
554 stabstr_section, &source_file_info);
555 symbols->source_file_info.push_back(source_file_info);
556 }
557 i += step;
558 }
559
560 // Second pass, compute the size of functions and lines.
561 if (ComputeSizeAndRVA(loading_addr, symbols)) {
562 // Third pass, check for included source code, especially for header files.
563 // Until now, we only have compiling unit information, but they can
564 // have code from include files, add them here.
565 AddIncludedFiles(symbols, stabstr_section);
566 return true;
567 }
568 return false;
569 }
570
571 static bool LoadSymbols(ElfW(Ehdr)* elf_header, struct SymbolInfo* symbols) {
572 // Translate all offsets in section headers into address.
573 FixAddress(elf_header);
574 ElfW(Addr) loading_addr = GetLoadingAddress(
575 reinterpret_cast<ElfW(Phdr)* >(elf_header->e_phoff),
576 elf_header->e_phnum);
577
578 const ElfW(Shdr)* sections =
579 reinterpret_cast<ElfW(Shdr)* >(elf_header->e_shoff);
580 const ElfW(Shdr)* strtab = sections + elf_header->e_shstrndx;
581 const ElfW(Shdr)* stab_section =
582 FindSectionByName(kStabName, sections, strtab, elf_header->e_shnum);
583 if (stab_section == NULL) {
584 fprintf(stderr, "Stab section not found.\n");
585 return false;
586 }
587 const ElfW(Shdr)* stabstr_section = stab_section->sh_link + sections;
588
589 // Load symbols.
590 return LoadSymbols(stab_section, stabstr_section, loading_addr, symbols);
591 }
592
593 static bool WriteModuleInfo(int fd,
594 ElfW(Half) arch,
595 const std::string& obj_file) {
596 const char* arch_name = NULL;
597 if (arch == EM_386)
598 arch_name = "x86";
599 else if (arch == EM_X86_64)
600 arch_name = "x86_64";
601 else
602 return false;
603
604 uint8_t identifier[google_breakpad::kMDGUIDSize];
605 google_breakpad::FileID file_id(obj_file.c_str());
606 if (file_id.ElfFileIdentifier(identifier)) {
607 char identifier_str[40];
608 file_id.ConvertIdentifierToString(identifier,
609 identifier_str, sizeof(identifier_str));
610 char id_no_dash[40];
611 int id_no_dash_len = 0;
612 memset(id_no_dash, 0, sizeof(id_no_dash));
613 for (int i = 0; identifier_str[i] != '\0'; ++i)
614 if (identifier_str[i] != '-')
615 id_no_dash[id_no_dash_len++] = identifier_str[i];
616 // Add an extra "0" by the end.
617 id_no_dash[id_no_dash_len++] = '0';
618 std::string filename = obj_file;
619 size_t slash_pos = obj_file.find_last_of("/");
620 if (slash_pos != std::string::npos)
621 filename = obj_file.substr(slash_pos + 1);
622 return WriteFormat(fd, "MODULE Linux %s %s %s\n", arch_name,
623 id_no_dash, filename.c_str());
624 }
625 return false;
626 }
627
628 static bool WriteSourceFileInfo(int fd, const struct SymbolInfo& symbols) {
629 for (SourceFileInfoList::const_iterator it =
630 symbols.source_file_info.begin();
631 it != symbols.source_file_info.end(); it++) {
632 if (it->source_id != -1) {
633 const char* name = it->name;
634 if (!WriteFormat(fd, "FILE %d %s\n", it->source_id, name))
635 return false;
636 }
637 }
638 return true;
639 }
640
641 static bool WriteOneFunction(int fd,
642 const struct FuncInfo& func_info) {
643 // Discard the ending part of the name.
644 std::string func_name(func_info.name);
645 std::string::size_type last_colon = func_name.find_last_of(':');
646 if (last_colon != std::string::npos)
647 func_name = func_name.substr(0, last_colon);
648 func_name = Demangle(func_name.c_str());
649
650 if (func_info.size <= 0)
651 return true;
652
653 if (WriteFormat(fd, "FUNC %lx %lx %d %s\n",
654 func_info.rva_to_base,
655 func_info.size,
656 func_info.stack_param_size,
657 func_name.c_str())) {
658 for (LineInfoList::const_iterator it = func_info.line_info.begin();
659 it != func_info.line_info.end(); it++) {
660 const struct LineInfo& line_info =* it;
661 if (!WriteFormat(fd, "%lx %lx %d %d\n",
662 line_info.rva_to_base,
663 line_info.size,
664 line_info.line_num,
665 line_info.source_id))
666 return false;
667 }
668 return true;
669 }
670 return false;
671 }
672
673 static bool WriteFunctionInfo(int fd, const struct SymbolInfo& symbols) {
674 for (SourceFileInfoList::const_iterator it =
675 symbols.source_file_info.begin();
676 it != symbols.source_file_info.end(); it++) {
677 const struct SourceFileInfo& file_info =* it;
678 for (FuncInfoList::const_iterator fiIt = file_info.func_info.begin();
679 fiIt != file_info.func_info.end(); fiIt++) {
680 const struct FuncInfo& func_info =* fiIt;
681 if (!WriteOneFunction(fd, func_info))
682 return false;
683 }
684 }
685 return true;
686 }
687
688 static bool DumpStabSymbols(int fd, const struct SymbolInfo& symbols) {
689 return WriteSourceFileInfo(fd, symbols) &&
690 WriteFunctionInfo(fd, symbols);
691 }
692
693 //
694 // FDWrapper
695 //
696 // Wrapper class to make sure opened file is closed.
697 //
698 class FDWrapper {
699 public:
700 explicit FDWrapper(int fd) :
701 fd_(fd) {
702 }
703 ~FDWrapper() {
704 if (fd_ != -1)
705 close(fd_);
706 }
707 int get() {
708 return fd_;
709 }
710 int release() {
711 int fd = fd_;
712 fd_ = -1;
713 return fd;
714 }
715 private:
716 int fd_;
717 };
718
719 //
720 // MmapWrapper
721 //
722 // Wrapper class to make sure mapped regions are unmapped.
723 //
724 class MmapWrapper {
725 public:
726 MmapWrapper(void* mapped_address, size_t mapped_size) :
727 base_(mapped_address), size_(mapped_size) {
728 }
729 ~MmapWrapper() {
730 if (base_ != NULL) {
731 assert(size_ > 0);
732 munmap(base_, size_);
733 }
734 }
735 void release() {
736 base_ = NULL;
737 size_ = 0;
738 }
739
740 private:
741 void* base_;
742 size_t size_;
743 };
744
745 } // namespace
746
747 namespace google_breakpad {
748
749 bool DumpSymbols::WriteSymbolFile(const std::string& obj_file,
750 int sym_fd) {
751 int obj_fd = open(obj_file.c_str(), O_RDONLY);
752 if (obj_fd < 0)
753 return false;
754 FDWrapper obj_fd_wrapper(obj_fd);
755 struct stat st;
756 if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
757 return false;
758 void* obj_base = mmap(NULL, st.st_size,
759 PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
760 if (obj_base == MAP_FAILED)
761 return false;
762 MmapWrapper map_wrapper(obj_base, st.st_size);
763 ElfW(Ehdr)* elf_header = reinterpret_cast<ElfW(Ehdr)* >(obj_base);
764 if (!IsValidElf(elf_header))
765 return false;
766 struct SymbolInfo symbols;
767 symbols.next_source_id = 0;
768
769 if (!LoadSymbols(elf_header, &symbols))
770 return false;
771 // Write to symbol file.
772 if (WriteModuleInfo(sym_fd, elf_header->e_machine, obj_file) &&
773 DumpStabSymbols(sym_fd, symbols))
774 return true;
775
776 return false;
777 }
778
779 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « breakpad/linux/dump_symbols.h ('k') | breakpad/linux/dump_syms.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698