Modify symbol supplier interface to support an overload that takes a symbol data buffer, to get around an extraneous read/write of symbol data
R=doshimun git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@311 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
a285652cba
commit
0fd2f1ae21
@ -69,6 +69,12 @@ class BasicSourceLineResolver : public SourceLineResolverInterface {
|
|||||||
// retained until the BasicSourceLineResolver is destroyed.
|
// retained until the BasicSourceLineResolver is destroyed.
|
||||||
virtual bool LoadModule(const string &module_name, const string &map_file);
|
virtual bool LoadModule(const string &module_name, const string &map_file);
|
||||||
|
|
||||||
|
// Exactly the same as above, except the given map_buffer is used
|
||||||
|
// for symbols.
|
||||||
|
virtual bool LoadModuleUsingMapBuffer(const string &module_name,
|
||||||
|
const string &map_buffer);
|
||||||
|
|
||||||
|
|
||||||
virtual bool HasModule(const string &module_name) const;
|
virtual bool HasModule(const string &module_name) const;
|
||||||
|
|
||||||
virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const;
|
virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const;
|
||||||
|
@ -56,6 +56,9 @@ class SourceLineResolverInterface {
|
|||||||
// map_file should contain line/address mappings for this module.
|
// map_file should contain line/address mappings for this module.
|
||||||
virtual bool LoadModule(const string &module_name,
|
virtual bool LoadModule(const string &module_name,
|
||||||
const string &map_file) = 0;
|
const string &map_file) = 0;
|
||||||
|
// Same as above, but takes the contents of a pre-read map buffer
|
||||||
|
virtual bool LoadModuleUsingMapBuffer(const string &module_name,
|
||||||
|
const string &map_buffer) = 0;
|
||||||
|
|
||||||
// Returns true if a module with the given name has been loaded.
|
// Returns true if a module with the given name has been loaded.
|
||||||
virtual bool HasModule(const string &module_name) const = 0;
|
virtual bool HasModule(const string &module_name) const = 0;
|
||||||
|
@ -59,12 +59,22 @@ class SymbolSupplier {
|
|||||||
|
|
||||||
// Retrieves the symbol file for the given CodeModule, placing the
|
// Retrieves the symbol file for the given CodeModule, placing the
|
||||||
// path in symbol_file if successful. system_info contains strings
|
// path in symbol_file if successful. system_info contains strings
|
||||||
// identifying the operating system and CPU; SymbolSupplier may use to help
|
// identifying the operating system and CPU; SymbolSupplier may use
|
||||||
// locate the symbol file. system_info may be NULL or its fields may be
|
// to help locate the symbol file. system_info may be NULL or its
|
||||||
// empty if these values are unknown.
|
// fields may be empty if these values are unknown. symbol_file
|
||||||
|
// must be a pointer to a valid string
|
||||||
virtual SymbolResult GetSymbolFile(const CodeModule *module,
|
virtual SymbolResult GetSymbolFile(const CodeModule *module,
|
||||||
const SystemInfo *system_info,
|
const SystemInfo *system_info,
|
||||||
string *symbol_file) = 0;
|
string *symbol_file) = 0;
|
||||||
|
// Same as above, except also places symbol data into symbol_data.
|
||||||
|
// If symbol_data is NULL, the data is not returned.
|
||||||
|
// TODO(nealsid) Once we have symbol data caching behavior implemented
|
||||||
|
// investigate making all symbol suppliers implement all methods,
|
||||||
|
// and make this pure virtual
|
||||||
|
virtual SymbolResult GetSymbolFile(const CodeModule *module,
|
||||||
|
const SystemInfo *system_info,
|
||||||
|
string *symbol_file,
|
||||||
|
string *symbol_data) { assert(0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -106,9 +109,13 @@ class BasicSourceLineResolver::Module {
|
|||||||
public:
|
public:
|
||||||
Module(const string &name) : name_(name) { }
|
Module(const string &name) : name_(name) { }
|
||||||
|
|
||||||
// Loads the given map file, returning true on success.
|
// Loads the given map file, returning true on success. Reads the
|
||||||
|
// map file into memory and calls LoadMapFromBuffer
|
||||||
bool LoadMap(const string &map_file);
|
bool LoadMap(const string &map_file);
|
||||||
|
|
||||||
|
// Loads a map from the given buffer, returning true on success
|
||||||
|
bool LoadMapFromBuffer(const string &map_buffer);
|
||||||
|
|
||||||
// Looks up the given relative address, and fills the StackFrame struct
|
// Looks up the given relative address, and fills the StackFrame struct
|
||||||
// with the result. Additional debugging information, if available, is
|
// with the result. Additional debugging information, if available, is
|
||||||
// returned. If no additional information is available, returns NULL.
|
// returned. If no additional information is available, returns NULL.
|
||||||
@ -211,6 +218,27 @@ bool BasicSourceLineResolver::LoadModule(const string &module_name,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BasicSourceLineResolver::LoadModuleUsingMapBuffer(
|
||||||
|
const string &module_name,
|
||||||
|
const string &map_buffer) {
|
||||||
|
// Make sure we don't already have a module with the given name.
|
||||||
|
if (modules_->find(module_name) != modules_->end()) {
|
||||||
|
BPLOG(INFO) << "Symbols for module " << module_name << " already loaded";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPLOG(INFO) << "Loading symbols for module " << module_name << " from buffer";
|
||||||
|
|
||||||
|
Module *module = new Module(module_name);
|
||||||
|
if (!module->LoadMapFromBuffer(map_buffer)) {
|
||||||
|
delete module;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
modules_->insert(make_pair(module_name, module));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool BasicSourceLineResolver::HasModule(const string &module_name) const {
|
bool BasicSourceLineResolver::HasModule(const string &module_name) const {
|
||||||
return modules_->find(module_name) != modules_->end();
|
return modules_->find(module_name) != modules_->end();
|
||||||
}
|
}
|
||||||
@ -238,44 +266,56 @@ class AutoFileCloser {
|
|||||||
FILE *file_;
|
FILE *file_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
bool BasicSourceLineResolver::Module::LoadMapFromBuffer(
|
||||||
FILE *f = fopen(map_file.c_str(), "r");
|
const string &map_buffer) {
|
||||||
if (!f) {
|
linked_ptr<Function> cur_func;
|
||||||
string error_string;
|
int line_number = 0;
|
||||||
int error_code = ErrnoString(&error_string);
|
const char *map_buffer_c_str = map_buffer.c_str();
|
||||||
BPLOG(ERROR) << "Could not open " << map_file <<
|
char *save_ptr;
|
||||||
", error " << error_code << ": " << error_string;
|
|
||||||
|
// set up our input buffer as a c-style string so we
|
||||||
|
// can we use strtok()
|
||||||
|
// have to copy because modifying the result of string::c_str is not
|
||||||
|
// permitted
|
||||||
|
size_t map_buffer_length = strlen(map_buffer_c_str);
|
||||||
|
char *map_buffer_chars = new char[map_buffer_length];
|
||||||
|
if (map_buffer_chars == NULL) {
|
||||||
|
BPLOG(ERROR) << "Memory allocation of " << map_buffer_length <<
|
||||||
|
" bytes failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoFileCloser closer(f);
|
strncpy(map_buffer_chars, map_buffer_c_str, map_buffer_length);
|
||||||
|
|
||||||
// TODO(mmentovai): this might not be large enough to handle really long
|
if (map_buffer_chars[map_buffer_length - 1] == '\n') {
|
||||||
// lines, which might be present for FUNC lines of highly-templatized
|
map_buffer_chars[map_buffer_length - 1] = '\0';
|
||||||
// code.
|
}
|
||||||
char buffer[8192];
|
char *buffer;
|
||||||
linked_ptr<Function> cur_func;
|
buffer = strtok_r(map_buffer_chars, "\r\n", &save_ptr);
|
||||||
|
|
||||||
int line_number = 0;
|
while (buffer != NULL) {
|
||||||
while (fgets(buffer, sizeof(buffer), f)) {
|
|
||||||
++line_number;
|
++line_number;
|
||||||
|
|
||||||
if (strncmp(buffer, "FILE ", 5) == 0) {
|
if (strncmp(buffer, "FILE ", 5) == 0) {
|
||||||
if (!ParseFile(buffer)) {
|
if (!ParseFile(buffer)) {
|
||||||
BPLOG(ERROR) << "ParseFile failed at " <<
|
BPLOG(ERROR) << "ParseFile on buffer failed at " <<
|
||||||
map_file << ":" << line_number;
|
":" << line_number;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (strncmp(buffer, "STACK ", 6) == 0) {
|
} else if (strncmp(buffer, "STACK ", 6) == 0) {
|
||||||
if (!ParseStackInfo(buffer)) {
|
if (!ParseStackInfo(buffer)) {
|
||||||
BPLOG(ERROR) << "ParseStackInfo failed at " <<
|
BPLOG(ERROR) << "ParseStackInfo failed at " <<
|
||||||
map_file << ":" << line_number;
|
":" << line_number;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (strncmp(buffer, "FUNC ", 5) == 0) {
|
} else if (strncmp(buffer, "FUNC ", 5) == 0) {
|
||||||
cur_func.reset(ParseFunction(buffer));
|
cur_func.reset(ParseFunction(buffer));
|
||||||
if (!cur_func.get()) {
|
if (!cur_func.get()) {
|
||||||
BPLOG(ERROR) << "ParseFunction failed at " <<
|
BPLOG(ERROR) << "ParseFunction failed at " <<
|
||||||
map_file << ":" << line_number;
|
":" << line_number;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// StoreRange will fail if the function has an invalid address or size.
|
// StoreRange will fail if the function has an invalid address or size.
|
||||||
@ -288,7 +328,8 @@ bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
|||||||
|
|
||||||
if (!ParsePublicSymbol(buffer)) {
|
if (!ParsePublicSymbol(buffer)) {
|
||||||
BPLOG(ERROR) << "ParsePublicSymbol failed at " <<
|
BPLOG(ERROR) << "ParsePublicSymbol failed at " <<
|
||||||
map_file << ":" << line_number;
|
":" << line_number;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
|
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
|
||||||
@ -301,23 +342,82 @@ bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
|||||||
} else {
|
} else {
|
||||||
if (!cur_func.get()) {
|
if (!cur_func.get()) {
|
||||||
BPLOG(ERROR) << "Found source line data without a function at " <<
|
BPLOG(ERROR) << "Found source line data without a function at " <<
|
||||||
map_file << ":" << line_number;
|
":" << line_number;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Line *line = ParseLine(buffer);
|
Line *line = ParseLine(buffer);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
BPLOG(ERROR) << "ParseLine failed at " <<
|
BPLOG(ERROR) << "ParseLine failed at " << line_number << " for " <<
|
||||||
map_file << ":" << line_number;
|
buffer;
|
||||||
|
delete [] map_buffer_chars;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cur_func->lines.StoreRange(line->address, line->size,
|
cur_func->lines.StoreRange(line->address, line->size,
|
||||||
linked_ptr<Line>(line));
|
linked_ptr<Line>(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer = strtok_r(NULL, "\r\n", &save_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
||||||
|
struct stat buf;
|
||||||
|
int error_code = stat(map_file.c_str(), &buf);
|
||||||
|
if (error_code == -1) {
|
||||||
|
string error_string;
|
||||||
|
int error_code = ErrnoString(&error_string);
|
||||||
|
BPLOG(ERROR) << "Could not open " << map_file <<
|
||||||
|
", error " << error_code << ": " << error_string;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t file_size = buf.st_size;
|
||||||
|
|
||||||
|
// Allocate memory for file contents, plus a null terminator
|
||||||
|
// since we'll use strtok() on the contents.
|
||||||
|
char *file_buffer = new char[sizeof(char)*file_size + 1];
|
||||||
|
|
||||||
|
if (file_buffer == NULL) {
|
||||||
|
BPLOG(ERROR) << "Could not allocate memory for " << map_file;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPLOG(ERROR) << "Opening " << map_file;
|
||||||
|
|
||||||
|
FILE *f = fopen(map_file.c_str(), "rt");
|
||||||
|
if (!f) {
|
||||||
|
string error_string;
|
||||||
|
int error_code = ErrnoString(&error_string);
|
||||||
|
BPLOG(ERROR) << "Could not open " << map_file <<
|
||||||
|
", error " << error_code << ": " << error_string;
|
||||||
|
delete [] file_buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoFileCloser closer(f);
|
||||||
|
|
||||||
|
int items_read = 0;
|
||||||
|
|
||||||
|
items_read = fread(file_buffer, 1, file_size, f);
|
||||||
|
|
||||||
|
if (items_read != file_size) {
|
||||||
|
string error_string;
|
||||||
|
int error_code = ErrnoString(&error_string);
|
||||||
|
BPLOG(ERROR) << "Could not slurp " << map_file <<
|
||||||
|
", error " << error_code << ": " << error_string;
|
||||||
|
delete [] file_buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
file_buffer[file_size] = '\0';
|
||||||
|
string map_buffer(file_buffer);
|
||||||
|
delete [] file_buffer;
|
||||||
|
|
||||||
|
return LoadMapFromBuffer(map_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
StackFrameInfo* BasicSourceLineResolver::Module::LookupAddress(
|
StackFrameInfo* BasicSourceLineResolver::Module::LookupAddress(
|
||||||
StackFrame *frame) const {
|
StackFrame *frame) const {
|
||||||
MemAddr address = frame->instruction - frame->module->base_address();
|
MemAddr address = frame->instruction - frame->module->base_address();
|
||||||
|
@ -62,15 +62,16 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
|
|||||||
|
|
||||||
for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) {
|
for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) {
|
||||||
SymbolResult result;
|
SymbolResult result;
|
||||||
if ((result = GetSymbolFileAtPath(module, system_info, paths_[path_index],
|
if ((result = GetSymbolFileAtPathFromRoot(module, system_info,
|
||||||
symbol_file)) != NOT_FOUND) {
|
paths_[path_index],
|
||||||
|
symbol_file)) != NOT_FOUND) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath(
|
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot(
|
||||||
const CodeModule *module, const SystemInfo *system_info,
|
const CodeModule *module, const SystemInfo *system_info,
|
||||||
const string &root_path, string *symbol_file) {
|
const string &root_path, string *symbol_file) {
|
||||||
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath "
|
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath "
|
||||||
|
@ -102,15 +102,19 @@ class SimpleSymbolSupplier : public SymbolSupplier {
|
|||||||
|
|
||||||
// Returns the path to the symbol file for the given module. See the
|
// Returns the path to the symbol file for the given module. See the
|
||||||
// description above.
|
// description above.
|
||||||
SymbolResult GetSymbolFile(const CodeModule *module,
|
virtual SymbolResult GetSymbolFile(const CodeModule *module,
|
||||||
const SystemInfo *system_info,
|
const SystemInfo *system_info,
|
||||||
string *symbol_file);
|
string *symbol_file);
|
||||||
|
|
||||||
|
virtual SymbolResult GetSymbolFile(const CodeModule *module,
|
||||||
|
const SystemInfo *system_info,
|
||||||
|
string *symbol_file,
|
||||||
|
string *symbol_data) { assert(0); }
|
||||||
protected:
|
protected:
|
||||||
SymbolResult GetSymbolFileAtPath(const CodeModule *module,
|
SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module,
|
||||||
const SystemInfo *system_info,
|
const SystemInfo *system_info,
|
||||||
const string &root_path,
|
const string &root_path,
|
||||||
string *symbol_file);
|
string *symbol_file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<string> paths_;
|
vector<string> paths_;
|
||||||
|
@ -101,13 +101,15 @@ bool Stackwalker::Walk(CallStack *stack) {
|
|||||||
if (resolver_ &&
|
if (resolver_ &&
|
||||||
!resolver_->HasModule(frame->module->code_file()) &&
|
!resolver_->HasModule(frame->module->code_file()) &&
|
||||||
supplier_) {
|
supplier_) {
|
||||||
string symbol_file;
|
string symbol_data, symbol_file;
|
||||||
SymbolSupplier::SymbolResult symbol_result =
|
SymbolSupplier::SymbolResult symbol_result =
|
||||||
supplier_->GetSymbolFile(module, system_info_, &symbol_file);
|
supplier_->GetSymbolFile(module, system_info_,
|
||||||
|
&symbol_file, &symbol_data);
|
||||||
|
|
||||||
switch (symbol_result) {
|
switch (symbol_result) {
|
||||||
case SymbolSupplier::FOUND:
|
case SymbolSupplier::FOUND:
|
||||||
resolver_->LoadModule(frame->module->code_file(), symbol_file);
|
resolver_->LoadModuleUsingMapBuffer(frame->module->code_file(),
|
||||||
|
symbol_data);
|
||||||
break;
|
break;
|
||||||
case SymbolSupplier::NOT_FOUND:
|
case SymbolSupplier::NOT_FOUND:
|
||||||
break; // nothing to do
|
break; // nothing to do
|
||||||
|
Loading…
Reference in New Issue
Block a user