Breakpad processor: Don't pass Windows stack walking information to all walkers.
At the moment, the StackWalker GetCallerFrame member function expects a vector of WindowsFrameInfo structures, even though WindowsFrameInfo is only used or useful on one one implementation (StackWalkerX86). This patch changes StackWalker::GetCallerFrame to no longer expect the WindowsFrameInfo structures, and changes all implementations to match. In particular, StackWalkerX86 is changed to find the WindowsFrameInfo data itself, and store a pointer to whatever it got in the StackFrame object itself (which is really a StackFrameX86). To allow GetCallerFrame implementations to look up stack walking data, StackWalker::resolver_ needs to be made protected, not private. a=jimblandy, r=mmentovai git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@491 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
5251e64f48
commit
2684b4dc19
13 changed files with 51 additions and 69 deletions
|
@ -44,6 +44,8 @@
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
struct WindowsFrameInfo;
|
||||
|
||||
struct StackFrameX86 : public StackFrame {
|
||||
// ContextValidity has one entry for each relevant hardware pointer register
|
||||
// (%eip and %esp) and one entry for each nonvolatile (callee-save) register.
|
||||
|
@ -74,7 +76,9 @@ struct StackFrameX86 : public StackFrame {
|
|||
StackFrameX86()
|
||||
: context(),
|
||||
context_validity(CONTEXT_VALID_NONE),
|
||||
trust(FRAME_TRUST_NONE) {}
|
||||
trust(FRAME_TRUST_NONE),
|
||||
windows_frame_info(NULL) {}
|
||||
~StackFrameX86();
|
||||
|
||||
// Register state. This is only fully valid for the topmost frame in a
|
||||
// stack. In other frames, the values of nonvolatile registers may be
|
||||
|
@ -90,6 +94,11 @@ struct StackFrameX86 : public StackFrame {
|
|||
// Amount of trust the stack walker has in the instruction pointer
|
||||
// of this frame.
|
||||
FrameTrust trust;
|
||||
|
||||
// Any stack walking information we found describing
|
||||
// this.instruction. These may be NULL if we couldn't find the
|
||||
// appropriate information.
|
||||
WindowsFrameInfo *windows_frame_info;
|
||||
};
|
||||
|
||||
struct StackFramePPC : public StackFrame {
|
||||
|
|
|
@ -48,12 +48,10 @@ namespace google_breakpad {
|
|||
|
||||
class CallStack;
|
||||
class CodeModules;
|
||||
template<typename T> class linked_ptr;
|
||||
class MemoryRegion;
|
||||
class MinidumpContext;
|
||||
class SourceLineResolverInterface;
|
||||
struct StackFrame;
|
||||
struct WindowsFrameInfo;
|
||||
class SymbolSupplier;
|
||||
class SystemInfo;
|
||||
|
||||
|
@ -118,6 +116,10 @@ class Stackwalker {
|
|||
// This field is optional and may be NULL.
|
||||
const CodeModules *modules_;
|
||||
|
||||
protected:
|
||||
// The SourceLineResolver implementation.
|
||||
SourceLineResolverInterface *resolver_;
|
||||
|
||||
private:
|
||||
// Obtains the context frame, the innermost called procedure in a stack
|
||||
// trace. Returns NULL on failure. GetContextFrame allocates a new
|
||||
|
@ -133,15 +135,10 @@ class Stackwalker {
|
|||
// the end of the stack has been reached). GetCallerFrame allocates a new
|
||||
// StackFrame (or StackFrame subclass), ownership of which is taken by
|
||||
// the caller.
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) = 0;
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack) = 0;
|
||||
|
||||
// The optional SymbolSupplier for resolving source line info.
|
||||
SymbolSupplier *supplier_;
|
||||
|
||||
// The SourceLineResolver implementation
|
||||
SourceLineResolverInterface *resolver_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
#include "processor/windows_frame_info.h"
|
||||
#include "processor/stackwalker_ppc.h"
|
||||
#include "processor/stackwalker_sparc.h"
|
||||
#include "processor/stackwalker_x86.h"
|
||||
|
@ -65,8 +64,8 @@ Stackwalker::Stackwalker(const SystemInfo *system_info,
|
|||
: system_info_(system_info),
|
||||
memory_(memory),
|
||||
modules_(modules),
|
||||
supplier_(supplier),
|
||||
resolver_(resolver) {
|
||||
resolver_(resolver),
|
||||
supplier_(supplier) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,11 +74,6 @@ bool Stackwalker::Walk(CallStack *stack) {
|
|||
assert(stack);
|
||||
stack->Clear();
|
||||
|
||||
// stack_frame_info parallels the CallStack. The vector is passed to the
|
||||
// GetCallerFrame function. It contains information that may be helpful
|
||||
// for stackwalking.
|
||||
vector< linked_ptr<WindowsFrameInfo> > stack_frame_info;
|
||||
|
||||
// Begin with the context frame, and keep getting callers until there are
|
||||
// no more.
|
||||
|
||||
|
@ -91,8 +85,6 @@ bool Stackwalker::Walk(CallStack *stack) {
|
|||
// frame_pointer fields. The frame structure comes from either the
|
||||
// context frame (above) or a caller frame (below).
|
||||
|
||||
linked_ptr<WindowsFrameInfo> frame_info;
|
||||
|
||||
// Resolve the module information, if a module map was provided.
|
||||
if (modules_) {
|
||||
const CodeModule *module =
|
||||
|
@ -119,7 +111,6 @@ bool Stackwalker::Walk(CallStack *stack) {
|
|||
}
|
||||
}
|
||||
resolver_->FillSourceLineInfo(frame.get());
|
||||
frame_info.reset(resolver_->FindWindowsFrameInfo(frame.get()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,12 +118,8 @@ bool Stackwalker::Walk(CallStack *stack) {
|
|||
// over the frame, because the stack now owns it.
|
||||
stack->frames_.push_back(frame.release());
|
||||
|
||||
// Add the frame info to the parallel stack.
|
||||
stack_frame_info.push_back(frame_info);
|
||||
frame_info.reset(NULL);
|
||||
|
||||
// Get the next frame and take ownership.
|
||||
frame.reset(GetCallerFrame(stack, stack_frame_info));
|
||||
frame.reset(GetCallerFrame(stack));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -72,9 +72,7 @@ StackFrame* StackwalkerAMD64::GetContextFrame() {
|
|||
}
|
||||
|
||||
|
||||
StackFrame* StackwalkerAMD64::GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) {
|
||||
StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack *stack) {
|
||||
if (!memory_ || !stack) {
|
||||
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||
return NULL;
|
||||
|
|
|
@ -64,9 +64,7 @@ class StackwalkerAMD64 : public Stackwalker {
|
|||
// Implementation of Stackwalker, using amd64 context (stack pointer in %rsp,
|
||||
// stack base in %rbp) and stack conventions (saved stack pointer at 0(%rbp))
|
||||
virtual StackFrame* GetContextFrame();
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info);
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack);
|
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
|
|
|
@ -72,9 +72,7 @@ StackFrame* StackwalkerARM::GetContextFrame() {
|
|||
}
|
||||
|
||||
|
||||
StackFrame* StackwalkerARM::GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) {
|
||||
StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) {
|
||||
if (!memory_ || !stack) {
|
||||
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||
return NULL;
|
||||
|
|
|
@ -64,9 +64,7 @@ class StackwalkerARM : public Stackwalker {
|
|||
// Implementation of Stackwalker, using arm context and stack conventions.
|
||||
// TODO: currently stubbed out, needs CFI symbol dumper support
|
||||
virtual StackFrame* GetContextFrame();
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info);
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack);
|
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
|
|
|
@ -81,9 +81,7 @@ StackFrame* StackwalkerPPC::GetContextFrame() {
|
|||
}
|
||||
|
||||
|
||||
StackFrame* StackwalkerPPC::GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) {
|
||||
StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack *stack) {
|
||||
if (!memory_ || !stack) {
|
||||
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||
return NULL;
|
||||
|
|
|
@ -65,9 +65,7 @@ class StackwalkerPPC : public Stackwalker {
|
|||
// saved program counter in %srr0) and stack conventions (saved stack
|
||||
// pointer at 0(%r1), return address at 8(0(%r1)).
|
||||
virtual StackFrame* GetContextFrame();
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info);
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack);
|
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
|
|
|
@ -72,9 +72,7 @@ StackFrame* StackwalkerSPARC::GetContextFrame() {
|
|||
}
|
||||
|
||||
|
||||
StackFrame* StackwalkerSPARC::GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) {
|
||||
StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack *stack) {
|
||||
if (!memory_ || !stack) {
|
||||
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||
return NULL;
|
||||
|
|
|
@ -61,18 +61,10 @@ class StackwalkerSPARC : public Stackwalker {
|
|||
SourceLineResolverInterface *resolver);
|
||||
|
||||
private:
|
||||
// Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and
|
||||
// stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp], or
|
||||
// alternate conventions as guided by stack_frame_info_).
|
||||
// Implementation of Stackwalker, using ppc context (stack pointer in %r1,
|
||||
// saved program counter in %srr0) and stack conventions (saved stack
|
||||
// pointer at 0(%r1), return address at 8(0(%r1)).
|
||||
// Implementation of Stackwalker, using sparc context (%fp, %sp, %pc) and
|
||||
// stack conventions (saved %sp at)
|
||||
// stack conventions
|
||||
virtual StackFrame* GetContextFrame();
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info);
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack);
|
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "google_breakpad/processor/code_modules.h"
|
||||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/windows_frame_info.h"
|
||||
|
||||
|
@ -66,6 +66,11 @@ StackwalkerX86::StackwalkerX86(const SystemInfo *system_info,
|
|||
}
|
||||
}
|
||||
|
||||
StackFrameX86::~StackFrameX86() {
|
||||
if (windows_frame_info)
|
||||
delete windows_frame_info;
|
||||
windows_frame_info = NULL;
|
||||
}
|
||||
|
||||
StackFrame* StackwalkerX86::GetContextFrame() {
|
||||
if (!context_ || !memory_) {
|
||||
|
@ -86,9 +91,7 @@ StackFrame* StackwalkerX86::GetContextFrame() {
|
|||
}
|
||||
|
||||
|
||||
StackFrame* StackwalkerX86::GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info) {
|
||||
StackFrame* StackwalkerX86::GetCallerFrame(const CallStack *stack) {
|
||||
if (!memory_ || !stack) {
|
||||
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||
return NULL;
|
||||
|
@ -96,7 +99,9 @@ StackFrame* StackwalkerX86::GetCallerFrame(
|
|||
StackFrameX86::FrameTrust trust = StackFrameX86::FRAME_TRUST_NONE;
|
||||
StackFrameX86 *last_frame = static_cast<StackFrameX86*>(
|
||||
stack->frames()->back());
|
||||
WindowsFrameInfo *last_frame_info = stack_frame_info.back().get();
|
||||
|
||||
WindowsFrameInfo *last_frame_info
|
||||
= resolver_->FindWindowsFrameInfo(last_frame);
|
||||
|
||||
// This stackwalker sets each frame's %esp to its value immediately prior
|
||||
// to the CALL into the callee. This means that %esp points to the last
|
||||
|
@ -130,13 +135,17 @@ StackFrame* StackwalkerX86::GetCallerFrame(
|
|||
// are unknown, 0 is also used in that case. When that happens, it should
|
||||
// be possible to walk to the next frame without reference to %esp.
|
||||
|
||||
int frames_already_walked = stack_frame_info.size();
|
||||
int frames_already_walked = stack->frames()->size();
|
||||
u_int32_t last_frame_callee_parameter_size = 0;
|
||||
if (frames_already_walked >= 2) {
|
||||
WindowsFrameInfo *last_frame_callee_info =
|
||||
stack_frame_info[frames_already_walked - 2].get();
|
||||
StackFrameX86 *last_frame_callee
|
||||
= static_cast<StackFrameX86 *>((*stack->frames())
|
||||
[frames_already_walked - 2]);
|
||||
WindowsFrameInfo *last_frame_callee_info
|
||||
= last_frame_callee->windows_frame_info;
|
||||
if (last_frame_callee_info &&
|
||||
last_frame_callee_info->valid & WindowsFrameInfo::VALID_PARAMETER_SIZE) {
|
||||
(last_frame_callee_info->valid
|
||||
& WindowsFrameInfo::VALID_PARAMETER_SIZE)) {
|
||||
last_frame_callee_parameter_size =
|
||||
last_frame_callee_info->parameter_size;
|
||||
}
|
||||
|
@ -433,6 +442,9 @@ StackFrame* StackwalkerX86::GetCallerFrame(
|
|||
// StackFrameX86.
|
||||
frame->instruction = frame->context.eip - 1;
|
||||
|
||||
// Save the stack walking info we found for the callee.
|
||||
last_frame->windows_frame_info = last_frame_info;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,11 +64,10 @@ class StackwalkerX86 : public Stackwalker {
|
|||
private:
|
||||
// Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and
|
||||
// stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp], or
|
||||
// alternate conventions as guided by stack_frame_info_).
|
||||
// alternate conventions as guided by any WindowsFrameInfo available for the
|
||||
// code in question.).
|
||||
virtual StackFrame* GetContextFrame();
|
||||
virtual StackFrame* GetCallerFrame(
|
||||
const CallStack *stack,
|
||||
const vector< linked_ptr<WindowsFrameInfo> > &stack_frame_info);
|
||||
virtual StackFrame* GetCallerFrame(const CallStack *stack);
|
||||
|
||||
// Scan the stack starting at location_start, looking for an address
|
||||
// that looks like a valid instruction pointer. Addresses must
|
||||
|
|
Loading…
Reference in a new issue