michael@0: // Copyright (c) 2010 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Author: Alfred Peng michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "common/scoped_ptr.h" michael@0: #include "common/solaris/dump_symbols.h" michael@0: #include "common/solaris/file_id.h" michael@0: #include "common/solaris/guid_creator.h" michael@0: michael@0: // This namespace contains helper functions. michael@0: namespace { michael@0: michael@0: using std::make_pair; michael@0: michael@0: #if defined(_LP64) michael@0: typedef Elf64_Sym Elf_Sym; michael@0: #else michael@0: typedef Elf32_Sym Elf_Sym; michael@0: #endif michael@0: michael@0: // Symbol table entry from stabs. Sun CC specific. michael@0: struct slist { michael@0: // String table index. michael@0: unsigned int n_strx; michael@0: // Stab type. michael@0: unsigned char n_type; michael@0: char n_other; michael@0: short n_desc; michael@0: unsigned long n_value; michael@0: }; michael@0: michael@0: // Symbol table entry michael@0: struct SymbolEntry { michael@0: // Offset from the start of the file. michael@0: GElf_Addr offset; michael@0: // Function size. michael@0: GElf_Word size; michael@0: }; michael@0: michael@0: // Infomation of a line. michael@0: struct LineInfo { michael@0: // Offset from start of the function. michael@0: // Load from stab symbol. michael@0: GElf_Off rva_to_func; michael@0: // Offset from base of the loading binary. michael@0: GElf_Off rva_to_base; michael@0: // Size of the line. michael@0: // The first line: equals to rva_to_func. michael@0: // The other lines: the difference of rva_to_func of the line and michael@0: // rva_to_func of the previous N_SLINE. michael@0: uint32_t size; michael@0: // Line number. michael@0: uint32_t line_num; michael@0: }; michael@0: michael@0: // Information of a function. michael@0: struct FuncInfo { michael@0: // Name of the function. michael@0: const char *name; michael@0: // Offset from the base of the loading address. michael@0: GElf_Off rva_to_base; michael@0: // Virtual address of the function. michael@0: // Load from stab symbol. michael@0: GElf_Addr addr; michael@0: // Size of the function. michael@0: // Equal to rva_to_func of the last function line. michael@0: uint32_t size; michael@0: // Total size of stack parameters. michael@0: uint32_t stack_param_size; michael@0: // Line information array. michael@0: std::vector line_info; michael@0: }; michael@0: michael@0: // Information of a source file. michael@0: struct SourceFileInfo { michael@0: // Name of the source file. michael@0: const char *name; michael@0: // Starting address of the source file. michael@0: GElf_Addr addr; michael@0: // Id of the source file. michael@0: int source_id; michael@0: // Functions information. michael@0: std::vector func_info; michael@0: }; michael@0: michael@0: struct CompareString { michael@0: bool operator()(const char *s1, const char *s2) const { michael@0: return strcmp(s1, s2) < 0; michael@0: } michael@0: }; michael@0: michael@0: typedef std::map SymbolMap; michael@0: michael@0: // Information of a symbol table. michael@0: // This is the root of all types of symbol. michael@0: struct SymbolInfo { michael@0: std::vector source_file_info; michael@0: // Symbols information. michael@0: SymbolMap symbol_entries; michael@0: }; michael@0: michael@0: // Stab section name. michael@0: const char *kStabName = ".stab"; michael@0: michael@0: // Stab str section name. michael@0: const char *kStabStrName = ".stabstr"; michael@0: michael@0: // Symtab section name. michael@0: const char *kSymtabName = ".symtab"; michael@0: michael@0: // Strtab section name. michael@0: const char *kStrtabName = ".strtab"; michael@0: michael@0: // Default buffer lenght for demangle. michael@0: const int demangleLen = 20000; michael@0: michael@0: // Offset to the string table. michael@0: uint64_t stringOffset = 0; michael@0: michael@0: // Update the offset to the start of the string index of the next michael@0: // object module for every N_ENDM stabs. michael@0: inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { michael@0: while ((--cur_list)->n_strx == 0) ; michael@0: stringOffset += cur_list->n_strx; michael@0: michael@0: char *temp = stabstr + stringOffset; michael@0: while (*temp != '\0') { michael@0: ++stringOffset; michael@0: ++temp; michael@0: } michael@0: // Skip the extra '\0' michael@0: ++stringOffset; michael@0: } michael@0: michael@0: // Demangle using demangle library on Solaris. michael@0: std::string Demangle(const char *mangled) { michael@0: int status = 0; michael@0: std::string str(mangled); michael@0: char *demangled = (char *)malloc(demangleLen); michael@0: michael@0: if (!demangled) { michael@0: fprintf(stderr, "no enough memory.\n"); michael@0: goto out; michael@0: } michael@0: michael@0: if ((status = cplus_demangle(mangled, demangled, demangleLen)) == michael@0: DEMANGLE_ESPACE) { michael@0: fprintf(stderr, "incorrect demangle.\n"); michael@0: goto out; michael@0: } michael@0: michael@0: str = demangled; michael@0: free(demangled); michael@0: michael@0: out: michael@0: return str; michael@0: } michael@0: michael@0: bool WriteFormat(int fd, const char *fmt, ...) { michael@0: va_list list; michael@0: char buffer[4096]; michael@0: ssize_t expected, written; michael@0: va_start(list, fmt); michael@0: vsnprintf(buffer, sizeof(buffer), fmt, list); michael@0: expected = strlen(buffer); michael@0: written = write(fd, buffer, strlen(buffer)); michael@0: va_end(list); michael@0: return expected == written; michael@0: } michael@0: michael@0: bool IsValidElf(const GElf_Ehdr *elf_header) { michael@0: return memcmp(elf_header, ELFMAG, SELFMAG) == 0; michael@0: } michael@0: michael@0: static bool FindSectionByName(Elf *elf, const char *name, michael@0: int shstrndx, michael@0: GElf_Shdr *shdr) { michael@0: assert(name != NULL); michael@0: michael@0: if (strlen(name) == 0) michael@0: return false; michael@0: michael@0: Elf_Scn *scn = NULL; michael@0: michael@0: while ((scn = elf_nextscn(elf, scn)) != NULL) { michael@0: if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { michael@0: fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); michael@0: return false; michael@0: } michael@0: michael@0: const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); michael@0: if (!section_name) { michael@0: fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); michael@0: continue; michael@0: } michael@0: michael@0: if (strcmp(section_name, name) == 0) michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: // The parameter size is used for FPO-optimized code, and michael@0: // this is all tied up with the debugging data for Windows x86. michael@0: // Set it to 0 on Solaris. michael@0: int LoadStackParamSize(struct slist *list, michael@0: struct slist *list_end, michael@0: struct FuncInfo *func_info) { michael@0: struct slist *cur_list = list; michael@0: int step = 1; michael@0: while (cur_list < list_end && cur_list->n_type == N_PSYM) { michael@0: ++cur_list; michael@0: ++step; michael@0: } michael@0: michael@0: func_info->stack_param_size = 0; michael@0: return step; michael@0: } michael@0: michael@0: int LoadLineInfo(struct slist *list, michael@0: struct slist *list_end, michael@0: struct FuncInfo *func_info) { michael@0: struct slist *cur_list = list; michael@0: do { michael@0: // Skip non line information. michael@0: while (cur_list < list_end && cur_list->n_type != N_SLINE) { michael@0: // Only exit when got another function, or source file, or end stab. michael@0: if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || michael@0: cur_list->n_type == N_ENDM) { michael@0: return cur_list - list; michael@0: } michael@0: ++cur_list; michael@0: } michael@0: struct LineInfo line; michael@0: while (cur_list < list_end && cur_list->n_type == N_SLINE) { michael@0: line.rva_to_func = cur_list->n_value; michael@0: // n_desc is a signed short michael@0: line.line_num = (unsigned short)cur_list->n_desc; michael@0: func_info->line_info.push_back(line); michael@0: ++cur_list; michael@0: } michael@0: if (cur_list == list_end && cur_list->n_type == N_ENDM) michael@0: break; michael@0: } while (list < list_end); michael@0: michael@0: return cur_list - list; michael@0: } michael@0: michael@0: int LoadFuncSymbols(struct slist *list, michael@0: struct slist *list_end, michael@0: char *stabstr, michael@0: GElf_Word base, michael@0: struct SourceFileInfo *source_file_info) { michael@0: struct slist *cur_list = list; michael@0: assert(cur_list->n_type == N_SO); michael@0: ++cur_list; michael@0: michael@0: source_file_info->func_info.clear(); michael@0: while (cur_list < list_end) { michael@0: // Go until the function symbol. michael@0: while (cur_list < list_end && cur_list->n_type != N_FUN) { michael@0: if (cur_list->n_type == N_SO) { michael@0: return cur_list - list; michael@0: } michael@0: ++cur_list; michael@0: if (cur_list->n_type == N_ENDM) michael@0: RecalculateOffset(cur_list, stabstr); michael@0: continue; michael@0: } michael@0: while (cur_list->n_type == N_FUN) { michael@0: struct FuncInfo func_info; michael@0: memset(&func_info, 0, sizeof(func_info)); michael@0: func_info.name = stabstr + cur_list->n_strx + stringOffset; michael@0: // The n_value field is always 0 from stab generated by Sun CC. michael@0: // TODO(Alfred): Find the correct value. michael@0: func_info.addr = cur_list->n_value; michael@0: ++cur_list; michael@0: if (cur_list->n_type == N_ENDM) michael@0: RecalculateOffset(cur_list, stabstr); michael@0: if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && michael@0: cur_list->n_type != N_FUN) { michael@0: // Stack parameter size. michael@0: cur_list += LoadStackParamSize(cur_list, list_end, &func_info); michael@0: // Line info. michael@0: cur_list += LoadLineInfo(cur_list, list_end, &func_info); michael@0: } michael@0: if (cur_list < list_end && cur_list->n_type == N_ENDM) michael@0: RecalculateOffset(cur_list, stabstr); michael@0: // Functions in this module should have address bigger than the module michael@0: // starting address. michael@0: // michael@0: // These two values are always 0 with Sun CC. michael@0: // TODO(Alfred): Get the correct value or remove the condition statement. michael@0: if (func_info.addr >= source_file_info->addr) { michael@0: source_file_info->func_info.push_back(func_info); michael@0: } michael@0: } michael@0: } michael@0: return cur_list - list; michael@0: } michael@0: michael@0: // Compute size and rva information based on symbols loaded from stab section. michael@0: bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { michael@0: std::vector *sorted_files = michael@0: &(symbols->source_file_info); michael@0: SymbolMap *symbol_entries = &(symbols->symbol_entries); michael@0: for (size_t i = 0; i < sorted_files->size(); ++i) { michael@0: struct SourceFileInfo &source_file = (*sorted_files)[i]; michael@0: std::vector *sorted_functions = &(source_file.func_info); michael@0: int func_size = sorted_functions->size(); michael@0: michael@0: for (size_t j = 0; j < func_size; ++j) { michael@0: struct FuncInfo &func_info = (*sorted_functions)[j]; michael@0: int line_count = func_info.line_info.size(); michael@0: michael@0: // Discard the ending part of the name. michael@0: std::string func_name(func_info.name); michael@0: std::string::size_type last_colon = func_name.find_first_of(':'); michael@0: if (last_colon != std::string::npos) michael@0: func_name = func_name.substr(0, last_colon); michael@0: michael@0: // Fine the symbol offset from the loading address and size by name. michael@0: SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); michael@0: if (it->second) { michael@0: func_info.rva_to_base = it->second->offset; michael@0: func_info.size = (line_count == 0) ? 0 : it->second->size; michael@0: } else { michael@0: func_info.rva_to_base = 0; michael@0: func_info.size = 0; michael@0: } michael@0: michael@0: // Compute function and line size. michael@0: for (size_t k = 0; k < line_count; ++k) { michael@0: struct LineInfo &line_info = func_info.line_info[k]; michael@0: michael@0: line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; michael@0: if (k == line_count - 1) { michael@0: line_info.size = func_info.size - line_info.rva_to_func; michael@0: } else { michael@0: struct LineInfo &next_line = func_info.line_info[k + 1]; michael@0: line_info.size = next_line.rva_to_func - line_info.rva_to_func; michael@0: } michael@0: } // for each line. michael@0: } // for each function. michael@0: } // for each source file. michael@0: for (SymbolMap::iterator it = symbol_entries->begin(); michael@0: it != symbol_entries->end(); ++it) { michael@0: free(it->second); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool LoadAllSymbols(const GElf_Shdr *stab_section, michael@0: const GElf_Shdr *stabstr_section, michael@0: GElf_Word base, michael@0: struct SymbolInfo *symbols) { michael@0: if (stab_section == NULL || stabstr_section == NULL) michael@0: return false; michael@0: michael@0: char *stabstr = michael@0: reinterpret_cast(stabstr_section->sh_offset + base); michael@0: struct slist *lists = michael@0: reinterpret_cast(stab_section->sh_offset + base); michael@0: int nstab = stab_section->sh_size / sizeof(struct slist); michael@0: int source_id = 0; michael@0: michael@0: // First pass, load all symbols from the object file. michael@0: for (int i = 0; i < nstab; ) { michael@0: int step = 1; michael@0: struct slist *cur_list = lists + i; michael@0: if (cur_list->n_type == N_SO) { michael@0: // FUNC
michael@0: struct SourceFileInfo source_file_info; michael@0: source_file_info.name = stabstr + cur_list->n_strx + stringOffset; michael@0: // The n_value field is always 0 from stab generated by Sun CC. michael@0: // TODO(Alfred): Find the correct value. michael@0: source_file_info.addr = cur_list->n_value; michael@0: if (strchr(source_file_info.name, '.')) michael@0: source_file_info.source_id = source_id++; michael@0: else michael@0: source_file_info.source_id = -1; michael@0: step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, michael@0: base, &source_file_info); michael@0: symbols->source_file_info.push_back(source_file_info); michael@0: } michael@0: i += step; michael@0: } michael@0: // Second pass, compute the size of functions and lines. michael@0: return ComputeSizeAndRVA(symbols); michael@0: } michael@0: michael@0: bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, michael@0: void *obj_base) { michael@0: GElf_Word base = reinterpret_cast(obj_base); michael@0: michael@0: const GElf_Shdr *sections = michael@0: reinterpret_cast(elf_header->e_shoff + base); michael@0: GElf_Shdr stab_section; michael@0: if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, michael@0: &stab_section)) { michael@0: fprintf(stderr, "Stab section not found.\n"); michael@0: return false; michael@0: } michael@0: GElf_Shdr stabstr_section; michael@0: if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx, michael@0: &stabstr_section)) { michael@0: fprintf(stderr, "Stabstr section not found.\n"); michael@0: return false; michael@0: } michael@0: GElf_Shdr symtab_section; michael@0: if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, michael@0: &symtab_section)) { michael@0: fprintf(stderr, "Symtab section not found.\n"); michael@0: return false; michael@0: } michael@0: GElf_Shdr strtab_section; michael@0: if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, michael@0: &strtab_section)) { michael@0: fprintf(stderr, "Strtab section not found.\n"); michael@0: return false; michael@0: } michael@0: michael@0: Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); michael@0: for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { michael@0: struct SymbolEntry *symbol_entry = michael@0: (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); michael@0: const char *name = reinterpret_cast( michael@0: strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); michael@0: symbol_entry->offset = symbol->st_value; michael@0: symbol_entry->size = symbol->st_size; michael@0: symbols->symbol_entries.insert(make_pair(name, symbol_entry)); michael@0: ++symbol; michael@0: } michael@0: michael@0: michael@0: // Load symbols. michael@0: return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); michael@0: } michael@0: michael@0: bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { michael@0: const char *arch_name = NULL; michael@0: if (arch == EM_386) michael@0: arch_name = "x86"; michael@0: else if (arch == EM_X86_64) michael@0: arch_name = "x86_64"; michael@0: else if (arch == EM_SPARC32PLUS) michael@0: arch_name = "SPARC_32+"; michael@0: else { michael@0: printf("Please add more ARCH support\n"); michael@0: return false; michael@0: } michael@0: michael@0: unsigned char identifier[16]; michael@0: google_breakpad::FileID file_id(obj_file.c_str()); michael@0: if (file_id.ElfFileIdentifier(identifier)) { michael@0: char identifier_str[40]; michael@0: file_id.ConvertIdentifierToString(identifier, michael@0: identifier_str, sizeof(identifier_str)); michael@0: std::string filename = obj_file; michael@0: size_t slash_pos = obj_file.find_last_of("/"); michael@0: if (slash_pos != std::string::npos) michael@0: filename = obj_file.substr(slash_pos + 1); michael@0: return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name, michael@0: identifier_str, filename.c_str()); michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { michael@0: for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { michael@0: if (symbols.source_file_info[i].source_id != -1) { michael@0: const char *name = symbols.source_file_info[i].name; michael@0: if (!WriteFormat(fd, "FILE %d %s\n", michael@0: symbols.source_file_info[i].source_id, name)) michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool WriteOneFunction(int fd, int source_id, michael@0: const struct FuncInfo &func_info){ michael@0: // Discard the ending part of the name. michael@0: std::string func_name(func_info.name); michael@0: std::string::size_type last_colon = func_name.find_last_of(':'); michael@0: if (last_colon != std::string::npos) michael@0: func_name = func_name.substr(0, last_colon); michael@0: func_name = Demangle(func_name.c_str()); michael@0: michael@0: if (func_info.size <= 0) michael@0: return true; michael@0: michael@0: // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). michael@0: if (WriteFormat(fd, "FUNC %llx %x %d %s\n", michael@0: (long long)func_info.rva_to_base, michael@0: func_info.size, michael@0: func_info.stack_param_size, michael@0: func_name.c_str())) { michael@0: for (size_t i = 0; i < func_info.line_info.size(); ++i) { michael@0: const struct LineInfo &line_info = func_info.line_info[i]; michael@0: if (line_info.line_num == 0) michael@0: return true; michael@0: if (!WriteFormat(fd, "%llx %x %d %d\n", michael@0: (long long)line_info.rva_to_base, michael@0: line_info.size, michael@0: line_info.line_num, michael@0: source_id)) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { michael@0: for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { michael@0: const struct SourceFileInfo &file_info = symbols.source_file_info[i]; michael@0: for (size_t j = 0; j < file_info.func_info.size(); ++j) { michael@0: const struct FuncInfo &func_info = file_info.func_info[j]; michael@0: if (!WriteOneFunction(fd, file_info.source_id, func_info)) michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { michael@0: return WriteSourceFileInfo(fd, symbols) && michael@0: WriteFunctionInfo(fd, symbols); michael@0: } michael@0: michael@0: // michael@0: // FDWrapper michael@0: // michael@0: // Wrapper class to make sure opened file is closed. michael@0: // michael@0: class FDWrapper { michael@0: public: michael@0: explicit FDWrapper(int fd) : michael@0: fd_(fd) { michael@0: } michael@0: ~FDWrapper() { michael@0: if (fd_ != -1) michael@0: close(fd_); michael@0: } michael@0: int get() { michael@0: return fd_; michael@0: } michael@0: int release() { michael@0: int fd = fd_; michael@0: fd_ = -1; michael@0: return fd; michael@0: } michael@0: private: michael@0: int fd_; michael@0: }; michael@0: michael@0: // michael@0: // MmapWrapper michael@0: // michael@0: // Wrapper class to make sure mapped regions are unmapped. michael@0: // michael@0: class MmapWrapper { michael@0: public: michael@0: MmapWrapper(void *mapped_address, size_t mapped_size) : michael@0: base_(mapped_address), size_(mapped_size) { michael@0: } michael@0: ~MmapWrapper() { michael@0: if (base_ != NULL) { michael@0: assert(size_ > 0); michael@0: munmap((char *)base_, size_); michael@0: } michael@0: } michael@0: void release() { michael@0: base_ = NULL; michael@0: size_ = 0; michael@0: } michael@0: michael@0: private: michael@0: void *base_; michael@0: size_t size_; michael@0: }; michael@0: michael@0: } // namespace michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: class AutoElfEnder { michael@0: public: michael@0: AutoElfEnder(Elf *elf) : elf_(elf) {} michael@0: ~AutoElfEnder() { if (elf_) elf_end(elf_); } michael@0: private: michael@0: Elf *elf_; michael@0: }; michael@0: michael@0: michael@0: bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { michael@0: if (elf_version(EV_CURRENT) == EV_NONE) { michael@0: fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); michael@0: return false; michael@0: } michael@0: michael@0: int obj_fd = open(obj_file.c_str(), O_RDONLY); michael@0: if (obj_fd < 0) michael@0: return false; michael@0: FDWrapper obj_fd_wrapper(obj_fd); michael@0: struct stat st; michael@0: if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) michael@0: return false; michael@0: void *obj_base = mmap(NULL, st.st_size, michael@0: PROT_READ, MAP_PRIVATE, obj_fd, 0); michael@0: if (obj_base == MAP_FAILED) michael@0: return false; michael@0: MmapWrapper map_wrapper(obj_base, st.st_size); michael@0: GElf_Ehdr elf_header; michael@0: Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); michael@0: AutoElfEnder elfEnder(elf); michael@0: michael@0: if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { michael@0: fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); michael@0: return false; michael@0: } michael@0: michael@0: if (!IsValidElf(&elf_header)) { michael@0: fprintf(stderr, "header magic doesn't match\n"); michael@0: return false; michael@0: } michael@0: struct SymbolInfo symbols; michael@0: if (!LoadSymbols(elf, &elf_header, &symbols, obj_base)) michael@0: return false; michael@0: // Write to symbol file. michael@0: if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) && michael@0: DumpStabSymbols(sym_fd, symbols)) michael@0: return true; michael@0: michael@0: return false; michael@0: } michael@0: michael@0: } // namespace google_breakpad