1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,681 @@ 1.4 +// Copyright (c) 2010 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Author: Alfred Peng 1.34 + 1.35 +#include <demangle.h> 1.36 +#include <fcntl.h> 1.37 +#include <gelf.h> 1.38 +#include <link.h> 1.39 +#include <sys/mman.h> 1.40 +#include <stab.h> 1.41 +#include <sys/stat.h> 1.42 +#include <sys/types.h> 1.43 +#include <unistd.h> 1.44 + 1.45 +#include <functional> 1.46 +#include <map> 1.47 +#include <vector> 1.48 + 1.49 +#include "common/scoped_ptr.h" 1.50 +#include "common/solaris/dump_symbols.h" 1.51 +#include "common/solaris/file_id.h" 1.52 +#include "common/solaris/guid_creator.h" 1.53 + 1.54 +// This namespace contains helper functions. 1.55 +namespace { 1.56 + 1.57 +using std::make_pair; 1.58 + 1.59 +#if defined(_LP64) 1.60 +typedef Elf64_Sym Elf_Sym; 1.61 +#else 1.62 +typedef Elf32_Sym Elf_Sym; 1.63 +#endif 1.64 + 1.65 +// Symbol table entry from stabs. Sun CC specific. 1.66 +struct slist { 1.67 + // String table index. 1.68 + unsigned int n_strx; 1.69 + // Stab type. 1.70 + unsigned char n_type; 1.71 + char n_other; 1.72 + short n_desc; 1.73 + unsigned long n_value; 1.74 +}; 1.75 + 1.76 +// Symbol table entry 1.77 +struct SymbolEntry { 1.78 + // Offset from the start of the file. 1.79 + GElf_Addr offset; 1.80 + // Function size. 1.81 + GElf_Word size; 1.82 +}; 1.83 + 1.84 +// Infomation of a line. 1.85 +struct LineInfo { 1.86 + // Offset from start of the function. 1.87 + // Load from stab symbol. 1.88 + GElf_Off rva_to_func; 1.89 + // Offset from base of the loading binary. 1.90 + GElf_Off rva_to_base; 1.91 + // Size of the line. 1.92 + // The first line: equals to rva_to_func. 1.93 + // The other lines: the difference of rva_to_func of the line and 1.94 + // rva_to_func of the previous N_SLINE. 1.95 + uint32_t size; 1.96 + // Line number. 1.97 + uint32_t line_num; 1.98 +}; 1.99 + 1.100 +// Information of a function. 1.101 +struct FuncInfo { 1.102 + // Name of the function. 1.103 + const char *name; 1.104 + // Offset from the base of the loading address. 1.105 + GElf_Off rva_to_base; 1.106 + // Virtual address of the function. 1.107 + // Load from stab symbol. 1.108 + GElf_Addr addr; 1.109 + // Size of the function. 1.110 + // Equal to rva_to_func of the last function line. 1.111 + uint32_t size; 1.112 + // Total size of stack parameters. 1.113 + uint32_t stack_param_size; 1.114 + // Line information array. 1.115 + std::vector<struct LineInfo> line_info; 1.116 +}; 1.117 + 1.118 +// Information of a source file. 1.119 +struct SourceFileInfo { 1.120 + // Name of the source file. 1.121 + const char *name; 1.122 + // Starting address of the source file. 1.123 + GElf_Addr addr; 1.124 + // Id of the source file. 1.125 + int source_id; 1.126 + // Functions information. 1.127 + std::vector<struct FuncInfo> func_info; 1.128 +}; 1.129 + 1.130 +struct CompareString { 1.131 + bool operator()(const char *s1, const char *s2) const { 1.132 + return strcmp(s1, s2) < 0; 1.133 + } 1.134 +}; 1.135 + 1.136 +typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap; 1.137 + 1.138 +// Information of a symbol table. 1.139 +// This is the root of all types of symbol. 1.140 +struct SymbolInfo { 1.141 + std::vector<struct SourceFileInfo> source_file_info; 1.142 + // Symbols information. 1.143 + SymbolMap symbol_entries; 1.144 +}; 1.145 + 1.146 +// Stab section name. 1.147 +const char *kStabName = ".stab"; 1.148 + 1.149 +// Stab str section name. 1.150 +const char *kStabStrName = ".stabstr"; 1.151 + 1.152 +// Symtab section name. 1.153 +const char *kSymtabName = ".symtab"; 1.154 + 1.155 +// Strtab section name. 1.156 +const char *kStrtabName = ".strtab"; 1.157 + 1.158 +// Default buffer lenght for demangle. 1.159 +const int demangleLen = 20000; 1.160 + 1.161 +// Offset to the string table. 1.162 +uint64_t stringOffset = 0; 1.163 + 1.164 +// Update the offset to the start of the string index of the next 1.165 +// object module for every N_ENDM stabs. 1.166 +inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { 1.167 + while ((--cur_list)->n_strx == 0) ; 1.168 + stringOffset += cur_list->n_strx; 1.169 + 1.170 + char *temp = stabstr + stringOffset; 1.171 + while (*temp != '\0') { 1.172 + ++stringOffset; 1.173 + ++temp; 1.174 + } 1.175 + // Skip the extra '\0' 1.176 + ++stringOffset; 1.177 +} 1.178 + 1.179 +// Demangle using demangle library on Solaris. 1.180 +std::string Demangle(const char *mangled) { 1.181 + int status = 0; 1.182 + std::string str(mangled); 1.183 + char *demangled = (char *)malloc(demangleLen); 1.184 + 1.185 + if (!demangled) { 1.186 + fprintf(stderr, "no enough memory.\n"); 1.187 + goto out; 1.188 + } 1.189 + 1.190 + if ((status = cplus_demangle(mangled, demangled, demangleLen)) == 1.191 + DEMANGLE_ESPACE) { 1.192 + fprintf(stderr, "incorrect demangle.\n"); 1.193 + goto out; 1.194 + } 1.195 + 1.196 + str = demangled; 1.197 + free(demangled); 1.198 + 1.199 +out: 1.200 + return str; 1.201 +} 1.202 + 1.203 +bool WriteFormat(int fd, const char *fmt, ...) { 1.204 + va_list list; 1.205 + char buffer[4096]; 1.206 + ssize_t expected, written; 1.207 + va_start(list, fmt); 1.208 + vsnprintf(buffer, sizeof(buffer), fmt, list); 1.209 + expected = strlen(buffer); 1.210 + written = write(fd, buffer, strlen(buffer)); 1.211 + va_end(list); 1.212 + return expected == written; 1.213 +} 1.214 + 1.215 +bool IsValidElf(const GElf_Ehdr *elf_header) { 1.216 + return memcmp(elf_header, ELFMAG, SELFMAG) == 0; 1.217 +} 1.218 + 1.219 +static bool FindSectionByName(Elf *elf, const char *name, 1.220 + int shstrndx, 1.221 + GElf_Shdr *shdr) { 1.222 + assert(name != NULL); 1.223 + 1.224 + if (strlen(name) == 0) 1.225 + return false; 1.226 + 1.227 + Elf_Scn *scn = NULL; 1.228 + 1.229 + while ((scn = elf_nextscn(elf, scn)) != NULL) { 1.230 + if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { 1.231 + fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); 1.232 + return false; 1.233 + } 1.234 + 1.235 + const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); 1.236 + if (!section_name) { 1.237 + fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); 1.238 + continue; 1.239 + } 1.240 + 1.241 + if (strcmp(section_name, name) == 0) 1.242 + return true; 1.243 + } 1.244 + 1.245 + return false; 1.246 +} 1.247 + 1.248 +// The parameter size is used for FPO-optimized code, and 1.249 +// this is all tied up with the debugging data for Windows x86. 1.250 +// Set it to 0 on Solaris. 1.251 +int LoadStackParamSize(struct slist *list, 1.252 + struct slist *list_end, 1.253 + struct FuncInfo *func_info) { 1.254 + struct slist *cur_list = list; 1.255 + int step = 1; 1.256 + while (cur_list < list_end && cur_list->n_type == N_PSYM) { 1.257 + ++cur_list; 1.258 + ++step; 1.259 + } 1.260 + 1.261 + func_info->stack_param_size = 0; 1.262 + return step; 1.263 +} 1.264 + 1.265 +int LoadLineInfo(struct slist *list, 1.266 + struct slist *list_end, 1.267 + struct FuncInfo *func_info) { 1.268 + struct slist *cur_list = list; 1.269 + do { 1.270 + // Skip non line information. 1.271 + while (cur_list < list_end && cur_list->n_type != N_SLINE) { 1.272 + // Only exit when got another function, or source file, or end stab. 1.273 + if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || 1.274 + cur_list->n_type == N_ENDM) { 1.275 + return cur_list - list; 1.276 + } 1.277 + ++cur_list; 1.278 + } 1.279 + struct LineInfo line; 1.280 + while (cur_list < list_end && cur_list->n_type == N_SLINE) { 1.281 + line.rva_to_func = cur_list->n_value; 1.282 + // n_desc is a signed short 1.283 + line.line_num = (unsigned short)cur_list->n_desc; 1.284 + func_info->line_info.push_back(line); 1.285 + ++cur_list; 1.286 + } 1.287 + if (cur_list == list_end && cur_list->n_type == N_ENDM) 1.288 + break; 1.289 + } while (list < list_end); 1.290 + 1.291 + return cur_list - list; 1.292 +} 1.293 + 1.294 +int LoadFuncSymbols(struct slist *list, 1.295 + struct slist *list_end, 1.296 + char *stabstr, 1.297 + GElf_Word base, 1.298 + struct SourceFileInfo *source_file_info) { 1.299 + struct slist *cur_list = list; 1.300 + assert(cur_list->n_type == N_SO); 1.301 + ++cur_list; 1.302 + 1.303 + source_file_info->func_info.clear(); 1.304 + while (cur_list < list_end) { 1.305 + // Go until the function symbol. 1.306 + while (cur_list < list_end && cur_list->n_type != N_FUN) { 1.307 + if (cur_list->n_type == N_SO) { 1.308 + return cur_list - list; 1.309 + } 1.310 + ++cur_list; 1.311 + if (cur_list->n_type == N_ENDM) 1.312 + RecalculateOffset(cur_list, stabstr); 1.313 + continue; 1.314 + } 1.315 + while (cur_list->n_type == N_FUN) { 1.316 + struct FuncInfo func_info; 1.317 + memset(&func_info, 0, sizeof(func_info)); 1.318 + func_info.name = stabstr + cur_list->n_strx + stringOffset; 1.319 + // The n_value field is always 0 from stab generated by Sun CC. 1.320 + // TODO(Alfred): Find the correct value. 1.321 + func_info.addr = cur_list->n_value; 1.322 + ++cur_list; 1.323 + if (cur_list->n_type == N_ENDM) 1.324 + RecalculateOffset(cur_list, stabstr); 1.325 + if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && 1.326 + cur_list->n_type != N_FUN) { 1.327 + // Stack parameter size. 1.328 + cur_list += LoadStackParamSize(cur_list, list_end, &func_info); 1.329 + // Line info. 1.330 + cur_list += LoadLineInfo(cur_list, list_end, &func_info); 1.331 + } 1.332 + if (cur_list < list_end && cur_list->n_type == N_ENDM) 1.333 + RecalculateOffset(cur_list, stabstr); 1.334 + // Functions in this module should have address bigger than the module 1.335 + // starting address. 1.336 + // 1.337 + // These two values are always 0 with Sun CC. 1.338 + // TODO(Alfred): Get the correct value or remove the condition statement. 1.339 + if (func_info.addr >= source_file_info->addr) { 1.340 + source_file_info->func_info.push_back(func_info); 1.341 + } 1.342 + } 1.343 + } 1.344 + return cur_list - list; 1.345 +} 1.346 + 1.347 +// Compute size and rva information based on symbols loaded from stab section. 1.348 +bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { 1.349 + std::vector<struct SourceFileInfo> *sorted_files = 1.350 + &(symbols->source_file_info); 1.351 + SymbolMap *symbol_entries = &(symbols->symbol_entries); 1.352 + for (size_t i = 0; i < sorted_files->size(); ++i) { 1.353 + struct SourceFileInfo &source_file = (*sorted_files)[i]; 1.354 + std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info); 1.355 + int func_size = sorted_functions->size(); 1.356 + 1.357 + for (size_t j = 0; j < func_size; ++j) { 1.358 + struct FuncInfo &func_info = (*sorted_functions)[j]; 1.359 + int line_count = func_info.line_info.size(); 1.360 + 1.361 + // Discard the ending part of the name. 1.362 + std::string func_name(func_info.name); 1.363 + std::string::size_type last_colon = func_name.find_first_of(':'); 1.364 + if (last_colon != std::string::npos) 1.365 + func_name = func_name.substr(0, last_colon); 1.366 + 1.367 + // Fine the symbol offset from the loading address and size by name. 1.368 + SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); 1.369 + if (it->second) { 1.370 + func_info.rva_to_base = it->second->offset; 1.371 + func_info.size = (line_count == 0) ? 0 : it->second->size; 1.372 + } else { 1.373 + func_info.rva_to_base = 0; 1.374 + func_info.size = 0; 1.375 + } 1.376 + 1.377 + // Compute function and line size. 1.378 + for (size_t k = 0; k < line_count; ++k) { 1.379 + struct LineInfo &line_info = func_info.line_info[k]; 1.380 + 1.381 + line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; 1.382 + if (k == line_count - 1) { 1.383 + line_info.size = func_info.size - line_info.rva_to_func; 1.384 + } else { 1.385 + struct LineInfo &next_line = func_info.line_info[k + 1]; 1.386 + line_info.size = next_line.rva_to_func - line_info.rva_to_func; 1.387 + } 1.388 + } // for each line. 1.389 + } // for each function. 1.390 + } // for each source file. 1.391 + for (SymbolMap::iterator it = symbol_entries->begin(); 1.392 + it != symbol_entries->end(); ++it) { 1.393 + free(it->second); 1.394 + } 1.395 + return true; 1.396 +} 1.397 + 1.398 +bool LoadAllSymbols(const GElf_Shdr *stab_section, 1.399 + const GElf_Shdr *stabstr_section, 1.400 + GElf_Word base, 1.401 + struct SymbolInfo *symbols) { 1.402 + if (stab_section == NULL || stabstr_section == NULL) 1.403 + return false; 1.404 + 1.405 + char *stabstr = 1.406 + reinterpret_cast<char *>(stabstr_section->sh_offset + base); 1.407 + struct slist *lists = 1.408 + reinterpret_cast<struct slist *>(stab_section->sh_offset + base); 1.409 + int nstab = stab_section->sh_size / sizeof(struct slist); 1.410 + int source_id = 0; 1.411 + 1.412 + // First pass, load all symbols from the object file. 1.413 + for (int i = 0; i < nstab; ) { 1.414 + int step = 1; 1.415 + struct slist *cur_list = lists + i; 1.416 + if (cur_list->n_type == N_SO) { 1.417 + // FUNC <address> <size> <param_stack_size> <function> 1.418 + struct SourceFileInfo source_file_info; 1.419 + source_file_info.name = stabstr + cur_list->n_strx + stringOffset; 1.420 + // The n_value field is always 0 from stab generated by Sun CC. 1.421 + // TODO(Alfred): Find the correct value. 1.422 + source_file_info.addr = cur_list->n_value; 1.423 + if (strchr(source_file_info.name, '.')) 1.424 + source_file_info.source_id = source_id++; 1.425 + else 1.426 + source_file_info.source_id = -1; 1.427 + step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, 1.428 + base, &source_file_info); 1.429 + symbols->source_file_info.push_back(source_file_info); 1.430 + } 1.431 + i += step; 1.432 + } 1.433 + // Second pass, compute the size of functions and lines. 1.434 + return ComputeSizeAndRVA(symbols); 1.435 +} 1.436 + 1.437 +bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, 1.438 + void *obj_base) { 1.439 + GElf_Word base = reinterpret_cast<GElf_Word>(obj_base); 1.440 + 1.441 + const GElf_Shdr *sections = 1.442 + reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base); 1.443 + GElf_Shdr stab_section; 1.444 + if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, 1.445 + &stab_section)) { 1.446 + fprintf(stderr, "Stab section not found.\n"); 1.447 + return false; 1.448 + } 1.449 + GElf_Shdr stabstr_section; 1.450 + if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx, 1.451 + &stabstr_section)) { 1.452 + fprintf(stderr, "Stabstr section not found.\n"); 1.453 + return false; 1.454 + } 1.455 + GElf_Shdr symtab_section; 1.456 + if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, 1.457 + &symtab_section)) { 1.458 + fprintf(stderr, "Symtab section not found.\n"); 1.459 + return false; 1.460 + } 1.461 + GElf_Shdr strtab_section; 1.462 + if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, 1.463 + &strtab_section)) { 1.464 + fprintf(stderr, "Strtab section not found.\n"); 1.465 + return false; 1.466 + } 1.467 + 1.468 + Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); 1.469 + for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { 1.470 + struct SymbolEntry *symbol_entry = 1.471 + (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); 1.472 + const char *name = reinterpret_cast<char *>( 1.473 + strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); 1.474 + symbol_entry->offset = symbol->st_value; 1.475 + symbol_entry->size = symbol->st_size; 1.476 + symbols->symbol_entries.insert(make_pair(name, symbol_entry)); 1.477 + ++symbol; 1.478 + } 1.479 + 1.480 + 1.481 + // Load symbols. 1.482 + return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); 1.483 +} 1.484 + 1.485 +bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { 1.486 + const char *arch_name = NULL; 1.487 + if (arch == EM_386) 1.488 + arch_name = "x86"; 1.489 + else if (arch == EM_X86_64) 1.490 + arch_name = "x86_64"; 1.491 + else if (arch == EM_SPARC32PLUS) 1.492 + arch_name = "SPARC_32+"; 1.493 + else { 1.494 + printf("Please add more ARCH support\n"); 1.495 + return false; 1.496 + } 1.497 + 1.498 + unsigned char identifier[16]; 1.499 + google_breakpad::FileID file_id(obj_file.c_str()); 1.500 + if (file_id.ElfFileIdentifier(identifier)) { 1.501 + char identifier_str[40]; 1.502 + file_id.ConvertIdentifierToString(identifier, 1.503 + identifier_str, sizeof(identifier_str)); 1.504 + std::string filename = obj_file; 1.505 + size_t slash_pos = obj_file.find_last_of("/"); 1.506 + if (slash_pos != std::string::npos) 1.507 + filename = obj_file.substr(slash_pos + 1); 1.508 + return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name, 1.509 + identifier_str, filename.c_str()); 1.510 + } 1.511 + return false; 1.512 +} 1.513 + 1.514 +bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { 1.515 + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { 1.516 + if (symbols.source_file_info[i].source_id != -1) { 1.517 + const char *name = symbols.source_file_info[i].name; 1.518 + if (!WriteFormat(fd, "FILE %d %s\n", 1.519 + symbols.source_file_info[i].source_id, name)) 1.520 + return false; 1.521 + } 1.522 + } 1.523 + return true; 1.524 +} 1.525 + 1.526 +bool WriteOneFunction(int fd, int source_id, 1.527 + const struct FuncInfo &func_info){ 1.528 + // Discard the ending part of the name. 1.529 + std::string func_name(func_info.name); 1.530 + std::string::size_type last_colon = func_name.find_last_of(':'); 1.531 + if (last_colon != std::string::npos) 1.532 + func_name = func_name.substr(0, last_colon); 1.533 + func_name = Demangle(func_name.c_str()); 1.534 + 1.535 + if (func_info.size <= 0) 1.536 + return true; 1.537 + 1.538 + // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). 1.539 + if (WriteFormat(fd, "FUNC %llx %x %d %s\n", 1.540 + (long long)func_info.rva_to_base, 1.541 + func_info.size, 1.542 + func_info.stack_param_size, 1.543 + func_name.c_str())) { 1.544 + for (size_t i = 0; i < func_info.line_info.size(); ++i) { 1.545 + const struct LineInfo &line_info = func_info.line_info[i]; 1.546 + if (line_info.line_num == 0) 1.547 + return true; 1.548 + if (!WriteFormat(fd, "%llx %x %d %d\n", 1.549 + (long long)line_info.rva_to_base, 1.550 + line_info.size, 1.551 + line_info.line_num, 1.552 + source_id)) 1.553 + return false; 1.554 + } 1.555 + return true; 1.556 + } 1.557 + return false; 1.558 +} 1.559 + 1.560 +bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { 1.561 + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { 1.562 + const struct SourceFileInfo &file_info = symbols.source_file_info[i]; 1.563 + for (size_t j = 0; j < file_info.func_info.size(); ++j) { 1.564 + const struct FuncInfo &func_info = file_info.func_info[j]; 1.565 + if (!WriteOneFunction(fd, file_info.source_id, func_info)) 1.566 + return false; 1.567 + } 1.568 + } 1.569 + return true; 1.570 +} 1.571 + 1.572 +bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { 1.573 + return WriteSourceFileInfo(fd, symbols) && 1.574 + WriteFunctionInfo(fd, symbols); 1.575 +} 1.576 + 1.577 +// 1.578 +// FDWrapper 1.579 +// 1.580 +// Wrapper class to make sure opened file is closed. 1.581 +// 1.582 +class FDWrapper { 1.583 + public: 1.584 + explicit FDWrapper(int fd) : 1.585 + fd_(fd) { 1.586 + } 1.587 + ~FDWrapper() { 1.588 + if (fd_ != -1) 1.589 + close(fd_); 1.590 + } 1.591 + int get() { 1.592 + return fd_; 1.593 + } 1.594 + int release() { 1.595 + int fd = fd_; 1.596 + fd_ = -1; 1.597 + return fd; 1.598 + } 1.599 + private: 1.600 + int fd_; 1.601 +}; 1.602 + 1.603 +// 1.604 +// MmapWrapper 1.605 +// 1.606 +// Wrapper class to make sure mapped regions are unmapped. 1.607 +// 1.608 +class MmapWrapper { 1.609 + public: 1.610 + MmapWrapper(void *mapped_address, size_t mapped_size) : 1.611 + base_(mapped_address), size_(mapped_size) { 1.612 + } 1.613 + ~MmapWrapper() { 1.614 + if (base_ != NULL) { 1.615 + assert(size_ > 0); 1.616 + munmap((char *)base_, size_); 1.617 + } 1.618 + } 1.619 + void release() { 1.620 + base_ = NULL; 1.621 + size_ = 0; 1.622 + } 1.623 + 1.624 + private: 1.625 + void *base_; 1.626 + size_t size_; 1.627 +}; 1.628 + 1.629 +} // namespace 1.630 + 1.631 +namespace google_breakpad { 1.632 + 1.633 +class AutoElfEnder { 1.634 + public: 1.635 + AutoElfEnder(Elf *elf) : elf_(elf) {} 1.636 + ~AutoElfEnder() { if (elf_) elf_end(elf_); } 1.637 + private: 1.638 + Elf *elf_; 1.639 +}; 1.640 + 1.641 + 1.642 +bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { 1.643 + if (elf_version(EV_CURRENT) == EV_NONE) { 1.644 + fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); 1.645 + return false; 1.646 + } 1.647 + 1.648 + int obj_fd = open(obj_file.c_str(), O_RDONLY); 1.649 + if (obj_fd < 0) 1.650 + return false; 1.651 + FDWrapper obj_fd_wrapper(obj_fd); 1.652 + struct stat st; 1.653 + if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) 1.654 + return false; 1.655 + void *obj_base = mmap(NULL, st.st_size, 1.656 + PROT_READ, MAP_PRIVATE, obj_fd, 0); 1.657 + if (obj_base == MAP_FAILED) 1.658 + return false; 1.659 + MmapWrapper map_wrapper(obj_base, st.st_size); 1.660 + GElf_Ehdr elf_header; 1.661 + Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); 1.662 + AutoElfEnder elfEnder(elf); 1.663 + 1.664 + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { 1.665 + fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); 1.666 + return false; 1.667 + } 1.668 + 1.669 + if (!IsValidElf(&elf_header)) { 1.670 + fprintf(stderr, "header magic doesn't match\n"); 1.671 + return false; 1.672 + } 1.673 + struct SymbolInfo symbols; 1.674 + if (!LoadSymbols(elf, &elf_header, &symbols, obj_base)) 1.675 + return false; 1.676 + // Write to symbol file. 1.677 + if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) && 1.678 + DumpStabSymbols(sym_fd, symbols)) 1.679 + return true; 1.680 + 1.681 + return false; 1.682 +} 1.683 + 1.684 +} // namespace google_breakpad