Fix bug of issue 135, now can dump symbols for dynamic libraries.
Also some minor fixes to make it compile with more strict compiling options. git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@133 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
baaeb5af71
commit
ab175ccc2b
5 changed files with 65 additions and 20 deletions
|
@ -107,7 +107,7 @@ static bool MinidumpCallback(const char *dump_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int handler_index = 1;
|
int handler_index = 0;
|
||||||
ExceptionHandler handler_ignore(".", NULL, MinidumpCallback,
|
ExceptionHandler handler_ignore(".", NULL, MinidumpCallback,
|
||||||
(void*)handler_index, true);
|
(void*)handler_index, true);
|
||||||
++handler_index;
|
++handler_index;
|
||||||
|
|
|
@ -297,7 +297,7 @@ int LinuxThread::GetModuleCount() const {
|
||||||
int LinuxThread::ListModules(
|
int LinuxThread::ListModules(
|
||||||
CallbackParam<ModuleCallback> *callback_param) const {
|
CallbackParam<ModuleCallback> *callback_param) const {
|
||||||
char line[512];
|
char line[512];
|
||||||
char *maps_path = "/proc/self/maps";
|
const char *maps_path = "/proc/self/maps";
|
||||||
|
|
||||||
int module_count = 0;
|
int module_count = 0;
|
||||||
FILE *fp = fopen(maps_path, "r");
|
FILE *fp = fopen(maps_path, "r");
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
#include "google_breakpad/common/minidump_format.h"
|
#include "google_breakpad/common/minidump_format.h"
|
||||||
#include "client/linux/handler/minidump_generator.h"
|
#include "client/linux/handler/minidump_generator.h"
|
||||||
|
|
||||||
|
#ifndef CLONE_UNTRACED
|
||||||
|
#define CLONE_UNTRACED 0x00800000
|
||||||
|
#endif
|
||||||
|
|
||||||
// This unnamed namespace contains helper functions.
|
// This unnamed namespace contains helper functions.
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -322,11 +326,11 @@ bool WriteThreadStream(MinidumpFileWriter *minidump_writer,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
||||||
char *proc_cpu_path = "/proc/cpuinfo";
|
const char *proc_cpu_path = "/proc/cpuinfo";
|
||||||
char line[128];
|
char line[128];
|
||||||
|
|
||||||
struct CpuInfoEntry {
|
struct CpuInfoEntry {
|
||||||
char *info_name;
|
const char *info_name;
|
||||||
int value;
|
int value;
|
||||||
} cpu_info_table[] = {
|
} cpu_info_table[] = {
|
||||||
{ "processor", -1 },
|
{ "processor", -1 },
|
||||||
|
@ -384,7 +388,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
|
||||||
char os_version[512];
|
char os_version[512];
|
||||||
size_t space_left = sizeof(os_version);
|
size_t space_left = sizeof(os_version);
|
||||||
memset(os_version, 0, space_left);
|
memset(os_version, 0, space_left);
|
||||||
char *os_info_table[] = {
|
const char *os_info_table[] = {
|
||||||
uts.sysname,
|
uts.sysname,
|
||||||
uts.release,
|
uts.release,
|
||||||
uts.version,
|
uts.version,
|
||||||
|
@ -392,7 +396,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
|
||||||
"GNU/Linux",
|
"GNU/Linux",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
for (char **cur_os_info = os_info_table;
|
for (const char **cur_os_info = os_info_table;
|
||||||
*cur_os_info != NULL;
|
*cur_os_info != NULL;
|
||||||
cur_os_info++) {
|
cur_os_info++) {
|
||||||
if (cur_os_info != os_info_table && space_left > 1) {
|
if (cur_os_info != os_info_table && space_left > 1) {
|
||||||
|
@ -472,7 +476,8 @@ bool WriteThreadListStream(MinidumpFileWriter *minidump_writer,
|
||||||
context.thread_index = 0;
|
context.thread_index = 0;
|
||||||
CallbackParam<ThreadCallback> callback_param(ThreadInfomationCallback,
|
CallbackParam<ThreadCallback> callback_param(ThreadInfomationCallback,
|
||||||
&context);
|
&context);
|
||||||
return thread_lister->ListThreads(&callback_param) == thread_count;
|
int written = thread_lister->ListThreads(&callback_param);
|
||||||
|
return written == thread_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
||||||
|
@ -481,7 +486,7 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
||||||
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
|
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
|
||||||
|
|
||||||
// Only return the last path component of the full module path
|
// Only return the last path component of the full module path
|
||||||
char *module_name = strrchr(module_path, '/');
|
const char *module_name = strrchr(module_path, '/');
|
||||||
// Increment past the slash
|
// Increment past the slash
|
||||||
if (module_name)
|
if (module_name)
|
||||||
++module_name;
|
++module_name;
|
||||||
|
@ -491,11 +496,13 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
||||||
size_t module_name_length = strlen(module_name);
|
size_t module_name_length = strlen(module_name);
|
||||||
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
|
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
|
||||||
return false;
|
return false;
|
||||||
if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
|
if (!cv.CopyIndexAfterObject(0, const_cast<char *>(module_name),
|
||||||
|
module_name_length))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
module->cv_record = cv.location();
|
module->cv_record = cv.location();
|
||||||
MDCVInfoPDB70 *cv_ptr = cv.get();
|
MDCVInfoPDB70 *cv_ptr = cv.get();
|
||||||
|
memset(cv_ptr, 0, sizeof(MDCVInfoPDB70));
|
||||||
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
|
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
|
||||||
cv_ptr->age = 0;
|
cv_ptr->age = 0;
|
||||||
|
|
||||||
|
@ -517,9 +524,8 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
||||||
cv_ptr->signature.data4[5] = identifier[13];
|
cv_ptr->signature.data4[5] = identifier[13];
|
||||||
cv_ptr->signature.data4[6] = identifier[14];
|
cv_ptr->signature.data4[6] = identifier[14];
|
||||||
cv_ptr->signature.data4[7] = identifier[15];
|
cv_ptr->signature.data4[7] = identifier[15];
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleInfoCallbackCtx {
|
struct ModuleInfoCallbackCtx {
|
||||||
|
|
|
@ -138,15 +138,15 @@ void FixAddress(void *obj_base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the prefered loading address of the binary.
|
// Find the prefered loading address of the binary.
|
||||||
// It is the PT_LOAD segment with offset to zero.
|
|
||||||
ElfW(Addr) GetLoadingAddress(const ElfW(Phdr) *program_headers, int nheader) {
|
ElfW(Addr) GetLoadingAddress(const ElfW(Phdr) *program_headers, int nheader) {
|
||||||
for (int i = 0; i < nheader; ++i) {
|
for (int i = 0; i < nheader; ++i) {
|
||||||
const ElfW(Phdr) &header = program_headers[i];
|
const ElfW(Phdr) &header = program_headers[i];
|
||||||
|
// For executable, it is the PT_LOAD segment with offset to zero.
|
||||||
if (header.p_type == PT_LOAD &&
|
if (header.p_type == PT_LOAD &&
|
||||||
header.p_offset == 0)
|
header.p_offset == 0)
|
||||||
return header.p_vaddr;
|
return header.p_vaddr;
|
||||||
}
|
}
|
||||||
assert(!"Should get a valid loading address");
|
// For other types of ELF, return 0.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +263,8 @@ int LoadFuncSymbols(struct nlist *list,
|
||||||
cur_list += LoadLineInfo(cur_list, list_end, &func_info);
|
cur_list += LoadLineInfo(cur_list, list_end, &func_info);
|
||||||
// Functions in this module should have address bigger than the module
|
// Functions in this module should have address bigger than the module
|
||||||
// startring address.
|
// startring address.
|
||||||
|
// There maybe a lot of duplicated entry for a function in the symbol,
|
||||||
|
// only one of them can met this.
|
||||||
if (func_info.addr >= source_file_info->addr) {
|
if (func_info.addr >= source_file_info->addr) {
|
||||||
source_file_info->func_info.push_back(func_info);
|
source_file_info->func_info.push_back(func_info);
|
||||||
}
|
}
|
||||||
|
@ -344,10 +346,40 @@ bool ComputeSizeAndRVA(ElfW(Addr) loading_addr, struct SymbolInfo *symbols) {
|
||||||
ElfW(Addr) next_addr = NextAddress(&sorted_functions,
|
ElfW(Addr) next_addr = NextAddress(&sorted_functions,
|
||||||
&sorted_files,
|
&sorted_files,
|
||||||
func_info);
|
func_info);
|
||||||
if (next_addr == 0)
|
// I've noticed functions with an address bigger than any other functions
|
||||||
continue;
|
// and source files modules, this is probably the last function in the
|
||||||
func_info.size = next_addr - func_info.addr;
|
// module, due to limitions of Linux stab symbol, it is impossible to get
|
||||||
|
// the exact size of this kind of function, thus we give it a default
|
||||||
|
// very big value. This should be safe since this is the last function.
|
||||||
|
// But it is a ugly hack.....
|
||||||
|
// The following code can reproduce the case:
|
||||||
|
// template<class T>
|
||||||
|
// void Foo(T value) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int main(void) {
|
||||||
|
// Foo(10);
|
||||||
|
// Foo(std::string("hello"));
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
// TODO(liuli): Find a better solution.
|
||||||
|
static const int kDefaultSize = 0x10000000;
|
||||||
|
static int no_next_addr_count = 0;
|
||||||
|
if (next_addr != 0) {
|
||||||
|
func_info.size = next_addr - func_info.addr;
|
||||||
|
} else {
|
||||||
|
if (no_next_addr_count > 1) {
|
||||||
|
fprintf(stderr, "Got more than one funtion without the \
|
||||||
|
following symbol. Igore this function.\n");
|
||||||
|
fprintf(stderr, "The dumped symbol may not correct.\n");
|
||||||
|
assert(!"This should not happen!\n");
|
||||||
|
func_info.size = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
no_next_addr_count++;
|
||||||
|
func_info.size = kDefaultSize;
|
||||||
|
}
|
||||||
// Compute line size.
|
// Compute line size.
|
||||||
for (size_t k = 0; k < func_info.line_info.size(); ++k) {
|
for (size_t k = 0; k < func_info.line_info.size(); ++k) {
|
||||||
struct LineInfo &line_info = func_info.line_info[k];
|
struct LineInfo &line_info = func_info.line_info[k];
|
||||||
|
@ -356,9 +388,18 @@ bool ComputeSizeAndRVA(ElfW(Addr) loading_addr, struct SymbolInfo *symbols) {
|
||||||
line_info.size =
|
line_info.size =
|
||||||
func_info.line_info[k + 1].rva_to_func - line_info.rva_to_func;
|
func_info.line_info[k + 1].rva_to_func - line_info.rva_to_func;
|
||||||
} else {
|
} else {
|
||||||
|
// The last line in the function.
|
||||||
|
// If we can find a function or source file symbol immediately
|
||||||
|
// following the line, we can get the size of the line by computing
|
||||||
|
// the difference of the next address to the starting address of this
|
||||||
|
// line.
|
||||||
|
// Otherwise, we need to set a default big enough value. This occurs
|
||||||
|
// mostly because the this function is the last one in the module.
|
||||||
if (next_addr != 0) {
|
if (next_addr != 0) {
|
||||||
ElfW(Off) next_addr_offset = next_addr - func_info.addr;
|
ElfW(Off) next_addr_offset = next_addr - func_info.addr;
|
||||||
line_info.size = next_addr_offset - line_info.rva_to_func;
|
line_info.size = next_addr_offset - line_info.rva_to_func;
|
||||||
|
} else {
|
||||||
|
line_info.size = kDefaultSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
|
line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
|
||||||
|
@ -409,8 +450,6 @@ bool LoadSymbols(ElfW(Ehdr) *elf_header, struct SymbolInfo *symbols) {
|
||||||
ElfW(Addr) loading_addr = GetLoadingAddress(
|
ElfW(Addr) loading_addr = GetLoadingAddress(
|
||||||
reinterpret_cast<ElfW(Phdr) *>(elf_header->e_phoff),
|
reinterpret_cast<ElfW(Phdr) *>(elf_header->e_phoff),
|
||||||
elf_header->e_phnum);
|
elf_header->e_phnum);
|
||||||
if (loading_addr == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const ElfW(Shdr) *sections =
|
const ElfW(Shdr) *sections =
|
||||||
reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
|
reinterpret_cast<ElfW(Shdr) *>(elf_header->e_shoff);
|
||||||
|
|
|
@ -31,11 +31,11 @@
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
#include "common/string_conversion.h"
|
#include "common/string_conversion.h"
|
||||||
|
|
||||||
|
namespace google_breakpad {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
namespace google_breakpad {
|
|
||||||
|
|
||||||
void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
|
void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
|
||||||
size_t source_length = strlen(in);
|
size_t source_length = strlen(in);
|
||||||
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
|
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
|
||||||
|
|
Loading…
Reference in a new issue