From dd2ff4a21c57672170eb14ccc5142efd7d92f3f1 Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Tue, 18 Mar 2008 16:10:10 +0000 Subject: issue 223 - Fixes for SOlaris handler during integration with Firefox. patch by Alfred Peng, r=mento,me git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@250 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/common/solaris/dump_symbols.cc | 187 +++++++++++++++++++++++++++---------- 1 file changed, 140 insertions(+), 47 deletions(-) (limited to 'src/common/solaris') diff --git a/src/common/solaris/dump_symbols.cc b/src/common/solaris/dump_symbols.cc index b9fc74f6..df1c5b09 100644 --- a/src/common/solaris/dump_symbols.cc +++ b/src/common/solaris/dump_symbols.cc @@ -40,6 +40,7 @@ #include #include +#include #include #include "common/solaris/dump_symbols.h" @@ -50,7 +51,15 @@ // This namespace contains helper functions. namespace { -// Symbol table entry for stabs. Sun CC specific. +using std::make_pair; + +#if defined(_LP64) +typedef Elf64_Sym Elf_Sym; +#else +typedef Elf32_Sym Elf_Sym; +#endif + +// Symbol table entry from stabs. Sun CC specific. struct slist { // String table index. unsigned int n_strx; @@ -61,6 +70,14 @@ struct slist { unsigned long n_value; }; +// Symbol table entry +struct SymbolEntry { + // Offset from the start of the file. + GElf_Addr offset; + // Function size. + GElf_Word size; +}; + // Infomation of a line. struct LineInfo { // Offset from start of the function. @@ -107,10 +124,20 @@ struct SourceFileInfo { std::vector func_info; }; +struct CompareString { + bool operator()(const char *s1, const char *s2) const { + return strcmp(s1, s2) < 0; + } +}; + +typedef std::map SymbolMap; + // Information of a symbol table. // This is the root of all types of symbol. struct SymbolInfo { std::vector source_file_info; + // Symbols information. + SymbolMap symbol_entries; }; // Stab section name. @@ -119,8 +146,32 @@ const char *kStabName = ".stab"; // Stab str section name. const char *kStabStrName = ".stabstr"; +// Symtab section name. +const char *kSymtabName = ".symtab"; + +// Strtab section name. +const char *kStrtabName = ".strtab"; + // Default buffer lenght for demangle. -const int demangleLen = 2000; +const int demangleLen = 20000; + +// Offset to the string table. +u_int64_t stringOffset = 0; + +// Update the offset to the start of the string index of the next +// object module for every N_ENDM stabs. +inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { + while ((--cur_list)->n_strx == 0) ; + stringOffset += cur_list->n_strx; + + char *temp = stabstr + stringOffset; + while (*temp != '\0') { + ++stringOffset; + ++temp; + } + // Skip the extra '\0' + ++stringOffset; +} // Demangle using demangle library on Solaris. std::string Demangle(const char *mangled) { @@ -145,18 +196,6 @@ out: return std::string(mangled); } -// Find the prefered loading address of the binary. -GElf_Addr GetLoadingAddress(const GElf_Phdr *program_headers, int nheader) { - for (int i = 0; i < nheader; ++i) { - const GElf_Phdr &header = program_headers[i]; - // For executable, it is the PT_LOAD segment with offset to zero. - if (header.p_type == PT_LOAD && header.p_offset == 0) - return header.p_vaddr; - } - // For other types of ELF, return 0. - return 0; -} - bool WriteFormat(int fd, const char *fmt, ...) { va_list list; char buffer[4096]; @@ -226,9 +265,11 @@ int LoadLineInfo(struct slist *list, do { // Skip non line information. while (cur_list < list_end && cur_list->n_type != N_SLINE) { - // Only exit when got another function, or source file. - if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO) + // Only exit when got another function, or source file, or end stab. + if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || + cur_list->n_type == N_ENDM) { return cur_list - list; + } ++cur_list; } struct LineInfo line; @@ -248,7 +289,7 @@ int LoadLineInfo(struct slist *list, int LoadFuncSymbols(struct slist *list, struct slist *list_end, - const GElf_Shdr *stabstr_section, + char *stabstr, GElf_Word base, struct SourceFileInfo *source_file_info) { struct slist *cur_list = list; @@ -263,18 +304,20 @@ int LoadFuncSymbols(struct slist *list, return cur_list - list; } ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); continue; } while (cur_list->n_type == N_FUN) { struct FuncInfo func_info; memset(&func_info, 0, sizeof(func_info)); - func_info.name = - reinterpret_cast(cur_list->n_strx + - stabstr_section->sh_offset + base); + func_info.name = stabstr + cur_list->n_strx + stringOffset; // The n_value field is always 0 from stab generated by Sun CC. // TODO(Alfred): Find the correct value. func_info.addr = cur_list->n_value; ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && cur_list->n_type != N_FUN) { // Stack parameter size. @@ -282,6 +325,8 @@ int LoadFuncSymbols(struct slist *list, // Line info. cur_list += LoadLineInfo(cur_list, list_end, &func_info); } + if (cur_list < list_end && cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); // Functions in this module should have address bigger than the module // starting address. // @@ -296,48 +341,70 @@ int LoadFuncSymbols(struct slist *list, } // Compute size and rva information based on symbols loaded from stab section. -bool ComputeSizeAndRVA(GElf_Addr loading_addr, struct SymbolInfo *symbols) { +bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { std::vector *sorted_files = &(symbols->source_file_info); + SymbolMap *symbol_entries = &(symbols->symbol_entries); for (size_t i = 0; i < sorted_files->size(); ++i) { struct SourceFileInfo &source_file = (*sorted_files)[i]; std::vector *sorted_functions = &(source_file.func_info); - for (size_t j = 0; j < sorted_functions->size(); ++j) { + int func_size = sorted_functions->size(); + + for (size_t j = 0; j < func_size; ++j) { struct FuncInfo &func_info = (*sorted_functions)[j]; - assert(func_info.addr >= loading_addr); - func_info.rva_to_base = func_info.addr - loading_addr; int line_count = func_info.line_info.size(); - func_info.size = - (line_count == 0) ? 0 : - func_info.line_info[line_count - 1].rva_to_func; + + // Discard the ending part of the name. + std::string func_name(func_info.name); + std::string::size_type last_colon = func_name.find_first_of(':'); + if (last_colon != std::string::npos) + func_name = func_name.substr(0, last_colon); + + // Fine the symbol offset from the loading address and size by name. + SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); + if (it->second) { + func_info.rva_to_base = it->second->offset; + func_info.size = (line_count == 0) ? 0 : it->second->size; + } else { + func_info.rva_to_base = 0; + func_info.size = 0; + } + // Compute function and line size. for (size_t k = 0; k < line_count; ++k) { struct LineInfo &line_info = func_info.line_info[k]; - if (k == 0) { - line_info.size = line_info.rva_to_func; + + line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; + if (k == line_count - 1) { + line_info.size = func_info.size - line_info.rva_to_func; } else { - line_info.size = - line_info.rva_to_func - func_info.line_info[k - 1].rva_to_func; + struct LineInfo &next_line = func_info.line_info[k + 1]; + line_info.size = next_line.rva_to_func - line_info.rva_to_func; } - line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; } // for each line. } // for each function. } // for each source file. + for (SymbolMap::iterator it = symbol_entries->begin(); + it != symbol_entries->end(); ++it) { + free(it->second); + } return true; } bool LoadAllSymbols(const GElf_Shdr *stab_section, const GElf_Shdr *stabstr_section, - GElf_Addr loading_addr, GElf_Word base, struct SymbolInfo *symbols) { if (stab_section == NULL || stabstr_section == NULL) return false; + char *stabstr = + reinterpret_cast(stabstr_section->sh_offset + base); struct slist *lists = reinterpret_cast(stab_section->sh_offset + base); int nstab = stab_section->sh_size / sizeof(struct slist); int source_id = 0; + // First pass, load all symbols from the object file. for (int i = 0; i < nstab; ) { int step = 1; @@ -345,9 +412,7 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section, if (cur_list->n_type == N_SO) { // FUNC
struct SourceFileInfo source_file_info; - source_file_info.name = - reinterpret_cast(cur_list->n_strx + - stabstr_section->sh_offset + base); + source_file_info.name = stabstr + cur_list->n_strx + stringOffset; // The n_value field is always 0 from stab generated by Sun CC. // TODO(Alfred): Find the correct value. source_file_info.addr = cur_list->n_value; @@ -355,22 +420,19 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section, source_file_info.source_id = source_id++; else source_file_info.source_id = -1; - step = LoadFuncSymbols(cur_list, lists + nstab - 1, - stabstr_section, base, &source_file_info); + step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, + base, &source_file_info); symbols->source_file_info.push_back(source_file_info); } i += step; } // Second pass, compute the size of functions and lines. - return ComputeSizeAndRVA(loading_addr, symbols); + return ComputeSizeAndRVA(symbols); } bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, void *obj_base) { GElf_Word base = reinterpret_cast(obj_base); - GElf_Addr loading_addr = GetLoadingAddress( - reinterpret_cast(elf_header->e_phoff + base), - elf_header->e_phnum); const GElf_Shdr *sections = reinterpret_cast(elf_header->e_shoff + base); @@ -386,9 +448,34 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, fprintf(stderr, "Stabstr section not found.\n"); return false; } + GElf_Shdr symtab_section; + if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, + &symtab_section)) { + fprintf(stderr, "Symtab section not found.\n"); + return false; + } + GElf_Shdr strtab_section; + if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, + &strtab_section)) { + fprintf(stderr, "Strtab section not found.\n"); + return false; + } + + Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); + for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { + struct SymbolEntry *symbol_entry = + (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); + const char *name = reinterpret_cast( + strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); + symbol_entry->offset = symbol->st_value; + symbol_entry->size = symbol->st_size; + symbols->symbol_entries.insert(make_pair(name, symbol_entry)); + ++symbol; + } + // Load symbols. - return LoadAllSymbols(&stab_section, &stabstr_section, loading_addr, base, symbols); + return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); } bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { @@ -397,8 +484,12 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { arch_name = "x86"; else if (arch == EM_X86_64) arch_name = "x86_64"; - else + else if (arch == EM_SPARC32PLUS) + arch_name = "SPARC_32+"; + else { + printf("Please add more ARCH support\n"); return false; + } unsigned char identifier[16]; google_breakpad::FileID file_id(obj_file.c_str()); @@ -437,18 +528,20 @@ bool WriteOneFunction(int fd, int source_id, func_name = func_name.substr(0, last_colon); func_name = Demangle(func_name.c_str()); - if (func_info.size < 0) + if (func_info.size <= 0) return true; // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). - if (WriteFormat(fd, "FUNC %llx %d %d %s\n", + if (WriteFormat(fd, "FUNC %llx %x %d %s\n", (long long)func_info.rva_to_base, func_info.size, func_info.stack_param_size, func_name.c_str())) { for (size_t i = 0; i < func_info.line_info.size(); ++i) { const struct LineInfo &line_info = func_info.line_info[i]; - if (!WriteFormat(fd, "%llx %d %d %d\n", + if (line_info.line_num == 0) + return true; + if (!WriteFormat(fd, "%llx %x %d %d\n", (long long)line_info.rva_to_base, line_info.size, line_info.line_num, -- cgit v1.2.1