aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2008-03-18 16:10:10 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2008-03-18 16:10:10 +0000
commitdd2ff4a21c57672170eb14ccc5142efd7d92f3f1 (patch)
tree0d8ced3d3cd41773a89aae46a9b269ebd29935a1 /src/common
parentIssue 245: refactoring minidump_format.h into architecture & platform specifi... (diff)
downloadbreakpad-dd2ff4a21c57672170eb14ccc5142efd7d92f3f1.tar.xz
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
Diffstat (limited to 'src/common')
-rw-r--r--src/common/solaris/dump_symbols.cc187
1 files changed, 140 insertions, 47 deletions
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 <unistd.h>
#include <functional>
+#include <map>
#include <vector>
#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<struct FuncInfo> func_info;
};
+struct CompareString {
+ bool operator()(const char *s1, const char *s2) const {
+ return strcmp(s1, s2) < 0;
+ }
+};
+
+typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap;
+
// Information of a symbol table.
// This is the root of all types of symbol.
struct SymbolInfo {
std::vector<struct SourceFileInfo> 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<char *>(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<struct SourceFileInfo> *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<struct FuncInfo> *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<char *>(stabstr_section->sh_offset + base);
struct slist *lists =
reinterpret_cast<struct slist *>(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 <address> <size> <param_stack_size> <function>
struct SourceFileInfo source_file_info;
- source_file_info.name =
- reinterpret_cast<char *>(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<GElf_Word>(obj_base);
- GElf_Addr loading_addr = GetLoadingAddress(
- reinterpret_cast<GElf_Phdr *>(elf_header->e_phoff + base),
- elf_header->e_phnum);
const GElf_Shdr *sections =
reinterpret_cast<GElf_Shdr *>(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<char *>(
+ 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,