mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-01-02 12:44:38 +01:00
Initial implementation of x86 stackwalker (#9). r=bryner
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@12 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
3261e8b6ea
commit
213800d30c
9 changed files with 543 additions and 7 deletions
103
src/processor/stackwalker_x86.cc
Normal file
103
src/processor/stackwalker_x86.cc
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (C) 2006 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// stackwalker_x86.cc: x86-specific stackwalker.
|
||||
//
|
||||
// See stackwalker_x86.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#include "processor/stackwalker_x86.h"
|
||||
#include "processor/minidump.h"
|
||||
|
||||
|
||||
namespace google_airbag {
|
||||
|
||||
|
||||
StackwalkerX86::StackwalkerX86(MinidumpContext* context,
|
||||
MemoryRegion* memory,
|
||||
MinidumpModuleList* modules)
|
||||
: Stackwalker(memory, modules)
|
||||
, last_frame_pointer_(0) {
|
||||
if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) {
|
||||
// The x86 is a 32-bit CPU, the limits of the supplied stack are invalid.
|
||||
// Mark memory_ = NULL, which will cause stackwalking to fail.
|
||||
memory_ = NULL;
|
||||
}
|
||||
|
||||
// TODO(mmentovai): verify that |context| is x86 when Minidump supports
|
||||
// other CPU types.
|
||||
context_ = context->context();
|
||||
}
|
||||
|
||||
|
||||
bool StackwalkerX86::GetContextFrame(StackFrame* frame) {
|
||||
if (!context_ || !memory_ || !frame)
|
||||
return false;
|
||||
|
||||
// The frame and instruction pointers are stored directly in registers,
|
||||
// so pull them straight out of the CPU context structure.
|
||||
frame->frame_pointer = last_frame_pointer_ = context_->ebp;
|
||||
frame->instruction = context_->eip;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool StackwalkerX86::GetCallerFrame(StackFrame* frame) {
|
||||
if (!memory_ || !frame)
|
||||
return false;
|
||||
|
||||
// The frame and instruction pointers for previous frames are saved on the
|
||||
// stack. The typical x86 calling convention, when frame pointers are
|
||||
// present, is for the calling procedure to use CALL, which pushes the
|
||||
// return address onto the stack and sets the instruction pointer (%eip)
|
||||
// to the entry point of the called routine. The called routine's then
|
||||
// PUSHes the calling routine's frame pointer (%ebp) onto the stack before
|
||||
// copying the stack pointer (%esp) to the frame pointer (%ebp). Therefore,
|
||||
// the calling procedure's frame pointer is always available by
|
||||
// dereferencing the called procedure's frame pointer, and the return
|
||||
// address is always available at the memory location immediately above
|
||||
// the address pointed to by the called procedure's frame pointer.
|
||||
|
||||
// If there is no frame pointer, determining the layout of the stack is
|
||||
// considerably more difficult, requiring debugging information. This
|
||||
// stackwalker doesn't attempt to solve that problem (at this point).
|
||||
|
||||
// Don't pass frame.frame_pointer or frame.instruction directly
|
||||
// ReadMemory, because their types are too wide (64-bit), and we
|
||||
// specifically want to read 32-bit quantities for both.
|
||||
u_int32_t frame_pointer;
|
||||
if (!memory_->GetMemoryAtAddress(last_frame_pointer_, &frame_pointer))
|
||||
return false;
|
||||
|
||||
// A caller frame must reside higher in memory than its callee frames.
|
||||
// Anything else is an error, or an indication that we've reached the
|
||||
// end of the stack.
|
||||
if (frame_pointer <= last_frame_pointer_)
|
||||
return false;
|
||||
|
||||
u_int32_t instruction;
|
||||
if (!memory_->GetMemoryAtAddress(last_frame_pointer_ + 4, &instruction))
|
||||
return false;
|
||||
|
||||
frame->frame_pointer = last_frame_pointer_ = frame_pointer;
|
||||
frame->instruction = instruction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace google_airbag
|
||||
Loading…
Add table
Add a link
Reference in a new issue