mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-01-11 17:08:23 +01:00
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
This commit is contained in:
parent
a194d6f1ac
commit
dd2ff4a21c
11 changed files with 689 additions and 336 deletions
|
|
@ -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;
|
||||
} else {
|
||||
line_info.size =
|
||||
line_info.rva_to_func - func_info.line_info[k - 1].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 {
|
||||
struct LineInfo &next_line = func_info.line_info[k + 1];
|
||||
line_info.size = next_line.rva_to_func - line_info.rva_to_func;
|
||||
}
|
||||
} // 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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue