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
20
Makefile.am
20
Makefile.am
|
@ -44,12 +44,17 @@ src_libairbag_la_SOURCES = \
|
|||
src/processor/minidump_format.h \
|
||||
src/processor/range_map.h \
|
||||
src/processor/source_line_resolver.cc \
|
||||
src/processor/source_line_resolver.h
|
||||
src/processor/source_line_resolver.h \
|
||||
src/processor/stackwalker.cc \
|
||||
src/processor/stackwalker.h \
|
||||
src/processor/stackwalker_x86.cc \
|
||||
src/processor/stackwalker_x86.h
|
||||
|
||||
|
||||
## Programs
|
||||
bin_PROGRAMS = \
|
||||
src/processor/minidump_dump
|
||||
src/processor/minidump_dump \
|
||||
src/processor/minidump_stackwalk
|
||||
|
||||
|
||||
## Tests
|
||||
|
@ -57,7 +62,8 @@ check_PROGRAMS = \
|
|||
src/processor/range_map_unittest \
|
||||
src/processor/source_line_resolver_unittest
|
||||
check_SCRIPTS = \
|
||||
src/processor/minidump_dump_test
|
||||
src/processor/minidump_dump_test \
|
||||
src/processor/minidump_stackwalk_test
|
||||
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
TESTS_ENVIRONMENT =
|
||||
|
||||
|
@ -79,12 +85,20 @@ src_processor_minidump_dump_SOURCES = \
|
|||
src_processor_minidump_dump_LDADD = \
|
||||
src/processor/minidump.lo
|
||||
|
||||
src_processor_minidump_stackwalk_SOURCES = \
|
||||
src/processor/minidump_stackwalk.cc
|
||||
src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/minidump.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
|
||||
## Additional files to be included in a source distribution
|
||||
EXTRA_DIST = \
|
||||
$(SCRIPTS) \
|
||||
src/processor/testdata/minidump1.dmp \
|
||||
src/processor/testdata/minidump1.out \
|
||||
src/processor/testdata/minidump1.stack.out \
|
||||
src/processor/testdata/module1.out \
|
||||
src/processor/testdata/module2.out \
|
||||
src/processor/testdata/module3_bad.out
|
||||
|
|
51
Makefile.in
51
Makefile.in
|
@ -53,7 +53,8 @@ PRE_UNINSTALL = :
|
|||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT)
|
||||
bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT) \
|
||||
src/processor/minidump_stackwalk$(EXEEXT)
|
||||
check_PROGRAMS = src/processor/range_map_unittest$(EXEEXT) \
|
||||
src/processor/source_line_resolver_unittest$(EXEEXT)
|
||||
noinst_PROGRAMS =
|
||||
|
@ -86,7 +87,8 @@ LTLIBRARIES = $(lib_LTLIBRARIES)
|
|||
src_libairbag_la_LIBADD =
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am_src_libairbag_la_OBJECTS = src/processor/minidump.lo \
|
||||
src/processor/source_line_resolver.lo
|
||||
src/processor/source_line_resolver.lo \
|
||||
src/processor/stackwalker.lo src/processor/stackwalker_x86.lo
|
||||
src_libairbag_la_OBJECTS = $(am_src_libairbag_la_OBJECTS)
|
||||
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
|
||||
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
|
||||
|
@ -95,6 +97,13 @@ am_src_processor_minidump_dump_OBJECTS = \
|
|||
src_processor_minidump_dump_OBJECTS = \
|
||||
$(am_src_processor_minidump_dump_OBJECTS)
|
||||
src_processor_minidump_dump_DEPENDENCIES = src/processor/minidump.lo
|
||||
am_src_processor_minidump_stackwalk_OBJECTS = \
|
||||
src/processor/minidump_stackwalk.$(OBJEXT)
|
||||
src_processor_minidump_stackwalk_OBJECTS = \
|
||||
$(am_src_processor_minidump_stackwalk_OBJECTS)
|
||||
src_processor_minidump_stackwalk_DEPENDENCIES = \
|
||||
src/processor/minidump.lo src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
am_src_processor_range_map_unittest_OBJECTS = \
|
||||
src/processor/range_map_unittest.$(OBJEXT)
|
||||
src_processor_range_map_unittest_OBJECTS = \
|
||||
|
@ -128,10 +137,12 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
|||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(src_libairbag_la_SOURCES) \
|
||||
$(src_processor_minidump_dump_SOURCES) \
|
||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||
$(src_processor_range_map_unittest_SOURCES) \
|
||||
$(src_processor_source_line_resolver_unittest_SOURCES)
|
||||
DIST_SOURCES = $(src_libairbag_la_SOURCES) \
|
||||
$(src_processor_minidump_dump_SOURCES) \
|
||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||
$(src_processor_range_map_unittest_SOURCES) \
|
||||
$(src_processor_source_line_resolver_unittest_SOURCES)
|
||||
dist_docDATA_INSTALL = $(INSTALL_DATA)
|
||||
|
@ -269,10 +280,15 @@ src_libairbag_la_SOURCES = \
|
|||
src/processor/minidump_format.h \
|
||||
src/processor/range_map.h \
|
||||
src/processor/source_line_resolver.cc \
|
||||
src/processor/source_line_resolver.h
|
||||
src/processor/source_line_resolver.h \
|
||||
src/processor/stackwalker.cc \
|
||||
src/processor/stackwalker.h \
|
||||
src/processor/stackwalker_x86.cc \
|
||||
src/processor/stackwalker_x86.h
|
||||
|
||||
check_SCRIPTS = \
|
||||
src/processor/minidump_dump_test
|
||||
src/processor/minidump_dump_test \
|
||||
src/processor/minidump_stackwalk_test
|
||||
|
||||
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
TESTS_ENVIRONMENT =
|
||||
|
@ -292,10 +308,19 @@ src_processor_minidump_dump_SOURCES = \
|
|||
src_processor_minidump_dump_LDADD = \
|
||||
src/processor/minidump.lo
|
||||
|
||||
src_processor_minidump_stackwalk_SOURCES = \
|
||||
src/processor/minidump_stackwalk.cc
|
||||
|
||||
src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/minidump.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(SCRIPTS) \
|
||||
src/processor/testdata/minidump1.dmp \
|
||||
src/processor/testdata/minidump1.out \
|
||||
src/processor/testdata/minidump1.stack.out \
|
||||
src/processor/testdata/module1.out \
|
||||
src/processor/testdata/module2.out \
|
||||
src/processor/testdata/module3_bad.out
|
||||
|
@ -391,6 +416,10 @@ src/processor/minidump.lo: src/processor/$(am__dirstamp) \
|
|||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/source_line_resolver.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/stackwalker_x86.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/$(am__dirstamp):
|
||||
@$(mkdir_p) src
|
||||
@: > src/$(am__dirstamp)
|
||||
|
@ -443,6 +472,12 @@ src/processor/minidump_dump.$(OBJEXT): src/processor/$(am__dirstamp) \
|
|||
src/processor/minidump_dump$(EXEEXT): $(src_processor_minidump_dump_OBJECTS) $(src_processor_minidump_dump_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/minidump_dump$(EXEEXT)
|
||||
$(CXXLINK) $(src_processor_minidump_dump_LDFLAGS) $(src_processor_minidump_dump_OBJECTS) $(src_processor_minidump_dump_LDADD) $(LIBS)
|
||||
src/processor/minidump_stackwalk.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/minidump_stackwalk$(EXEEXT): $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/minidump_stackwalk$(EXEEXT)
|
||||
$(CXXLINK) $(src_processor_minidump_stackwalk_LDFLAGS) $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_LDADD) $(LIBS)
|
||||
src/processor/range_map_unittest.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
|
@ -461,19 +496,27 @@ mostlyclean-compile:
|
|||
-rm -f src/processor/minidump.$(OBJEXT)
|
||||
-rm -f src/processor/minidump.lo
|
||||
-rm -f src/processor/minidump_dump.$(OBJEXT)
|
||||
-rm -f src/processor/minidump_stackwalk.$(OBJEXT)
|
||||
-rm -f src/processor/range_map_unittest.$(OBJEXT)
|
||||
-rm -f src/processor/source_line_resolver.$(OBJEXT)
|
||||
-rm -f src/processor/source_line_resolver.lo
|
||||
-rm -f src/processor/source_line_resolver_unittest.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker.lo
|
||||
-rm -f src/processor/stackwalker_x86.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker_x86.lo
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_dump.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_stackwalk.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_x86.Plo@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`; \
|
||||
|
|
118
src/processor/minidump_stackwalk.cc
Normal file
118
src/processor/minidump_stackwalk.cc
Normal file
|
@ -0,0 +1,118 @@
|
|||
// 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.
|
||||
|
||||
// minidump_stackwalk.cc: Print the stack of the exception thread from a
|
||||
// minidump.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#define O_BINARY 0
|
||||
#else // !_WIN32
|
||||
#include <io.h>
|
||||
#define open _open
|
||||
#endif // !_WIN32
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "processor/minidump.h"
|
||||
#include "processor/stackwalker_x86.h"
|
||||
|
||||
|
||||
using std::auto_ptr;
|
||||
using namespace google_airbag;
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int fd = open(argv[1], O_RDONLY | O_BINARY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "open failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Minidump minidump(fd);
|
||||
if (!minidump.Read()) {
|
||||
fprintf(stderr, "minidump.Read() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MinidumpException* exception = minidump.GetException();
|
||||
if (!exception) {
|
||||
fprintf(stderr, "minidump.GetException() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MinidumpThreadList* thread_list = minidump.GetThreadList();
|
||||
if (!thread_list) {
|
||||
fprintf(stderr, "minidump.GetThreadList() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MinidumpThread* exception_thread =
|
||||
thread_list->GetThreadByID(exception->GetThreadID());
|
||||
if (!exception_thread) {
|
||||
fprintf(stderr, "thread_list->GetThreadByID() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MemoryRegion* stack_memory = exception_thread->GetMemory();
|
||||
if (!stack_memory) {
|
||||
fprintf(stderr, "exception_thread->GetStackMemory() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MinidumpContext* context = exception->GetContext();
|
||||
if (!context) {
|
||||
fprintf(stderr, "exception->GetContext() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
MinidumpModuleList* modules = minidump.GetModuleList();
|
||||
if (!modules) {
|
||||
fprintf(stderr, "minidump.GetModuleList() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
StackwalkerX86 stackwalker = StackwalkerX86(context, stack_memory, modules);
|
||||
|
||||
auto_ptr<StackFrames> stack(stackwalker.Walk());
|
||||
if (!stack.get()) {
|
||||
fprintf(stderr, "stackwalker->Walk() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unsigned int index;
|
||||
for (index = 0 ; index < stack->size() ; index++) {
|
||||
StackFrame frame = stack->at(index);
|
||||
printf("[%2d] ebp = 0x%08llx eip = 0x%08llx \"%s\" + 0x%08llx\n",
|
||||
index,
|
||||
frame.frame_pointer,
|
||||
frame.instruction,
|
||||
frame.module_base ? frame.module_name.c_str() : "0x0",
|
||||
frame.instruction - frame.module_base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
6
src/processor/minidump_stackwalk_test
Executable file
6
src/processor/minidump_stackwalk_test
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
testdata_dir=$srcdir/src/processor/testdata
|
||||
./src/processor/minidump_stackwalk $testdata_dir/minidump1.dmp | \
|
||||
tr -s '\015' '\012' | \
|
||||
diff -u $testdata_dir/minidump1.stack.out -
|
||||
exit $?
|
78
src/processor/stackwalker.cc
Normal file
78
src/processor/stackwalker.cc
Normal file
|
@ -0,0 +1,78 @@
|
|||
// 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.cc: Generic stackwalker.
|
||||
//
|
||||
// See stackwalker.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "processor/stackwalker.h"
|
||||
#include "processor/minidump.h"
|
||||
|
||||
|
||||
namespace google_airbag {
|
||||
|
||||
|
||||
using std::auto_ptr;
|
||||
|
||||
|
||||
Stackwalker::Stackwalker(MemoryRegion* memory, MinidumpModuleList* modules)
|
||||
: memory_(memory), modules_(modules) {
|
||||
}
|
||||
|
||||
|
||||
StackFrames* Stackwalker::Walk() {
|
||||
auto_ptr<StackFrames> frames(new StackFrames());
|
||||
|
||||
// Begin with the context frame, and keep getting callers until there are
|
||||
// no more.
|
||||
|
||||
auto_ptr<StackFrame> frame(new StackFrame());
|
||||
bool valid = GetContextFrame(frame.get());
|
||||
while (valid) {
|
||||
// frame already contains a good frame with properly set instruction and
|
||||
// frame_pointer fields. The frame structure comes from either the
|
||||
// context frame (above) or a caller frame (below).
|
||||
|
||||
// Resolve the module information, if a module map was provided.
|
||||
if (modules_) {
|
||||
MinidumpModule* module =
|
||||
modules_->GetModuleForAddress(frame->instruction);
|
||||
if (module) {
|
||||
frame->module_name = *(module->GetName());
|
||||
frame->module_base = module->base_address();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the frame into the frames vector.
|
||||
frames->push_back(*frame);
|
||||
|
||||
// Use a new object for the next frame, even though the old object was
|
||||
// copied. If StackFrame provided some sort of Clear() method, then
|
||||
// the same frame could be reused.
|
||||
frame.reset(new StackFrame());
|
||||
|
||||
// Get the next frame.
|
||||
valid = GetCallerFrame(frame.get());
|
||||
}
|
||||
|
||||
return frames.release();
|
||||
}
|
||||
|
||||
|
||||
} // namespace google_airbag
|
83
src/processor/stackwalker.h
Normal file
83
src/processor/stackwalker.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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.cc: Generic stackwalker.
|
||||
//
|
||||
// The Stackwalker class is an abstract base class providing common generic
|
||||
// methods that apply to stacks from all systems. Specific implementations
|
||||
// will extend this class by providing GetContextFrame and GetCallerFrame
|
||||
// methods to fill in system-specific data in a StackFrame structure.
|
||||
// Stackwalker assembles these StackFrame strucutres into a vector of
|
||||
// StackFrames.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_H__
|
||||
#define PROCESSOR_STACKWALKER_H__
|
||||
|
||||
|
||||
#include "google/stack_frame.h"
|
||||
#include "processor/memory_region.h"
|
||||
|
||||
|
||||
namespace google_airbag {
|
||||
|
||||
|
||||
class MinidumpModuleList;
|
||||
|
||||
|
||||
class Stackwalker {
|
||||
public:
|
||||
virtual ~Stackwalker() {}
|
||||
|
||||
// Produces a vector of StackFrames by calling GetContextFrame and
|
||||
// GetCallerFrame, and populating the returned frames with module
|
||||
// offset and name information if possible. The caller takes ownership
|
||||
// of the StackFrames object and is responsible for freeing it.
|
||||
StackFrames* Walk();
|
||||
|
||||
protected:
|
||||
// memory identifies a MemoryRegion that provides the stack memory
|
||||
// for the stack to walk. modules, if non-NULL, is a MinidumpModuleList
|
||||
// that is used to look up which code module each stack frame is
|
||||
// associated with.
|
||||
Stackwalker(MemoryRegion* memory, MinidumpModuleList* modules);
|
||||
|
||||
// The stack memory to walk. Subclasses will require this region to
|
||||
// get information from the stack.
|
||||
MemoryRegion* memory_;
|
||||
|
||||
private:
|
||||
// Obtains the context frame, the innermost called procedure in a stack
|
||||
// trace. Returns false on failure.
|
||||
virtual bool GetContextFrame(StackFrame* frame) = 0;
|
||||
|
||||
// Obtains a caller frame. Each call to GetCallerFrame should return the
|
||||
// frame that called the last frame returned by GetContextFrame or
|
||||
// GetCallerFrame. GetCallerFrame should return false on failure or
|
||||
// when there are no more caller frames (when the end of the stack has
|
||||
// been reached).
|
||||
virtual bool GetCallerFrame(StackFrame* frame) = 0;
|
||||
|
||||
// A list of modules, for populating each StackFrame's module information.
|
||||
// This field is optional and may be NULL.
|
||||
MinidumpModuleList* modules_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace google_airbag
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_H__
|
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
|
68
src/processor/stackwalker_x86.h
Normal file
68
src/processor/stackwalker_x86.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
// 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.h: x86-specific stackwalker.
|
||||
//
|
||||
// Provides stack frames given x86 register context and a memory region
|
||||
// corresponding to an x86 stack.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALKER_X86_H__
|
||||
#define PROCESSOR_STACKWALKER_X86_H__
|
||||
|
||||
|
||||
#include "google/airbag_types.h"
|
||||
#include "processor/stackwalker.h"
|
||||
#include "processor/minidump_format.h"
|
||||
|
||||
|
||||
namespace google_airbag {
|
||||
|
||||
|
||||
class MinidumpContext;
|
||||
class MinidumpModuleList;
|
||||
|
||||
|
||||
class StackwalkerX86 : public Stackwalker {
|
||||
public:
|
||||
// context is a MinidumpContext object that gives access to x86-specific
|
||||
// register state corresponding to the innermost called frame to be
|
||||
// included in the stack. memory and modules are passed directly through
|
||||
// to the base Stackwalker constructor.
|
||||
StackwalkerX86(MinidumpContext* context,
|
||||
MemoryRegion* memory,
|
||||
MinidumpModuleList* modules);
|
||||
|
||||
private:
|
||||
// Implementation of Stackwalker, using x86 context (%ebp, %eip) and
|
||||
// stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp]).
|
||||
bool GetContextFrame(StackFrame* frame);
|
||||
bool GetCallerFrame(StackFrame* frame);
|
||||
|
||||
// Stores the CPU context corresponding to the innermost stack frame to
|
||||
// be returned by GetContextFrame.
|
||||
const MDRawContextX86* context_;
|
||||
|
||||
// Stores the frame pointer returned in the last stack frame returned by
|
||||
// GetContextFrame or GetCallerFrame.
|
||||
u_int32_t last_frame_pointer_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace google_airbag
|
||||
|
||||
|
||||
#endif // PROCESSOR_STACKWALKER_X86_H__
|
23
src/processor/testdata/minidump1.stack.out
vendored
Normal file
23
src/processor/testdata/minidump1.stack.out
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
[ 0] ebp = 0x0012ecb8 eip = 0x020a1515 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x00221515
|
||||
[ 1] ebp = 0x0012ecd8 eip = 0x020a03e3 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x002203e3
|
||||
[ 2] ebp = 0x0012ecf0 eip = 0x023c8a28 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x00548a28
|
||||
[ 3] ebp = 0x0012ed30 eip = 0x023ccfd9 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x0054cfd9
|
||||
[ 4] ebp = 0x0012ed64 eip = 0x0222fd12 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x003afd12
|
||||
[ 5] ebp = 0x0012ed94 eip = 0x022311dd "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x003b11dd
|
||||
[ 6] ebp = 0x0012edc8 eip = 0x034eb0f1 "c:\lizard\trunk\mozilla\dist\bin\components\xpc3250.dll" + 0x0005b0f1
|
||||
[ 7] ebp = 0x0012eeb0 eip = 0x0049bda4 "c:\lizard\trunk\mozilla\dist\bin\js3250.dll" + 0x0007bda4
|
||||
[ 8] ebp = 0x0012f834 eip = 0x0047b92f "c:\lizard\trunk\mozilla\dist\bin\js3250.dll" + 0x0005b92f
|
||||
[ 9] ebp = 0x0012f93c eip = 0x0046c945 "c:\lizard\trunk\mozilla\dist\bin\js3250.dll" + 0x0004c945
|
||||
[10] ebp = 0x0012f9c8 eip = 0x0046d345 "c:\lizard\trunk\mozilla\dist\bin\js3250.dll" + 0x0004d345
|
||||
[11] ebp = 0x0012f9f0 eip = 0x00430ec3 "c:\lizard\trunk\mozilla\dist\bin\js3250.dll" + 0x00010ec3
|
||||
[12] ebp = 0x0012fa4c eip = 0x02213b7f "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x00393b7f
|
||||
[13] ebp = 0x0012fb60 eip = 0x02249ced "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x003c9ced
|
||||
[14] ebp = 0x0012fb70 eip = 0x0224a810 "c:\lizard\trunk\mozilla\dist\bin\components\gklayout.dll" + 0x003ca810
|
||||
[15] ebp = 0x0012fbbc eip = 0x002ebff8 "c:\lizard\trunk\mozilla\dist\bin\xpcom_core.dll" + 0x0007bff8
|
||||
[16] ebp = 0x0012fbe4 eip = 0x002ec8ec "c:\lizard\trunk\mozilla\dist\bin\xpcom_core.dll" + 0x0007c8ec
|
||||
[17] ebp = 0x0012fc48 eip = 0x029193b5 "c:\lizard\trunk\mozilla\dist\bin\components\gkwidget.dll" + 0x000293b5
|
||||
[18] ebp = 0x0012fc5c eip = 0x03174b19 "c:\lizard\trunk\mozilla\dist\bin\components\tkitcmps.dll" + 0x00004b19
|
||||
[19] ebp = 0x0012ff54 eip = 0x10008e60 "c:\lizard\trunk\mozilla\dist\bin\xul.dll" + 0x00008e60
|
||||
[20] ebp = 0x0012ff68 eip = 0x00401036 "c:\lizard\trunk\mozilla\dist\bin\firefox.exe" + 0x00001036
|
||||
[21] ebp = 0x0012ffc0 eip = 0x004011bc "c:\lizard\trunk\mozilla\dist\bin\firefox.exe" + 0x000011bc
|
||||
[22] ebp = 0x0012fff0 eip = 0x7c816d4f "C:\WINDOWS\system32\kernel32.dll" + 0x00016d4f
|
Loading…
Reference in a new issue