Add PUBLIC support to SourceLineResolver (resolve function names in Windows

system libraries) (#53)
StackFrame::function_base is not populated (#49)
r=bryner

http://groups.google.com/group/airbag-dev/browse_thread/thread/a17d35348e7027bb


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@43 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
mmentovai 2006-10-20 19:50:01 +00:00
parent 246f406828
commit 2fc823f579
15 changed files with 638 additions and 32 deletions

View file

@ -34,6 +34,7 @@
#include <utility>
#include "processor/source_line_resolver.h"
#include "google/stack_frame.h"
#include "processor/address_map-inl.h"
#include "processor/contained_range_map-inl.h"
#include "processor/linked_ptr.h"
#include "processor/range_map-inl.h"
@ -77,6 +78,23 @@ struct SourceLineResolver::Function {
RangeMap< MemAddr, linked_ptr<Line> > lines;
};
struct SourceLineResolver::PublicSymbol {
PublicSymbol(const string& set_name,
MemAddr set_address,
int set_parameter_size)
: name(set_name),
address(set_address),
parameter_size(set_parameter_size) {}
string name;
MemAddr address;
// If the public symbol is used as a function entry point, parameter_size
// is set to the size of the parameters passed to the funciton on the
// stack, if known.
int parameter_size;
};
class SourceLineResolver::Module {
public:
Module(const string &name) : name_(name) { }
@ -129,12 +147,17 @@ class SourceLineResolver::Module {
// Parses a line declaration, returning a new Line object.
Line* ParseLine(char *line_line);
// Parses a PUBLIC symbol declaration, storing it in public_symbols_.
// Returns false if an error occurs.
bool ParsePublicSymbol(char *public_line);
// Parses a stack frame info declaration, storing it in stack_info_.
bool ParseStackInfo(char *stack_info_line);
string name_;
FileMap files_;
RangeMap< MemAddr, linked_ptr<Function> > functions_;
AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_;
// Each element in the array is a ContainedRangeMap for a type listed in
// StackInfoTypes. These are split by type because there may be overlaps
@ -208,10 +231,17 @@ bool SourceLineResolver::Module::LoadMap(const string &map_file) {
if (!cur_func) {
return false;
}
functions_.StoreRange(cur_func->address, cur_func->size,
linked_ptr<Function>(cur_func));
if (!functions_.StoreRange(cur_func->address, cur_func->size,
linked_ptr<Function>(cur_func))) {
return false;
}
} else if (strncmp(buffer, "PUBLIC ", 7) == 0) {
// TODO(mmentovai): add a public map
// Clear cur_func: public symbols don't contain line number information.
cur_func = NULL;
if (!ParsePublicSymbol(buffer)) {
return false;
}
} else {
if (!cur_func) {
return false;
@ -248,30 +278,62 @@ void SourceLineResolver::Module::LookupAddress(
}
}
// First, look for a matching FUNC range. Use RetrieveNearestRange instead
// of RetrieveRange so that the nearest function can be compared to the
// nearest PUBLIC symbol if the address does not lie within the function.
// Having access to the highest function below address, even when address
// is outside of the function, is useful: if the function is higher than
// the nearest PUBLIC symbol, then it means that the PUBLIC symbols is not
// valid for the address, and no function information should be filled in.
// Using RetrieveNearestRange instead of RetrieveRange means that we need
// to verify that address is within the range before using a FUNC.
//
// If no FUNC containing the address is found, look for the nearest PUBLIC
// symbol, being careful not to use a public symbol at a lower address than
// the nearest FUNC.
int parameter_size = 0;
linked_ptr<Function> func;
if (!functions_.RetrieveRange(address, &func)) {
linked_ptr<PublicSymbol> public_symbol;
MemAddr function_base;
MemAddr function_size;
MemAddr public_address;
if (functions_.RetrieveNearestRange(address, &func,
&function_base, &function_size) &&
address >= function_base && address < function_base + function_size) {
parameter_size = func->parameter_size;
frame->function_name = func->name;
frame->function_base = frame->module_base + function_base;
linked_ptr<Line> line;
MemAddr line_base;
if (func->lines.RetrieveRange(address, &line, &line_base, NULL)) {
FileMap::const_iterator it = files_.find(line->source_file_id);
if (it != files_.end()) {
frame->source_file_name = files_.find(line->source_file_id)->second;
}
frame->source_line = line->line;
frame->source_line_base = frame->module_base + line_base;
}
} else if (public_symbols_.Retrieve(address,
&public_symbol, &public_address) &&
(!func.get() || public_address > function_base + function_size)) {
parameter_size = public_symbol->parameter_size;
frame->function_name = public_symbol->name;
frame->function_base = frame->module_base + public_address;
} else {
// No FUNC or PUBLIC data available.
return;
}
frame->function_name = func->name;
linked_ptr<Line> line;
if (!func->lines.RetrieveRange(address, &line)) {
return;
}
FileMap::const_iterator it = files_.find(line->source_file_id);
if (it != files_.end()) {
frame->source_file_name = files_.find(line->source_file_id)->second;
}
frame->source_line = line->line;
if (frame_info &&
!(frame_info->valid & StackFrameInfo::VALID_PARAMETER_SIZE)) {
// Even without a relevant STACK line, many functions contain information
// about how much space their parameters consume on the stack. Prefer
// the STACK stuff (above), but if it's not present, take the
// information from the FUNC line.
frame_info->parameter_size = func->parameter_size;
// information from the FUNC or PUBLIC line.
frame_info->parameter_size = parameter_size;
frame_info->valid |= StackFrameInfo::VALID_PARAMETER_SIZE;
}
}
@ -325,7 +387,7 @@ void SourceLineResolver::Module::ParseFile(char *file_line) {
SourceLineResolver::Function* SourceLineResolver::Module::ParseFunction(
char *function_line) {
// FUNC <address> <stack_param_size> <name>
// FUNC <address> <size> <stack_param_size> <name>
function_line += 5; // skip prefix
vector<char*> tokens;
@ -360,6 +422,36 @@ SourceLineResolver::Line* SourceLineResolver::Module::ParseLine(
return new Line(address, size, source_file, line_number);
}
bool SourceLineResolver::Module::ParsePublicSymbol(char *public_line) {
// PUBLIC <address> <stack_param_size> <name>
// Skip "PUBLIC " prefix.
public_line += 7;
vector<char*> tokens;
if (!Tokenize(public_line, 3, &tokens)) {
return false;
}
u_int64_t address = strtoull(tokens[0], NULL, 16);
int stack_param_size = strtoull(tokens[1], NULL, 16);
char *name = tokens[2];
// A few public symbols show up with an address of 0. This has been seen
// in the dumped output of ntdll.pdb for symbols such as _CIlog, _CIpow,
// RtlDescribeChunkLZNT1, and RtlReserveChunkLZNT1. They would conflict
// with one another if they were allowed into the public_symbols_ map,
// but since the address is obviously invalid, gracefully accept them
// as input without putting them into the map.
if (address == 0) {
return true;
}
linked_ptr<PublicSymbol> symbol(new PublicSymbol(name, address,
stack_param_size));
return public_symbols_.Store(address, symbol);
}
bool SourceLineResolver::Module::ParseStackInfo(char *stack_info_line) {
// STACK WIN <type> <rva> <code_size> <prolog_size> <epliog_size>
// <parameter_size> <saved_register_size> <local_size> <max_stack_size>