diff options
author | mmentovai <mmentovai@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2006-10-20 01:46:38 +0000 |
---|---|---|
committer | mmentovai <mmentovai@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2006-10-20 01:46:38 +0000 |
commit | 246f4068280b5b191303ff13671e43a0522987de (patch) | |
tree | 9de2b66c7d8f0241de53669de045318d6283da7e /src/processor/source_line_resolver.cc | |
parent | Improvements for Windows client/tool-side code. r=bryner (diff) | |
download | breakpad-246f4068280b5b191303ff13671e43a0522987de.tar.xz |
Handle frame pointer omission, (#21), part 4 (final part!): FPO stackwalker.
r=bryner
- This change allows Airbag to properly walk win32 stacks produced by code
built with MSVC's frame pointer omission optimization (/Oy). This
optimization is enabled at /O1 and /O2.
- There too many interface and file format changes to list here.
http://groups.google.com/group/airbag-dev/browse_thread/thread/85ce85bfa8457ece
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@42 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor/source_line_resolver.cc')
-rw-r--r-- | src/processor/source_line_resolver.cc | 97 |
1 files changed, 68 insertions, 29 deletions
diff --git a/src/processor/source_line_resolver.cc b/src/processor/source_line_resolver.cc index 6d5f219c..3c612c75 100644 --- a/src/processor/source_line_resolver.cc +++ b/src/processor/source_line_resolver.cc @@ -62,13 +62,19 @@ struct SourceLineResolver::Line { struct SourceLineResolver::Function { Function(const string &function_name, MemAddr function_address, - MemAddr code_size) - : name(function_name), address(function_address), size(code_size) { } + MemAddr code_size, + int set_parameter_size) + : name(function_name), address(function_address), size(code_size), + parameter_size(set_parameter_size) { } string name; MemAddr address; MemAddr size; - RangeMap<MemAddr, linked_ptr<Line> > lines; + + // The size of parameters passed to this function on the stack. + int parameter_size; + + RangeMap< MemAddr, linked_ptr<Line> > lines; }; class SourceLineResolver::Module { @@ -128,7 +134,7 @@ class SourceLineResolver::Module { string name_; FileMap files_; - RangeMap<MemAddr, linked_ptr<Function> > functions_; + RangeMap< MemAddr, linked_ptr<Function> > functions_; // Each element in the array is a ContainedRangeMap for a type listed in // StackInfoTypes. These are split by type because there may be overlaps @@ -184,7 +190,10 @@ bool SourceLineResolver::Module::LoadMap(const string &map_file) { return false; } - char buffer[1024]; + // TODO(mmentovai): this might not be large enough to handle really long + // lines, which might be present for FUNC lines of highly-templatized + // code. + char buffer[8192]; Function *cur_func = NULL; while (fgets(buffer, sizeof(buffer), f)) { @@ -201,6 +210,8 @@ bool SourceLineResolver::Module::LoadMap(const string &map_file) { } functions_.StoreRange(cur_func->address, cur_func->size, linked_ptr<Function>(cur_func)); + } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { + // TODO(mmentovai): add a public map } else { if (!cur_func) { return false; @@ -221,18 +232,19 @@ bool SourceLineResolver::Module::LoadMap(const string &map_file) { void SourceLineResolver::Module::LookupAddress( MemAddr address, StackFrame *frame, StackFrameInfo *frame_info) const { if (frame_info) { + frame_info->valid = StackFrameInfo::VALID_NONE; + // Check for debugging info first, before any possible early returns. // The caller will know that frame_info was filled in by checking its // valid field. // - // We only know about STACK_INFO_FRAME_DATA and STACK_INFO_FPO. - // STACK_INFO_STANDARD looks like it would do the right thing, too. - // Prefer them in this order. + // We only know about STACK_INFO_FRAME_DATA and STACK_INFO_FPO. Prefer + // them in this order. STACK_INFO_FRAME_DATA is the newer type that + // includes its own program string. STACK_INFO_FPO is the older type + // corresponding to the FPO_DATA struct. See stackwalker_x86.cc. if (!stack_info_[STACK_INFO_FRAME_DATA].RetrieveRange(address, frame_info)) { - if (!stack_info_[STACK_INFO_FPO].RetrieveRange(address, frame_info)) { - stack_info_[STACK_INFO_STANDARD].RetrieveRange(address, frame_info); - } + stack_info_[STACK_INFO_FPO].RetrieveRange(address, frame_info); } } @@ -252,6 +264,16 @@ void SourceLineResolver::Module::LookupAddress( 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; + frame_info->valid |= StackFrameInfo::VALID_PARAMETER_SIZE; + } } // static @@ -303,19 +325,20 @@ void SourceLineResolver::Module::ParseFile(char *file_line) { SourceLineResolver::Function* SourceLineResolver::Module::ParseFunction( char *function_line) { - // FUNC <address> <name> + // FUNC <address> <stack_param_size> <name> function_line += 5; // skip prefix vector<char*> tokens; - if (!Tokenize(function_line, 3, &tokens)) { + if (!Tokenize(function_line, 4, &tokens)) { return NULL; } - u_int64_t address = strtoull(tokens[0], NULL, 16); - u_int64_t size = strtoull(tokens[1], NULL, 16); - char *name = tokens[2]; + u_int64_t address = strtoull(tokens[0], NULL, 16); + u_int64_t size = strtoull(tokens[1], NULL, 16); + int stack_param_size = strtoull(tokens[2], NULL, 16); + char *name = tokens[3]; - return new Function(name, address, size); + return new Function(name, address, size, stack_param_size); } SourceLineResolver::Line* SourceLineResolver::Module::ParseLine( @@ -340,17 +363,24 @@ SourceLineResolver::Line* SourceLineResolver::Module::ParseLine( 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> - // <program_string> + // <has_program_string> <program_string_OR_allocates_base_pointer> + // + // If has_program_string is 1, the rest of the line is a program string. + // Otherwise, the final token tells whether the stack info indicates that + // a base pointer has been allocated. + // + // Expect has_program_string to be 1 when type is STACK_INFO_FRAME_DATA and + // 0 when type is STACK_INFO_FPO, but don't enforce this. // Skip "STACK " prefix. stack_info_line += 6; vector<char*> tokens; - if (!Tokenize(stack_info_line, 11, &tokens)) + if (!Tokenize(stack_info_line, 12, &tokens)) return false; // Only MSVC stack frame info is understood for now. - char *platform = tokens[0]; + const char *platform = tokens[0]; if (strcmp(platform, "WIN") != 0) return false; @@ -358,15 +388,23 @@ bool SourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { if (type < 0 || type > STACK_INFO_LAST - 1) return false; - u_int64_t rva = strtoull(tokens[2], NULL, 16); - u_int64_t code_size = strtoull(tokens[3], NULL, 16); - u_int32_t prolog_size = strtoul(tokens[4], NULL, 16); - u_int32_t epilog_size = strtoul(tokens[5], NULL, 16); - u_int32_t parameter_size = strtoul(tokens[6], NULL, 16); - u_int32_t saved_register_size = strtoul(tokens[7], NULL, 16); - u_int32_t local_size = strtoul(tokens[8], NULL, 16); - u_int32_t max_stack_size = strtoul(tokens[9], NULL, 16); - char *program_string = tokens[10]; + u_int64_t rva = strtoull(tokens[2], NULL, 16); + u_int64_t code_size = strtoull(tokens[3], NULL, 16); + u_int32_t prolog_size = strtoul(tokens[4], NULL, 16); + u_int32_t epilog_size = strtoul(tokens[5], NULL, 16); + u_int32_t parameter_size = strtoul(tokens[6], NULL, 16); + u_int32_t saved_register_size = strtoul(tokens[7], NULL, 16); + u_int32_t local_size = strtoul(tokens[8], NULL, 16); + u_int32_t max_stack_size = strtoul(tokens[9], NULL, 16); + int has_program_string = strtoul(tokens[10], NULL, 16); + + const char *program_string = ""; + int allocates_base_pointer = 0; + if (has_program_string) { + program_string = tokens[11]; + } else { + allocates_base_pointer = strtoul(tokens[11], NULL, 16); + } // TODO(mmentovai): I wanted to use StoreRange's return value as this // method's return value, but MSVC infrequently outputs stack info that @@ -395,6 +433,7 @@ bool SourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { saved_register_size, local_size, max_stack_size, + allocates_base_pointer, program_string)); return true; |