Issue 196 - Breakpad processor support for x86-64. r=mento
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@227 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
11e180cd3e
commit
8eb7111814
11 changed files with 833 additions and 216 deletions
|
@ -93,6 +93,8 @@ src_libbreakpad_la_SOURCES = \
|
||||||
src/processor/simple_symbol_supplier.h \
|
src/processor/simple_symbol_supplier.h \
|
||||||
src/processor/stack_frame_info.h \
|
src/processor/stack_frame_info.h \
|
||||||
src/processor/stackwalker.cc \
|
src/processor/stackwalker.cc \
|
||||||
|
src/processor/stackwalker_amd64.cc \
|
||||||
|
src/processor/stackwalker_amd64.h \
|
||||||
src/processor/stackwalker_ppc.cc \
|
src/processor/stackwalker_ppc.cc \
|
||||||
src/processor/stackwalker_ppc.h \
|
src/processor/stackwalker_ppc.h \
|
||||||
src/processor/stackwalker_sparc.cc \
|
src/processor/stackwalker_sparc.cc \
|
||||||
|
@ -161,6 +163,7 @@ src_processor_minidump_processor_unittest_LDADD = \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -192,6 +195,7 @@ src_processor_stackwalker_selftest_LDADD = \
|
||||||
src/processor/minidump.lo \
|
src/processor/minidump.lo \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -221,6 +225,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/simple_symbol_supplier.lo \
|
src/processor/simple_symbol_supplier.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
|
23
Makefile.in
23
Makefile.in
|
@ -112,7 +112,9 @@ am_src_libbreakpad_la_OBJECTS = src/processor/basic_code_modules.lo \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/simple_symbol_supplier.lo \
|
src/processor/simple_symbol_supplier.lo \
|
||||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
src_libbreakpad_la_OBJECTS = $(am_src_libbreakpad_la_OBJECTS)
|
src_libbreakpad_la_OBJECTS = $(am_src_libbreakpad_la_OBJECTS)
|
||||||
|
@ -156,6 +158,7 @@ src_processor_minidump_processor_unittest_DEPENDENCIES = \
|
||||||
src/processor/minidump_processor.lo src/processor/minidump.lo \
|
src/processor/minidump_processor.lo src/processor/minidump.lo \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo src/processor/stackwalker.lo \
|
src/processor/process_state.lo src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -171,7 +174,9 @@ src_processor_minidump_stackwalk_DEPENDENCIES = \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/simple_symbol_supplier.lo \
|
src/processor/simple_symbol_supplier.lo \
|
||||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
am_src_processor_pathname_stripper_unittest_OBJECTS = \
|
am_src_processor_pathname_stripper_unittest_OBJECTS = \
|
||||||
|
@ -201,7 +206,9 @@ src_processor_stackwalker_selftest_DEPENDENCIES = \
|
||||||
src/processor/basic_source_line_resolver.lo \
|
src/processor/basic_source_line_resolver.lo \
|
||||||
src/processor/call_stack.lo src/processor/logging.lo \
|
src/processor/call_stack.lo src/processor/logging.lo \
|
||||||
src/processor/minidump.lo src/processor/pathname_stripper.lo \
|
src/processor/minidump.lo src/processor/pathname_stripper.lo \
|
||||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
SCRIPTS = $(noinst_SCRIPTS)
|
SCRIPTS = $(noinst_SCRIPTS)
|
||||||
|
@ -425,6 +432,8 @@ src_libbreakpad_la_SOURCES = \
|
||||||
src/processor/simple_symbol_supplier.h \
|
src/processor/simple_symbol_supplier.h \
|
||||||
src/processor/stack_frame_info.h \
|
src/processor/stack_frame_info.h \
|
||||||
src/processor/stackwalker.cc \
|
src/processor/stackwalker.cc \
|
||||||
|
src/processor/stackwalker_amd64.cc \
|
||||||
|
src/processor/stackwalker_amd64.h \
|
||||||
src/processor/stackwalker_ppc.cc \
|
src/processor/stackwalker_ppc.cc \
|
||||||
src/processor/stackwalker_ppc.h \
|
src/processor/stackwalker_ppc.h \
|
||||||
src/processor/stackwalker_sparc.cc \
|
src/processor/stackwalker_sparc.cc \
|
||||||
|
@ -474,6 +483,7 @@ src_processor_minidump_processor_unittest_LDADD = \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -509,6 +519,7 @@ src_processor_stackwalker_selftest_LDADD = \
|
||||||
src/processor/minidump.lo \
|
src/processor/minidump.lo \
|
||||||
src/processor/pathname_stripper.lo \
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -537,6 +548,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
src/processor/simple_symbol_supplier.lo \
|
src/processor/simple_symbol_supplier.lo \
|
||||||
src/processor/stackwalker.lo \
|
src/processor/stackwalker.lo \
|
||||||
|
src/processor/stackwalker_amd64.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_sparc.lo \
|
src/processor/stackwalker_sparc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
|
@ -781,6 +793,8 @@ src/processor/simple_symbol_supplier.lo: \
|
||||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||||
src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
|
src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||||
|
src/processor/stackwalker_amd64.lo: src/processor/$(am__dirstamp) \
|
||||||
|
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||||
src/processor/stackwalker_ppc.lo: src/processor/$(am__dirstamp) \
|
src/processor/stackwalker_ppc.lo: src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||||
src/processor/stackwalker_sparc.lo: src/processor/$(am__dirstamp) \
|
src/processor/stackwalker_sparc.lo: src/processor/$(am__dirstamp) \
|
||||||
|
@ -925,6 +939,8 @@ mostlyclean-compile:
|
||||||
-rm -f src/processor/simple_symbol_supplier.lo
|
-rm -f src/processor/simple_symbol_supplier.lo
|
||||||
-rm -f src/processor/stackwalker.$(OBJEXT)
|
-rm -f src/processor/stackwalker.$(OBJEXT)
|
||||||
-rm -f src/processor/stackwalker.lo
|
-rm -f src/processor/stackwalker.lo
|
||||||
|
-rm -f src/processor/stackwalker_amd64.$(OBJEXT)
|
||||||
|
-rm -f src/processor/stackwalker_amd64.lo
|
||||||
-rm -f src/processor/stackwalker_ppc.$(OBJEXT)
|
-rm -f src/processor/stackwalker_ppc.$(OBJEXT)
|
||||||
-rm -f src/processor/stackwalker_ppc.lo
|
-rm -f src/processor/stackwalker_ppc.lo
|
||||||
-rm -f src/processor/stackwalker_selftest.$(OBJEXT)
|
-rm -f src/processor/stackwalker_selftest.$(OBJEXT)
|
||||||
|
@ -955,6 +971,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.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)/simple_symbol_supplier.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/simple_symbol_supplier.Plo@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.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_amd64.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_selftest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_selftest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_sparc.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_sparc.Plo@am__quote@
|
||||||
|
|
|
@ -215,6 +215,160 @@ typedef struct {
|
||||||
|
|
||||||
#define MD_CONTEXT_CPU_MASK 0xffffffc0
|
#define MD_CONTEXT_CPU_MASK 0xffffffc0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AMD64 support, see WINNT.H
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u_int16_t control_word;
|
||||||
|
u_int16_t status_word;
|
||||||
|
u_int8_t tag_word;
|
||||||
|
u_int8_t reserved1;
|
||||||
|
u_int16_t error_opcode;
|
||||||
|
u_int32_t error_offset;
|
||||||
|
u_int16_t error_selector;
|
||||||
|
u_int16_t reserved2;
|
||||||
|
u_int32_t data_offset;
|
||||||
|
u_int16_t data_selector;
|
||||||
|
u_int16_t reserved3;
|
||||||
|
u_int32_t mx_csr;
|
||||||
|
u_int32_t mx_csr_mask;
|
||||||
|
u_int128_t float_registers[8];
|
||||||
|
u_int128_t xmm_registers[16];
|
||||||
|
u_int8_t reserved4[96];
|
||||||
|
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
|
||||||
|
|
||||||
|
#define MD_CONTEXT_AMD64_VR_COUNT 26
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/*
|
||||||
|
* Register parameter home addresses.
|
||||||
|
*/
|
||||||
|
u_int64_t p1_home;
|
||||||
|
u_int64_t p2_home;
|
||||||
|
u_int64_t p3_home;
|
||||||
|
u_int64_t p4_home;
|
||||||
|
u_int64_t p5_home;
|
||||||
|
u_int64_t p6_home;
|
||||||
|
|
||||||
|
/* The next field determines the layout of the structure, and which parts
|
||||||
|
* of it are populated */
|
||||||
|
u_int32_t context_flags;
|
||||||
|
u_int32_t mx_csr;
|
||||||
|
|
||||||
|
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||||
|
u_int16_t cs;
|
||||||
|
|
||||||
|
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
|
||||||
|
u_int16_t ds;
|
||||||
|
u_int16_t es;
|
||||||
|
u_int16_t fs;
|
||||||
|
u_int16_t gs;
|
||||||
|
|
||||||
|
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
|
||||||
|
u_int16_t ss;
|
||||||
|
u_int32_t eflags;
|
||||||
|
|
||||||
|
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||||
|
u_int64_t dr0;
|
||||||
|
u_int64_t dr1;
|
||||||
|
u_int64_t dr2;
|
||||||
|
u_int64_t dr3;
|
||||||
|
u_int64_t dr6;
|
||||||
|
u_int64_t dr7;
|
||||||
|
|
||||||
|
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||||
|
u_int64_t rax;
|
||||||
|
u_int64_t rcx;
|
||||||
|
u_int64_t rdx;
|
||||||
|
u_int64_t rbx;
|
||||||
|
|
||||||
|
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||||
|
u_int64_t rsp;
|
||||||
|
|
||||||
|
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||||
|
u_int64_t rbp;
|
||||||
|
u_int64_t rsi;
|
||||||
|
u_int64_t rdi;
|
||||||
|
u_int64_t r8;
|
||||||
|
u_int64_t r9;
|
||||||
|
u_int64_t r10;
|
||||||
|
u_int64_t r11;
|
||||||
|
u_int64_t r12;
|
||||||
|
u_int64_t r13;
|
||||||
|
u_int64_t r14;
|
||||||
|
u_int64_t r15;
|
||||||
|
|
||||||
|
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||||
|
u_int64_t rip;
|
||||||
|
|
||||||
|
/* The next set of registers are included with
|
||||||
|
* MD_CONTEXT_AMD64_FLOATING_POINT
|
||||||
|
*/
|
||||||
|
union {
|
||||||
|
MDXmmSaveArea32AMD64 flt_save;
|
||||||
|
struct {
|
||||||
|
u_int128_t header[2];
|
||||||
|
u_int128_t legacy[8];
|
||||||
|
u_int128_t xmm0;
|
||||||
|
u_int128_t xmm1;
|
||||||
|
u_int128_t xmm2;
|
||||||
|
u_int128_t xmm3;
|
||||||
|
u_int128_t xmm4;
|
||||||
|
u_int128_t xmm5;
|
||||||
|
u_int128_t xmm6;
|
||||||
|
u_int128_t xmm7;
|
||||||
|
u_int128_t xmm8;
|
||||||
|
u_int128_t xmm9;
|
||||||
|
u_int128_t xmm10;
|
||||||
|
u_int128_t xmm11;
|
||||||
|
u_int128_t xmm12;
|
||||||
|
u_int128_t xmm13;
|
||||||
|
u_int128_t xmm14;
|
||||||
|
u_int128_t xmm15;
|
||||||
|
} sse_registers;
|
||||||
|
};
|
||||||
|
|
||||||
|
u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||||
|
u_int64_t vector_control;
|
||||||
|
|
||||||
|
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||||
|
u_int64_t debug_control;
|
||||||
|
u_int64_t last_branch_to_rip;
|
||||||
|
u_int64_t last_branch_from_rip;
|
||||||
|
u_int64_t last_exception_to_rip;
|
||||||
|
u_int64_t last_exception_from_rip;
|
||||||
|
|
||||||
|
} MDRawContextAMD64; /* CONTEXT */
|
||||||
|
|
||||||
|
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||||
|
* context stored in the structure. The high 26 bits identify the CPU, the
|
||||||
|
* low 6 bits identify the type of context saved. */
|
||||||
|
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
|
||||||
|
/* CONTEXT_CONTROL */
|
||||||
|
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
|
||||||
|
/* CONTEXT_INTEGER */
|
||||||
|
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004)
|
||||||
|
/* CONTEXT_SEGMENTS */
|
||||||
|
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008)
|
||||||
|
/* CONTEXT_FLOATING_POINT */
|
||||||
|
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
|
||||||
|
/* CONTEXT_DEBUG_REGISTERS */
|
||||||
|
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
|
||||||
|
* I think it really means CONTEXT_FLOATING_POINT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \
|
||||||
|
MD_CONTEXT_AMD64_INTEGER | \
|
||||||
|
MD_CONTEXT_AMD64_FLOATING_POINT)
|
||||||
|
/* CONTEXT_FULL */
|
||||||
|
|
||||||
|
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \
|
||||||
|
MD_CONTEXT_AMD64_SEGMENTS | \
|
||||||
|
MD_CONTEXT_X86_DEBUG_REGISTERS)
|
||||||
|
/* CONTEXT_ALL */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPARC support, see (solaris)sys/procfs_isa.h also
|
* SPARC support, see (solaris)sys/procfs_isa.h also
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -175,8 +175,9 @@ class MinidumpContext : public MinidumpStream {
|
||||||
// Returns raw CPU-specific context data for the named CPU type. If the
|
// Returns raw CPU-specific context data for the named CPU type. If the
|
||||||
// context data does not match the CPU type or does not exist, returns
|
// context data does not match the CPU type or does not exist, returns
|
||||||
// NULL.
|
// NULL.
|
||||||
const MDRawContextX86* GetContextX86() const;
|
const MDRawContextX86* GetContextX86() const;
|
||||||
const MDRawContextPPC* GetContextPPC() const;
|
const MDRawContextPPC* GetContextPPC() const;
|
||||||
|
const MDRawContextAMD64* GetContextAMD64() const;
|
||||||
const MDRawContextSPARC* GetContextSPARC() const;
|
const MDRawContextSPARC* GetContextSPARC() const;
|
||||||
|
|
||||||
// Print a human-readable representation of the object to stdout.
|
// Print a human-readable representation of the object to stdout.
|
||||||
|
@ -200,11 +201,15 @@ class MinidumpContext : public MinidumpStream {
|
||||||
// not contain a system info stream.
|
// not contain a system info stream.
|
||||||
bool CheckAgainstSystemInfo(u_int32_t context_cpu_type);
|
bool CheckAgainstSystemInfo(u_int32_t context_cpu_type);
|
||||||
|
|
||||||
|
// Store this separately because of the weirdo AMD64 context
|
||||||
|
u_int32_t context_flags_;
|
||||||
|
|
||||||
// The CPU-specific context structure.
|
// The CPU-specific context structure.
|
||||||
union {
|
union {
|
||||||
MDRawContextBase* base;
|
MDRawContextBase* base;
|
||||||
MDRawContextX86* x86;
|
MDRawContextX86* x86;
|
||||||
MDRawContextPPC* ppc;
|
MDRawContextPPC* ppc;
|
||||||
|
MDRawContextAMD64* amd64;
|
||||||
// on Solaris SPARC, sparc is defined as a numeric constant,
|
// on Solaris SPARC, sparc is defined as a numeric constant,
|
||||||
// so variables can NOT be named as sparc
|
// so variables can NOT be named as sparc
|
||||||
MDRawContextSPARC* ctx_sparc;
|
MDRawContextSPARC* ctx_sparc;
|
||||||
|
|
|
@ -98,6 +98,32 @@ struct StackFramePPC : public StackFrame {
|
||||||
int context_validity;
|
int context_validity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StackFrameAMD64 : public StackFrame {
|
||||||
|
// ContextValidity has one entry for each relevant hardware pointer register
|
||||||
|
// (%rip and %rsp) and one entry for each nonvolatile (callee-save) register.
|
||||||
|
//FIXME: validate this list
|
||||||
|
enum ContextValidity {
|
||||||
|
CONTEXT_VALID_NONE = 0,
|
||||||
|
CONTEXT_VALID_RIP = 1 << 0,
|
||||||
|
CONTEXT_VALID_RSP = 1 << 1,
|
||||||
|
CONTEXT_VALID_RBP = 1 << 2,
|
||||||
|
CONTEXT_VALID_ALL = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
StackFrameAMD64() : context(), context_validity(CONTEXT_VALID_NONE) {}
|
||||||
|
|
||||||
|
// Register state. This is only fully valid for the topmost frame in a
|
||||||
|
// stack. In other frames, the values of nonvolatile registers may be
|
||||||
|
// present, given sufficient debugging information. Refer to
|
||||||
|
// context_validity.
|
||||||
|
MDRawContextAMD64 context;
|
||||||
|
|
||||||
|
// context_validity is actually ContextValidity, but int is used because
|
||||||
|
// the OR operator doesn't work well with enumerated types. This indicates
|
||||||
|
// which fields in context are valid.
|
||||||
|
int context_validity;
|
||||||
|
};
|
||||||
|
|
||||||
struct StackFrameSPARC : public StackFrame {
|
struct StackFrameSPARC : public StackFrame {
|
||||||
// to be confirmed
|
// to be confirmed
|
||||||
enum ContextValidity {
|
enum ContextValidity {
|
||||||
|
|
|
@ -271,6 +271,7 @@ MinidumpStream::MinidumpStream(Minidump* minidump)
|
||||||
|
|
||||||
MinidumpContext::MinidumpContext(Minidump* minidump)
|
MinidumpContext::MinidumpContext(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
|
context_flags_(0),
|
||||||
context_() {
|
context_() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,233 +287,334 @@ bool MinidumpContext::Read(u_int32_t expected_size) {
|
||||||
FreeContext();
|
FreeContext();
|
||||||
|
|
||||||
// First, figure out what type of CPU this context structure is for.
|
// First, figure out what type of CPU this context structure is for.
|
||||||
u_int32_t context_flags;
|
// For some reason, the AMD64 Context doesn't have context_flags
|
||||||
if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
|
// at the beginning of the structure, so special case it here.
|
||||||
BPLOG(ERROR) << "MinidumpContext could not read context flags";
|
if (expected_size == sizeof(MDRawContextAMD64)) {
|
||||||
return false;
|
BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
|
||||||
}
|
|
||||||
if (minidump_->swap())
|
|
||||||
Swap(&context_flags);
|
|
||||||
|
|
||||||
u_int32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
|
scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
|
||||||
|
if (!minidump_->ReadBytes(context_amd64.get(),
|
||||||
// Allocate the context structure for the correct CPU and fill it. The
|
sizeof(MDRawContextAMD64))) {
|
||||||
// casts are slightly unorthodox, but it seems better to do that than to
|
BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
|
||||||
// maintain a separate pointer for each type of CPU context structure
|
return false;
|
||||||
// when only one of them will be used.
|
|
||||||
switch (cpu_type) {
|
|
||||||
case MD_CONTEXT_X86: {
|
|
||||||
if (expected_size != sizeof(MDRawContextX86)) {
|
|
||||||
BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
|
|
||||||
expected_size << " != " << sizeof(MDRawContextX86);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
|
|
||||||
|
|
||||||
// Set the context_flags member, which has already been read, and
|
|
||||||
// read the rest of the structure beginning with the first member
|
|
||||||
// after context_flags.
|
|
||||||
context_x86->context_flags = context_flags;
|
|
||||||
|
|
||||||
size_t flags_size = sizeof(context_x86->context_flags);
|
|
||||||
u_int8_t* context_after_flags =
|
|
||||||
reinterpret_cast<u_int8_t*>(context_x86.get()) + flags_size;
|
|
||||||
if (!minidump_->ReadBytes(context_after_flags,
|
|
||||||
sizeof(MDRawContextX86) - flags_size)) {
|
|
||||||
BPLOG(ERROR) << "MinidumpContext could not read x86 context";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do this after reading the entire MDRawContext structure because
|
|
||||||
// GetSystemInfo may seek minidump to a new position.
|
|
||||||
if (!CheckAgainstSystemInfo(cpu_type)) {
|
|
||||||
BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minidump_->swap()) {
|
|
||||||
// context_x86->context_flags was already swapped.
|
|
||||||
Swap(&context_x86->dr0);
|
|
||||||
Swap(&context_x86->dr1);
|
|
||||||
Swap(&context_x86->dr2);
|
|
||||||
Swap(&context_x86->dr3);
|
|
||||||
Swap(&context_x86->dr6);
|
|
||||||
Swap(&context_x86->dr7);
|
|
||||||
Swap(&context_x86->float_save.control_word);
|
|
||||||
Swap(&context_x86->float_save.status_word);
|
|
||||||
Swap(&context_x86->float_save.tag_word);
|
|
||||||
Swap(&context_x86->float_save.error_offset);
|
|
||||||
Swap(&context_x86->float_save.error_selector);
|
|
||||||
Swap(&context_x86->float_save.data_offset);
|
|
||||||
Swap(&context_x86->float_save.data_selector);
|
|
||||||
// context_x86->float_save.register_area[] contains 8-bit quantities
|
|
||||||
// and does not need to be swapped.
|
|
||||||
Swap(&context_x86->float_save.cr0_npx_state);
|
|
||||||
Swap(&context_x86->gs);
|
|
||||||
Swap(&context_x86->fs);
|
|
||||||
Swap(&context_x86->es);
|
|
||||||
Swap(&context_x86->ds);
|
|
||||||
Swap(&context_x86->edi);
|
|
||||||
Swap(&context_x86->esi);
|
|
||||||
Swap(&context_x86->ebx);
|
|
||||||
Swap(&context_x86->edx);
|
|
||||||
Swap(&context_x86->ecx);
|
|
||||||
Swap(&context_x86->eax);
|
|
||||||
Swap(&context_x86->ebp);
|
|
||||||
Swap(&context_x86->eip);
|
|
||||||
Swap(&context_x86->cs);
|
|
||||||
Swap(&context_x86->eflags);
|
|
||||||
Swap(&context_x86->esp);
|
|
||||||
Swap(&context_x86->ss);
|
|
||||||
// context_x86->extended_registers[] contains 8-bit quantities and
|
|
||||||
// does not need to be swapped.
|
|
||||||
}
|
|
||||||
|
|
||||||
context_.x86 = context_x86.release();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case MD_CONTEXT_PPC: {
|
if (minidump_->swap())
|
||||||
if (expected_size != sizeof(MDRawContextPPC)) {
|
Swap(&context_amd64->context_flags);
|
||||||
BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
|
|
||||||
expected_size << " != " << sizeof(MDRawContextPPC);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
|
u_int32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
|
||||||
|
|
||||||
// Set the context_flags member, which has already been read, and
|
if (cpu_type != MD_CONTEXT_AMD64) {
|
||||||
// read the rest of the structure beginning with the first member
|
//TODO: fall through to switch below?
|
||||||
// after context_flags.
|
// need a Tell method to be able to SeekSet back to beginning
|
||||||
context_ppc->context_flags = context_flags;
|
// http://code.google.com/p/google-breakpad/issues/detail?id=224
|
||||||
|
BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size_t flags_size = sizeof(context_ppc->context_flags);
|
// Do this after reading the entire MDRawContext structure because
|
||||||
u_int8_t* context_after_flags =
|
// GetSystemInfo may seek minidump to a new position.
|
||||||
reinterpret_cast<u_int8_t*>(context_ppc.get()) + flags_size;
|
if (!CheckAgainstSystemInfo(cpu_type)) {
|
||||||
if (!minidump_->ReadBytes(context_after_flags,
|
BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
|
||||||
sizeof(MDRawContextPPC) - flags_size)) {
|
return false;
|
||||||
BPLOG(ERROR) << "MinidumpContext could not read ppc context";
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do this after reading the entire MDRawContext structure because
|
// Normalize the 128-bit types in the dump.
|
||||||
// GetSystemInfo may seek minidump to a new position.
|
// Since this is AMD64, by definition, the values are little-endian.
|
||||||
if (!CheckAgainstSystemInfo(cpu_type)) {
|
for (unsigned int vr_index = 0;
|
||||||
BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
|
vr_index < MD_CONTEXT_AMD64_VR_COUNT;
|
||||||
return false;
|
++vr_index)
|
||||||
}
|
Normalize128(&context_amd64->vector_register[vr_index], false);
|
||||||
|
|
||||||
|
if (minidump_->swap()) {
|
||||||
|
Swap(&context_amd64->p1_home);
|
||||||
|
Swap(&context_amd64->p2_home);
|
||||||
|
Swap(&context_amd64->p3_home);
|
||||||
|
Swap(&context_amd64->p4_home);
|
||||||
|
Swap(&context_amd64->p5_home);
|
||||||
|
Swap(&context_amd64->p6_home);
|
||||||
|
// context_flags is already swapped
|
||||||
|
Swap(&context_amd64->mx_csr);
|
||||||
|
Swap(&context_amd64->cs);
|
||||||
|
Swap(&context_amd64->ds);
|
||||||
|
Swap(&context_amd64->es);
|
||||||
|
Swap(&context_amd64->fs);
|
||||||
|
Swap(&context_amd64->ss);
|
||||||
|
Swap(&context_amd64->eflags);
|
||||||
|
Swap(&context_amd64->dr0);
|
||||||
|
Swap(&context_amd64->dr1);
|
||||||
|
Swap(&context_amd64->dr2);
|
||||||
|
Swap(&context_amd64->dr3);
|
||||||
|
Swap(&context_amd64->dr6);
|
||||||
|
Swap(&context_amd64->dr7);
|
||||||
|
Swap(&context_amd64->rax);
|
||||||
|
Swap(&context_amd64->rcx);
|
||||||
|
Swap(&context_amd64->rdx);
|
||||||
|
Swap(&context_amd64->rbx);
|
||||||
|
Swap(&context_amd64->rsp);
|
||||||
|
Swap(&context_amd64->rbp);
|
||||||
|
Swap(&context_amd64->rsi);
|
||||||
|
Swap(&context_amd64->rdi);
|
||||||
|
Swap(&context_amd64->r8);
|
||||||
|
Swap(&context_amd64->r9);
|
||||||
|
Swap(&context_amd64->r10);
|
||||||
|
Swap(&context_amd64->r11);
|
||||||
|
Swap(&context_amd64->r12);
|
||||||
|
Swap(&context_amd64->r13);
|
||||||
|
Swap(&context_amd64->r14);
|
||||||
|
Swap(&context_amd64->r15);
|
||||||
|
Swap(&context_amd64->rip);
|
||||||
|
//FIXME: I'm not sure what actually determines
|
||||||
|
// which member of the union {flt_save, sse_registers}
|
||||||
|
// is valid. We're not currently using either,
|
||||||
|
// but it would be good to have them swapped properly.
|
||||||
|
|
||||||
// Normalize the 128-bit types in the dump.
|
|
||||||
// Since this is PowerPC, by definition, the values are big-endian.
|
|
||||||
for (unsigned int vr_index = 0;
|
for (unsigned int vr_index = 0;
|
||||||
vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
|
vr_index < MD_CONTEXT_AMD64_VR_COUNT;
|
||||||
++vr_index) {
|
++vr_index)
|
||||||
Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
|
Swap(&context_amd64->vector_register[vr_index]);
|
||||||
|
Swap(&context_amd64->vector_control);
|
||||||
|
Swap(&context_amd64->debug_control);
|
||||||
|
Swap(&context_amd64->last_branch_to_rip);
|
||||||
|
Swap(&context_amd64->last_branch_from_rip);
|
||||||
|
Swap(&context_amd64->last_exception_to_rip);
|
||||||
|
Swap(&context_amd64->last_exception_from_rip);
|
||||||
|
}
|
||||||
|
|
||||||
|
context_flags_ = context_amd64->context_flags;
|
||||||
|
|
||||||
|
context_.amd64 = context_amd64.release();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u_int32_t context_flags;
|
||||||
|
if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext could not read context flags";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (minidump_->swap())
|
||||||
|
Swap(&context_flags);
|
||||||
|
|
||||||
|
u_int32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
|
||||||
|
|
||||||
|
// Allocate the context structure for the correct CPU and fill it. The
|
||||||
|
// casts are slightly unorthodox, but it seems better to do that than to
|
||||||
|
// maintain a separate pointer for each type of CPU context structure
|
||||||
|
// when only one of them will be used.
|
||||||
|
switch (cpu_type) {
|
||||||
|
case MD_CONTEXT_X86: {
|
||||||
|
if (expected_size != sizeof(MDRawContextX86)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
|
||||||
|
expected_size << " != " << sizeof(MDRawContextX86);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
|
||||||
|
|
||||||
|
// Set the context_flags member, which has already been read, and
|
||||||
|
// read the rest of the structure beginning with the first member
|
||||||
|
// after context_flags.
|
||||||
|
context_x86->context_flags = context_flags;
|
||||||
|
|
||||||
|
size_t flags_size = sizeof(context_x86->context_flags);
|
||||||
|
u_int8_t* context_after_flags =
|
||||||
|
reinterpret_cast<u_int8_t*>(context_x86.get()) + flags_size;
|
||||||
|
if (!minidump_->ReadBytes(context_after_flags,
|
||||||
|
sizeof(MDRawContextX86) - flags_size)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext could not read x86 context";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do this after reading the entire MDRawContext structure because
|
||||||
|
// GetSystemInfo may seek minidump to a new position.
|
||||||
|
if (!CheckAgainstSystemInfo(cpu_type)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minidump_->swap()) {
|
||||||
|
// context_x86->context_flags was already swapped.
|
||||||
|
Swap(&context_x86->dr0);
|
||||||
|
Swap(&context_x86->dr1);
|
||||||
|
Swap(&context_x86->dr2);
|
||||||
|
Swap(&context_x86->dr3);
|
||||||
|
Swap(&context_x86->dr6);
|
||||||
|
Swap(&context_x86->dr7);
|
||||||
|
Swap(&context_x86->float_save.control_word);
|
||||||
|
Swap(&context_x86->float_save.status_word);
|
||||||
|
Swap(&context_x86->float_save.tag_word);
|
||||||
|
Swap(&context_x86->float_save.error_offset);
|
||||||
|
Swap(&context_x86->float_save.error_selector);
|
||||||
|
Swap(&context_x86->float_save.data_offset);
|
||||||
|
Swap(&context_x86->float_save.data_selector);
|
||||||
|
// context_x86->float_save.register_area[] contains 8-bit quantities
|
||||||
|
// and does not need to be swapped.
|
||||||
|
Swap(&context_x86->float_save.cr0_npx_state);
|
||||||
|
Swap(&context_x86->gs);
|
||||||
|
Swap(&context_x86->fs);
|
||||||
|
Swap(&context_x86->es);
|
||||||
|
Swap(&context_x86->ds);
|
||||||
|
Swap(&context_x86->edi);
|
||||||
|
Swap(&context_x86->esi);
|
||||||
|
Swap(&context_x86->ebx);
|
||||||
|
Swap(&context_x86->edx);
|
||||||
|
Swap(&context_x86->ecx);
|
||||||
|
Swap(&context_x86->eax);
|
||||||
|
Swap(&context_x86->ebp);
|
||||||
|
Swap(&context_x86->eip);
|
||||||
|
Swap(&context_x86->cs);
|
||||||
|
Swap(&context_x86->eflags);
|
||||||
|
Swap(&context_x86->esp);
|
||||||
|
Swap(&context_x86->ss);
|
||||||
|
// context_x86->extended_registers[] contains 8-bit quantities and
|
||||||
|
// does not need to be swapped.
|
||||||
|
}
|
||||||
|
|
||||||
|
context_.x86 = context_x86.release();
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minidump_->swap()) {
|
case MD_CONTEXT_PPC: {
|
||||||
// context_ppc->context_flags was already swapped.
|
if (expected_size != sizeof(MDRawContextPPC)) {
|
||||||
Swap(&context_ppc->srr0);
|
BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
|
||||||
Swap(&context_ppc->srr1);
|
expected_size << " != " << sizeof(MDRawContextPPC);
|
||||||
for (unsigned int gpr_index = 0;
|
return false;
|
||||||
gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
|
|
||||||
++gpr_index) {
|
|
||||||
Swap(&context_ppc->gpr[gpr_index]);
|
|
||||||
}
|
}
|
||||||
Swap(&context_ppc->cr);
|
|
||||||
Swap(&context_ppc->xer);
|
scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
|
||||||
Swap(&context_ppc->lr);
|
|
||||||
Swap(&context_ppc->ctr);
|
// Set the context_flags member, which has already been read, and
|
||||||
Swap(&context_ppc->mq);
|
// read the rest of the structure beginning with the first member
|
||||||
Swap(&context_ppc->vrsave);
|
// after context_flags.
|
||||||
for (unsigned int fpr_index = 0;
|
context_ppc->context_flags = context_flags;
|
||||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
|
||||||
++fpr_index) {
|
size_t flags_size = sizeof(context_ppc->context_flags);
|
||||||
Swap(&context_ppc->float_save.fpregs[fpr_index]);
|
u_int8_t* context_after_flags =
|
||||||
|
reinterpret_cast<u_int8_t*>(context_ppc.get()) + flags_size;
|
||||||
|
if (!minidump_->ReadBytes(context_after_flags,
|
||||||
|
sizeof(MDRawContextPPC) - flags_size)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext could not read ppc context";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// Don't swap context_ppc->float_save.fpscr_pad because it is only
|
|
||||||
// used for padding.
|
// Do this after reading the entire MDRawContext structure because
|
||||||
Swap(&context_ppc->float_save.fpscr);
|
// GetSystemInfo may seek minidump to a new position.
|
||||||
|
if (!CheckAgainstSystemInfo(cpu_type)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the 128-bit types in the dump.
|
||||||
|
// Since this is PowerPC, by definition, the values are big-endian.
|
||||||
for (unsigned int vr_index = 0;
|
for (unsigned int vr_index = 0;
|
||||||
vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
|
vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
|
||||||
++vr_index) {
|
++vr_index) {
|
||||||
Swap(&context_ppc->vector_save.save_vr[vr_index]);
|
Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
|
||||||
}
|
}
|
||||||
Swap(&context_ppc->vector_save.save_vscr);
|
|
||||||
// Don't swap the padding fields in vector_save.
|
|
||||||
Swap(&context_ppc->vector_save.save_vrvalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
context_.ppc = context_ppc.release();
|
if (minidump_->swap()) {
|
||||||
|
// context_ppc->context_flags was already swapped.
|
||||||
break;
|
Swap(&context_ppc->srr0);
|
||||||
}
|
Swap(&context_ppc->srr1);
|
||||||
|
for (unsigned int gpr_index = 0;
|
||||||
case MD_CONTEXT_SPARC: {
|
gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
|
||||||
if (expected_size != sizeof(MDRawContextSPARC)) {
|
++gpr_index) {
|
||||||
BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
|
Swap(&context_ppc->gpr[gpr_index]);
|
||||||
expected_size << " != " << sizeof(MDRawContextSPARC);
|
}
|
||||||
return false;
|
Swap(&context_ppc->cr);
|
||||||
}
|
Swap(&context_ppc->xer);
|
||||||
|
Swap(&context_ppc->lr);
|
||||||
scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
|
Swap(&context_ppc->ctr);
|
||||||
|
Swap(&context_ppc->mq);
|
||||||
// Set the context_flags member, which has already been read, and
|
Swap(&context_ppc->vrsave);
|
||||||
// read the rest of the structure beginning with the first member
|
for (unsigned int fpr_index = 0;
|
||||||
// after context_flags.
|
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||||
context_sparc->context_flags = context_flags;
|
++fpr_index) {
|
||||||
|
Swap(&context_ppc->float_save.fpregs[fpr_index]);
|
||||||
size_t flags_size = sizeof(context_sparc->context_flags);
|
}
|
||||||
u_int8_t* context_after_flags =
|
// Don't swap context_ppc->float_save.fpscr_pad because it is only
|
||||||
reinterpret_cast<u_int8_t*>(context_sparc.get()) + flags_size;
|
// used for padding.
|
||||||
if (!minidump_->ReadBytes(context_after_flags,
|
Swap(&context_ppc->float_save.fpscr);
|
||||||
sizeof(MDRawContextSPARC) - flags_size)) {
|
for (unsigned int vr_index = 0;
|
||||||
BPLOG(ERROR) << "MinidumpContext could not read sparc context";
|
vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
|
||||||
return false;
|
++vr_index) {
|
||||||
}
|
Swap(&context_ppc->vector_save.save_vr[vr_index]);
|
||||||
|
}
|
||||||
// Do this after reading the entire MDRawContext structure because
|
Swap(&context_ppc->vector_save.save_vscr);
|
||||||
// GetSystemInfo may seek minidump to a new position.
|
// Don't swap the padding fields in vector_save.
|
||||||
if (!CheckAgainstSystemInfo(cpu_type)) {
|
Swap(&context_ppc->vector_save.save_vrvalid);
|
||||||
BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minidump_->swap()) {
|
|
||||||
// context_sparc->context_flags was already swapped.
|
|
||||||
for (unsigned int gpr_index = 0;
|
|
||||||
gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
|
|
||||||
++gpr_index) {
|
|
||||||
Swap(&context_sparc->g_r[gpr_index]);
|
|
||||||
}
|
}
|
||||||
Swap(&context_sparc->ccr);
|
|
||||||
Swap(&context_sparc->pc);
|
context_.ppc = context_ppc.release();
|
||||||
Swap(&context_sparc->npc);
|
|
||||||
Swap(&context_sparc->y);
|
break;
|
||||||
Swap(&context_sparc->asi);
|
|
||||||
Swap(&context_sparc->fprs);
|
|
||||||
for (unsigned int fpr_index = 0;
|
|
||||||
fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
|
|
||||||
++fpr_index) {
|
|
||||||
Swap(&context_sparc->float_save.regs[fpr_index]);
|
|
||||||
}
|
|
||||||
Swap(&context_sparc->float_save.filler);
|
|
||||||
Swap(&context_sparc->float_save.fsr);
|
|
||||||
}
|
}
|
||||||
context_.ctx_sparc = context_sparc.release();
|
|
||||||
|
|
||||||
break;
|
case MD_CONTEXT_SPARC: {
|
||||||
}
|
if (expected_size != sizeof(MDRawContextSPARC)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
|
||||||
|
expected_size << " != " << sizeof(MDRawContextSPARC);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
|
||||||
// Unknown context type
|
|
||||||
BPLOG(ERROR) << "MinidumpContext unknown context type " <<
|
// Set the context_flags member, which has already been read, and
|
||||||
HexString(cpu_type);
|
// read the rest of the structure beginning with the first member
|
||||||
return false;
|
// after context_flags.
|
||||||
break;
|
context_sparc->context_flags = context_flags;
|
||||||
|
|
||||||
|
size_t flags_size = sizeof(context_sparc->context_flags);
|
||||||
|
u_int8_t* context_after_flags =
|
||||||
|
reinterpret_cast<u_int8_t*>(context_sparc.get()) + flags_size;
|
||||||
|
if (!minidump_->ReadBytes(context_after_flags,
|
||||||
|
sizeof(MDRawContextSPARC) - flags_size)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext could not read sparc context";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do this after reading the entire MDRawContext structure because
|
||||||
|
// GetSystemInfo may seek minidump to a new position.
|
||||||
|
if (!CheckAgainstSystemInfo(cpu_type)) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minidump_->swap()) {
|
||||||
|
// context_sparc->context_flags was already swapped.
|
||||||
|
for (unsigned int gpr_index = 0;
|
||||||
|
gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
|
||||||
|
++gpr_index) {
|
||||||
|
Swap(&context_sparc->g_r[gpr_index]);
|
||||||
|
}
|
||||||
|
Swap(&context_sparc->ccr);
|
||||||
|
Swap(&context_sparc->pc);
|
||||||
|
Swap(&context_sparc->npc);
|
||||||
|
Swap(&context_sparc->y);
|
||||||
|
Swap(&context_sparc->asi);
|
||||||
|
Swap(&context_sparc->fprs);
|
||||||
|
for (unsigned int fpr_index = 0;
|
||||||
|
fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
|
||||||
|
++fpr_index) {
|
||||||
|
Swap(&context_sparc->float_save.regs[fpr_index]);
|
||||||
|
}
|
||||||
|
Swap(&context_sparc->float_save.filler);
|
||||||
|
Swap(&context_sparc->float_save.fsr);
|
||||||
|
}
|
||||||
|
context_.ctx_sparc = context_sparc.release();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
// Unknown context type
|
||||||
|
BPLOG(ERROR) << "MinidumpContext unknown context type " <<
|
||||||
|
HexString(cpu_type);
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
context_flags_ = context_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_ = true;
|
valid_ = true;
|
||||||
|
@ -527,7 +629,7 @@ u_int32_t MinidumpContext::GetContextCPU() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context_.base->context_flags & MD_CONTEXT_CPU_MASK;
|
return context_flags_ & MD_CONTEXT_CPU_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -550,6 +652,15 @@ const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
|
||||||
return context_.ppc;
|
return context_.ppc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
|
||||||
|
if (GetContextCPU() != MD_CONTEXT_AMD64) {
|
||||||
|
BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context_.amd64;
|
||||||
|
}
|
||||||
|
|
||||||
const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
|
const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
|
||||||
if (GetContextCPU() != MD_CONTEXT_SPARC) {
|
if (GetContextCPU() != MD_CONTEXT_SPARC) {
|
||||||
BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
|
BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
|
||||||
|
@ -569,6 +680,10 @@ void MinidumpContext::FreeContext() {
|
||||||
delete context_.ppc;
|
delete context_.ppc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MD_CONTEXT_AMD64:
|
||||||
|
delete context_.amd64;
|
||||||
|
break;
|
||||||
|
|
||||||
case MD_CONTEXT_SPARC:
|
case MD_CONTEXT_SPARC:
|
||||||
delete context_.ctx_sparc;
|
delete context_.ctx_sparc;
|
||||||
break;
|
break;
|
||||||
|
@ -580,6 +695,7 @@ void MinidumpContext::FreeContext() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context_flags_ = 0;
|
||||||
context_.base = NULL;
|
context_.base = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,6 +737,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) {
|
||||||
return_value = true;
|
return_value = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MD_CONTEXT_AMD64:
|
||||||
|
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
|
||||||
|
return_value = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case MD_CONTEXT_SPARC:
|
case MD_CONTEXT_SPARC:
|
||||||
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
|
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
|
||||||
return_value = true;
|
return_value = true;
|
||||||
|
@ -745,6 +866,60 @@ void MinidumpContext::Print() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MD_CONTEXT_AMD64: {
|
||||||
|
const MDRawContextAMD64* context_amd64 = GetContextAMD64();
|
||||||
|
printf("MDRawContextAMD64\n");
|
||||||
|
printf(" p1_home = 0x%llx\n",
|
||||||
|
context_amd64->p1_home);
|
||||||
|
printf(" p2_home = 0x%llx\n",
|
||||||
|
context_amd64->p2_home);
|
||||||
|
printf(" p3_home = 0x%llx\n",
|
||||||
|
context_amd64->p3_home);
|
||||||
|
printf(" p4_home = 0x%llx\n",
|
||||||
|
context_amd64->p4_home);
|
||||||
|
printf(" p5_home = 0x%llx\n",
|
||||||
|
context_amd64->p5_home);
|
||||||
|
printf(" p6_home = 0x%llx\n",
|
||||||
|
context_amd64->p6_home);
|
||||||
|
printf(" context_flags = 0x%x\n",
|
||||||
|
context_amd64->context_flags);
|
||||||
|
printf(" mx_csr = 0x%x\n",
|
||||||
|
context_amd64->mx_csr);
|
||||||
|
printf(" cs = 0x%x\n", context_amd64->cs);
|
||||||
|
printf(" ds = 0x%x\n", context_amd64->ds);
|
||||||
|
printf(" es = 0x%x\n", context_amd64->es);
|
||||||
|
printf(" fs = 0x%x\n", context_amd64->fs);
|
||||||
|
printf(" gs = 0x%x\n", context_amd64->gs);
|
||||||
|
printf(" ss = 0x%x\n", context_amd64->ss);
|
||||||
|
printf(" eflags = 0x%x\n", context_amd64->eflags);
|
||||||
|
printf(" dr0 = 0x%llx\n", context_amd64->dr0);
|
||||||
|
printf(" dr1 = 0x%llx\n", context_amd64->dr1);
|
||||||
|
printf(" dr2 = 0x%llx\n", context_amd64->dr2);
|
||||||
|
printf(" dr3 = 0x%llx\n", context_amd64->dr3);
|
||||||
|
printf(" dr6 = 0x%llx\n", context_amd64->dr6);
|
||||||
|
printf(" dr7 = 0x%llx\n", context_amd64->dr7);
|
||||||
|
printf(" rax = 0x%llx\n", context_amd64->rax);
|
||||||
|
printf(" rcx = 0x%llx\n", context_amd64->rcx);
|
||||||
|
printf(" rdx = 0x%llx\n", context_amd64->rdx);
|
||||||
|
printf(" rbx = 0x%llx\n", context_amd64->rbx);
|
||||||
|
printf(" rsp = 0x%llx\n", context_amd64->rsp);
|
||||||
|
printf(" rbp = 0x%llx\n", context_amd64->rbp);
|
||||||
|
printf(" rsi = 0x%llx\n", context_amd64->rsi);
|
||||||
|
printf(" rdi = 0x%llx\n", context_amd64->rdi);
|
||||||
|
printf(" r8 = 0x%llx\n", context_amd64->r8);
|
||||||
|
printf(" r9 = 0x%llx\n", context_amd64->r9);
|
||||||
|
printf(" r10 = 0x%llx\n", context_amd64->r10);
|
||||||
|
printf(" r11 = 0x%llx\n", context_amd64->r11);
|
||||||
|
printf(" r12 = 0x%llx\n", context_amd64->r12);
|
||||||
|
printf(" r13 = 0x%llx\n", context_amd64->r13);
|
||||||
|
printf(" r14 = 0x%llx\n", context_amd64->r14);
|
||||||
|
printf(" r15 = 0x%llx\n", context_amd64->r15);
|
||||||
|
printf(" rip = 0x%llx\n", context_amd64->rip);
|
||||||
|
//TODO: print xmm, vector, debug registers
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MD_CONTEXT_SPARC: {
|
case MD_CONTEXT_SPARC: {
|
||||||
const MDRawContextSPARC* context_sparc = GetContextSPARC();
|
const MDRawContextSPARC* context_sparc = GetContextSPARC();
|
||||||
printf("MDRawContextSPARC\n");
|
printf("MDRawContextSPARC\n");
|
||||||
|
|
|
@ -258,8 +258,14 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (raw_system_info->processor_architecture) {
|
switch (raw_system_info->processor_architecture) {
|
||||||
case MD_CPU_ARCHITECTURE_X86: {
|
case MD_CPU_ARCHITECTURE_X86:
|
||||||
info->cpu = "x86";
|
case MD_CPU_ARCHITECTURE_AMD64: {
|
||||||
|
if (raw_system_info->processor_architecture ==
|
||||||
|
MD_CPU_ARCHITECTURE_X86)
|
||||||
|
info->cpu = "x86";
|
||||||
|
else
|
||||||
|
info->cpu = "amd64";
|
||||||
|
|
||||||
const string *cpu_vendor = system_info->GetCPUVendor();
|
const string *cpu_vendor = system_info->GetCPUVendor();
|
||||||
if (cpu_vendor) {
|
if (cpu_vendor) {
|
||||||
info->cpu_info = *cpu_vendor;
|
info->cpu_info = *cpu_vendor;
|
||||||
|
|
|
@ -68,6 +68,7 @@ using google_breakpad::StackFrame;
|
||||||
using google_breakpad::StackFramePPC;
|
using google_breakpad::StackFramePPC;
|
||||||
using google_breakpad::StackFrameSPARC;
|
using google_breakpad::StackFrameSPARC;
|
||||||
using google_breakpad::StackFrameX86;
|
using google_breakpad::StackFrameX86;
|
||||||
|
using google_breakpad::StackFrameAMD64;
|
||||||
|
|
||||||
// Separator character for machine readable output.
|
// Separator character for machine readable output.
|
||||||
static const char kOutputSeparator = '|';
|
static const char kOutputSeparator = '|';
|
||||||
|
@ -165,6 +166,16 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
|
||||||
sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
|
sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
|
||||||
if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
|
if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
|
||||||
sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
|
sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
|
||||||
|
} else if (cpu == "amd64") {
|
||||||
|
const StackFrameAMD64 *frame_amd64 =
|
||||||
|
reinterpret_cast<const StackFrameAMD64*>(frame);
|
||||||
|
|
||||||
|
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
|
||||||
|
sequence = PrintRegister("rip", frame_amd64->context.rip, sequence);
|
||||||
|
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
|
||||||
|
sequence = PrintRegister("rsp", frame_amd64->context.rsp, sequence);
|
||||||
|
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
|
||||||
|
sequence = PrintRegister("rbp", frame_amd64->context.rbp, sequence);
|
||||||
} else if (cpu == "sparc") {
|
} else if (cpu == "sparc") {
|
||||||
const StackFrameSPARC *frame_sparc =
|
const StackFrameSPARC *frame_sparc =
|
||||||
reinterpret_cast<const StackFrameSPARC*>(frame);
|
reinterpret_cast<const StackFrameSPARC*>(frame);
|
||||||
|
@ -176,7 +187,6 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
|
||||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
|
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
|
||||||
sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
|
sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "processor/stackwalker_ppc.h"
|
#include "processor/stackwalker_ppc.h"
|
||||||
#include "processor/stackwalker_sparc.h"
|
#include "processor/stackwalker_sparc.h"
|
||||||
#include "processor/stackwalker_x86.h"
|
#include "processor/stackwalker_x86.h"
|
||||||
|
#include "processor/stackwalker_amd64.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -164,6 +165,13 @@ Stackwalker* Stackwalker::StackwalkerForCPU(
|
||||||
memory, modules, supplier,
|
memory, modules, supplier,
|
||||||
resolver);
|
resolver);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MD_CONTEXT_AMD64:
|
||||||
|
cpu_stackwalker = new StackwalkerAMD64(system_info,
|
||||||
|
context->GetContextAMD64(),
|
||||||
|
memory, modules, supplier,
|
||||||
|
resolver);
|
||||||
|
break;
|
||||||
|
|
||||||
case MD_CONTEXT_SPARC:
|
case MD_CONTEXT_SPARC:
|
||||||
cpu_stackwalker = new StackwalkerSPARC(system_info,
|
cpu_stackwalker = new StackwalkerSPARC(system_info,
|
||||||
|
|
131
src/processor/stackwalker_amd64.cc
Normal file
131
src/processor/stackwalker_amd64.cc
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
// Copyright (c) 2007, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// stackwalker_amd64.cc: amd64-specific stackwalker.
|
||||||
|
//
|
||||||
|
// See stackwalker_amd64.h for documentation.
|
||||||
|
//
|
||||||
|
// Author: Mark Mentovai, Ted Mielczarek
|
||||||
|
|
||||||
|
|
||||||
|
#include "processor/stackwalker_amd64.h"
|
||||||
|
#include "google_breakpad/processor/call_stack.h"
|
||||||
|
#include "google_breakpad/processor/memory_region.h"
|
||||||
|
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
|
||||||
|
StackwalkerAMD64::StackwalkerAMD64(const SystemInfo *system_info,
|
||||||
|
const MDRawContextAMD64 *context,
|
||||||
|
MemoryRegion *memory,
|
||||||
|
const CodeModules *modules,
|
||||||
|
SymbolSupplier *supplier,
|
||||||
|
SourceLineResolverInterface *resolver)
|
||||||
|
: Stackwalker(system_info, memory, modules, supplier, resolver),
|
||||||
|
context_(context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StackFrame* StackwalkerAMD64::GetContextFrame() {
|
||||||
|
if (!context_ || !memory_) {
|
||||||
|
BPLOG(ERROR) << "Can't get context frame without context or memory";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackFrameAMD64 *frame = new StackFrameAMD64();
|
||||||
|
|
||||||
|
// The instruction pointer is stored directly in a register, so pull it
|
||||||
|
// straight out of the CPU context structure.
|
||||||
|
frame->context = *context_;
|
||||||
|
frame->context_validity = StackFrameAMD64::CONTEXT_VALID_ALL;
|
||||||
|
frame->instruction = frame->context.rip;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StackFrame* StackwalkerAMD64::GetCallerFrame(
|
||||||
|
const CallStack *stack,
|
||||||
|
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) {
|
||||||
|
if (!memory_ || !stack) {
|
||||||
|
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackFrameAMD64 *last_frame = static_cast<StackFrameAMD64*>(
|
||||||
|
stack->frames()->back());
|
||||||
|
|
||||||
|
//FIXME: this pretty much doesn't work at all due to FPO
|
||||||
|
// being enabled by default.
|
||||||
|
// Brain-dead stackwalking:
|
||||||
|
// %rip_new = *(%rbp_old + 8)
|
||||||
|
// %rsp_new = %rbp_old + 16
|
||||||
|
// %rbp_new = *(%rbp_old)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
u_int64_t stack_pointer = last_frame->context.rbp + 16;
|
||||||
|
if (stack_pointer <= last_frame->context.rsp) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int64_t instruction;
|
||||||
|
if (!memory_->GetMemoryAtAddress(last_frame->context.rbp + 8,
|
||||||
|
&instruction) ||
|
||||||
|
instruction <= 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int64_t stack_base;
|
||||||
|
if (!memory_->GetMemoryAtAddress(last_frame->context.rbp,
|
||||||
|
&stack_base) ||
|
||||||
|
stack_base <= 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackFrameAMD64 *frame = new StackFrameAMD64();
|
||||||
|
|
||||||
|
frame->context = last_frame->context;
|
||||||
|
frame->context.rip = instruction;
|
||||||
|
frame->context.rsp = stack_pointer;
|
||||||
|
frame->context.rbp = stack_base;
|
||||||
|
frame->context_validity = StackFrameAMD64::CONTEXT_VALID_RIP |
|
||||||
|
StackFrameAMD64::CONTEXT_VALID_RSP |
|
||||||
|
StackFrameAMD64::CONTEXT_VALID_RBP;
|
||||||
|
|
||||||
|
frame->instruction = frame->context.rip - 1;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace google_breakpad
|
80
src/processor/stackwalker_amd64.h
Normal file
80
src/processor/stackwalker_amd64.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright (c) 2007, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// stackwalker_amd64.h: amd64-specific stackwalker.
|
||||||
|
//
|
||||||
|
// Provides stack frames given amd64 register context and a memory region
|
||||||
|
// corresponding to a amd64 stack.
|
||||||
|
//
|
||||||
|
// Author: Mark Mentovai, Ted Mielczarek
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PROCESSOR_STACKWALKER_AMD64_H__
|
||||||
|
#define PROCESSOR_STACKWALKER_AMD64_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "google_breakpad/common/breakpad_types.h"
|
||||||
|
#include "google_breakpad/common/minidump_format.h"
|
||||||
|
#include "google_breakpad/processor/stackwalker.h"
|
||||||
|
|
||||||
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
class CodeModules;
|
||||||
|
|
||||||
|
class StackwalkerAMD64 : public Stackwalker {
|
||||||
|
public:
|
||||||
|
// context is a amd64 context object that gives access to amd64-specific
|
||||||
|
// register state corresponding to the innermost called frame to be
|
||||||
|
// included in the stack. The other arguments are passed directly through
|
||||||
|
// to the base Stackwalker constructor.
|
||||||
|
StackwalkerAMD64(const SystemInfo *system_info,
|
||||||
|
const MDRawContextAMD64 *context,
|
||||||
|
MemoryRegion *memory,
|
||||||
|
const CodeModules *modules,
|
||||||
|
SymbolSupplier *supplier,
|
||||||
|
SourceLineResolverInterface *resolver);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 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<StackFrameInfo> > &stack_frame_info);
|
||||||
|
|
||||||
|
// Stores the CPU context corresponding to the innermost stack frame to
|
||||||
|
// be returned by GetContextFrame.
|
||||||
|
const MDRawContextAMD64 *context_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace google_breakpad
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PROCESSOR_STACKWALKER_AMD64_H__
|
Loading…
Reference in a new issue