aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2007-10-31 19:20:31 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2007-10-31 19:20:31 +0000
commit8eb7111814953cb64ec0569b91ea99804b2d5b85 (patch)
treece847bcddb073b3c4ce9d1fbb2a3f4456d62b27d /src
parentFix warning regarding initialization order compared to definition order (diff)
downloadbreakpad-8eb7111814953cb64ec0569b91ea99804b2d5b85.tar.xz
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
Diffstat (limited to 'src')
-rw-r--r--src/google_breakpad/common/minidump_format.h154
-rw-r--r--src/google_breakpad/processor/minidump.h15
-rw-r--r--src/google_breakpad/processor/stack_frame_cpu.h26
-rw-r--r--src/processor/minidump.cc555
-rw-r--r--src/processor/minidump_processor.cc10
-rw-r--r--src/processor/minidump_stackwalk.cc12
-rw-r--r--src/processor/stackwalker.cc8
-rw-r--r--src/processor/stackwalker_amd64.cc131
-rw-r--r--src/processor/stackwalker_amd64.h80
9 files changed, 793 insertions, 198 deletions
diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h
index cb6811e0..229bb9b2 100644
--- a/src/google_breakpad/common/minidump_format.h
+++ b/src/google_breakpad/common/minidump_format.h
@@ -216,6 +216,160 @@ typedef struct {
#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
*/
diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h
index 474382b9..4e900fb1 100644
--- a/src/google_breakpad/processor/minidump.h
+++ b/src/google_breakpad/processor/minidump.h
@@ -175,8 +175,9 @@ class MinidumpContext : public MinidumpStream {
// 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
// NULL.
- const MDRawContextX86* GetContextX86() const;
- const MDRawContextPPC* GetContextPPC() const;
+ const MDRawContextX86* GetContextX86() const;
+ const MDRawContextPPC* GetContextPPC() const;
+ const MDRawContextAMD64* GetContextAMD64() const;
const MDRawContextSPARC* GetContextSPARC() const;
// Print a human-readable representation of the object to stdout.
@@ -200,11 +201,15 @@ class MinidumpContext : public MinidumpStream {
// not contain a system info stream.
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.
union {
- MDRawContextBase* base;
- MDRawContextX86* x86;
- MDRawContextPPC* ppc;
+ MDRawContextBase* base;
+ MDRawContextX86* x86;
+ MDRawContextPPC* ppc;
+ MDRawContextAMD64* amd64;
// on Solaris SPARC, sparc is defined as a numeric constant,
// so variables can NOT be named as sparc
MDRawContextSPARC* ctx_sparc;
diff --git a/src/google_breakpad/processor/stack_frame_cpu.h b/src/google_breakpad/processor/stack_frame_cpu.h
index 567c1b7e..a8840278 100644
--- a/src/google_breakpad/processor/stack_frame_cpu.h
+++ b/src/google_breakpad/processor/stack_frame_cpu.h
@@ -98,6 +98,32 @@ struct StackFramePPC : public StackFrame {
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 {
// to be confirmed
enum ContextValidity {
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index 3cce5ed7..d08ad12f 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -271,6 +271,7 @@ MinidumpStream::MinidumpStream(Minidump* minidump)
MinidumpContext::MinidumpContext(Minidump* minidump)
: MinidumpStream(minidump),
+ context_flags_(0),
context_() {
}
@@ -286,233 +287,334 @@ bool MinidumpContext::Read(u_int32_t expected_size) {
FreeContext();
// First, figure out what type of CPU this context structure is for.
- 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);
+ // For some reason, the AMD64 Context doesn't have context_flags
+ // at the beginning of the structure, so special case it here.
+ if (expected_size == sizeof(MDRawContextAMD64)) {
+ BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
+
+ scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
+ if (!minidump_->ReadBytes(context_amd64.get(),
+ sizeof(MDRawContextAMD64))) {
+ BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
+ return false;
+ }
- u_int32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
+ if (minidump_->swap())
+ Swap(&context_amd64->context_flags);
- // 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;
- }
+ u_int32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
- scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
+ if (cpu_type != MD_CONTEXT_AMD64) {
+ //TODO: fall through to switch below?
+ // need a Tell method to be able to SeekSet back to beginning
+ // http://code.google.com/p/google-breakpad/issues/detail?id=224
+ BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
+ return false;
+ }
- // 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;
+ // Do this after reading the entire MDRawContext structure because
+ // GetSystemInfo may seek minidump to a new position.
+ if (!CheckAgainstSystemInfo(cpu_type)) {
+ BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
+ return false;
+ }
- 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;
- }
+ // Normalize the 128-bit types in the dump.
+ // Since this is AMD64, by definition, the values are little-endian.
+ for (unsigned int vr_index = 0;
+ vr_index < MD_CONTEXT_AMD64_VR_COUNT;
+ ++vr_index)
+ Normalize128(&context_amd64->vector_register[vr_index], 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()) {
+ 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.
- 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.
- }
+ for (unsigned int vr_index = 0;
+ vr_index < MD_CONTEXT_AMD64_VR_COUNT;
+ ++vr_index)
+ 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_.x86 = context_x86.release();
+ context_flags_ = context_amd64->context_flags;
- break;
+ 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;
+ }
- case MD_CONTEXT_PPC: {
- if (expected_size != sizeof(MDRawContextPPC)) {
- BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
- expected_size << " != " << sizeof(MDRawContextPPC);
- return false;
- }
+ scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
- scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
+ // 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;
- // 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_ppc->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;
+ }
- size_t flags_size = sizeof(context_ppc->context_flags);
- 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;
- }
+ // 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;
+ }
- // Do this after reading the entire MDRawContext structure because
- // GetSystemInfo may seek minidump to a new position.
- if (!CheckAgainstSystemInfo(cpu_type)) {
- BPLOG(ERROR) << "MinidumpContext ppc 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.
+ }
- // 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;
- vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
- ++vr_index) {
- Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
+ context_.x86 = context_x86.release();
+
+ break;
}
- if (minidump_->swap()) {
- // context_ppc->context_flags was already swapped.
- Swap(&context_ppc->srr0);
- Swap(&context_ppc->srr1);
- for (unsigned int gpr_index = 0;
- gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
- ++gpr_index) {
- Swap(&context_ppc->gpr[gpr_index]);
+ case MD_CONTEXT_PPC: {
+ if (expected_size != sizeof(MDRawContextPPC)) {
+ BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
+ expected_size << " != " << sizeof(MDRawContextPPC);
+ return false;
+ }
+
+ scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
+
+ // 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_ppc->context_flags = context_flags;
+
+ size_t flags_size = sizeof(context_ppc->context_flags);
+ 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;
}
- Swap(&context_ppc->cr);
- Swap(&context_ppc->xer);
- Swap(&context_ppc->lr);
- Swap(&context_ppc->ctr);
- Swap(&context_ppc->mq);
- Swap(&context_ppc->vrsave);
- for (unsigned int fpr_index = 0;
- fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
- ++fpr_index) {
- Swap(&context_ppc->float_save.fpregs[fpr_index]);
+
+ // Do this after reading the entire MDRawContext structure because
+ // GetSystemInfo may seek minidump to a new position.
+ if (!CheckAgainstSystemInfo(cpu_type)) {
+ BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
+ return false;
}
- // Don't swap context_ppc->float_save.fpscr_pad because it is only
- // used for padding.
- Swap(&context_ppc->float_save.fpscr);
+
+ // 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;
vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
++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.
+ Swap(&context_ppc->srr0);
+ Swap(&context_ppc->srr1);
+ for (unsigned int gpr_index = 0;
+ gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
+ ++gpr_index) {
+ Swap(&context_ppc->gpr[gpr_index]);
+ }
+ Swap(&context_ppc->cr);
+ Swap(&context_ppc->xer);
+ Swap(&context_ppc->lr);
+ Swap(&context_ppc->ctr);
+ Swap(&context_ppc->mq);
+ Swap(&context_ppc->vrsave);
+ for (unsigned int fpr_index = 0;
+ fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
+ ++fpr_index) {
+ Swap(&context_ppc->float_save.fpregs[fpr_index]);
+ }
+ // Don't swap context_ppc->float_save.fpscr_pad because it is only
+ // used for padding.
+ Swap(&context_ppc->float_save.fpscr);
+ for (unsigned int vr_index = 0;
+ vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
+ ++vr_index) {
+ Swap(&context_ppc->vector_save.save_vr[vr_index]);
+ }
+ Swap(&context_ppc->vector_save.save_vscr);
+ // Don't swap the padding fields in vector_save.
+ Swap(&context_ppc->vector_save.save_vrvalid);
+ }
- break;
- }
+ context_.ppc = context_ppc.release();
- case MD_CONTEXT_SPARC: {
- if (expected_size != sizeof(MDRawContextSPARC)) {
- BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
- expected_size << " != " << sizeof(MDRawContextSPARC);
- return false;
+ break;
}
- scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
+ case MD_CONTEXT_SPARC: {
+ if (expected_size != sizeof(MDRawContextSPARC)) {
+ BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
+ expected_size << " != " << sizeof(MDRawContextSPARC);
+ return false;
+ }
- // 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_sparc->context_flags = context_flags;
+ scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
- 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;
- }
+ // 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_sparc->context_flags = context_flags;
- // 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;
- }
+ 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;
+ }
- 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]);
+ // 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;
}
- 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]);
+
+ 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);
}
- Swap(&context_sparc->float_save.filler);
- Swap(&context_sparc->float_save.fsr);
- }
- context_.ctx_sparc = context_sparc.release();
+ context_.ctx_sparc = context_sparc.release();
- break;
- }
+ break;
+ }
- default: {
- // Unknown context type
- BPLOG(ERROR) << "MinidumpContext unknown context type " <<
- HexString(cpu_type);
- return false;
- break;
+ default: {
+ // Unknown context type
+ BPLOG(ERROR) << "MinidumpContext unknown context type " <<
+ HexString(cpu_type);
+ return false;
+ break;
+ }
}
+ context_flags_ = context_flags;
}
valid_ = true;
@@ -527,7 +629,7 @@ u_int32_t MinidumpContext::GetContextCPU() const {
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;
}
+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 {
if (GetContextCPU() != MD_CONTEXT_SPARC) {
BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
@@ -569,6 +680,10 @@ void MinidumpContext::FreeContext() {
delete context_.ppc;
break;
+ case MD_CONTEXT_AMD64:
+ delete context_.amd64;
+ break;
+
case MD_CONTEXT_SPARC:
delete context_.ctx_sparc;
break;
@@ -580,6 +695,7 @@ void MinidumpContext::FreeContext() {
break;
}
+ context_flags_ = 0;
context_.base = NULL;
}
@@ -621,6 +737,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) {
return_value = true;
break;
+ case MD_CONTEXT_AMD64:
+ if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
+ return_value = true;
+ break;
+
case MD_CONTEXT_SPARC:
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
return_value = true;
@@ -745,6 +866,60 @@ void MinidumpContext::Print() {
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: {
const MDRawContextSPARC* context_sparc = GetContextSPARC();
printf("MDRawContextSPARC\n");
diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
index 54e6b545..3c609170 100644
--- a/src/processor/minidump_processor.cc
+++ b/src/processor/minidump_processor.cc
@@ -258,8 +258,14 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
return false;
switch (raw_system_info->processor_architecture) {
- case MD_CPU_ARCHITECTURE_X86: {
- info->cpu = "x86";
+ case MD_CPU_ARCHITECTURE_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();
if (cpu_vendor) {
info->cpu_info = *cpu_vendor;
diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc
index 547914db..785d6512 100644
--- a/src/processor/minidump_stackwalk.cc
+++ b/src/processor/minidump_stackwalk.cc
@@ -68,6 +68,7 @@ using google_breakpad::StackFrame;
using google_breakpad::StackFramePPC;
using google_breakpad::StackFrameSPARC;
using google_breakpad::StackFrameX86;
+using google_breakpad::StackFrameAMD64;
// Separator character for machine readable output.
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);
if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
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") {
const StackFrameSPARC *frame_sparc =
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)
sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
}
-
printf("\n");
}
}
diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc
index 502f07d4..cdb0ce52 100644
--- a/src/processor/stackwalker.cc
+++ b/src/processor/stackwalker.cc
@@ -51,6 +51,7 @@
#include "processor/stackwalker_ppc.h"
#include "processor/stackwalker_sparc.h"
#include "processor/stackwalker_x86.h"
+#include "processor/stackwalker_amd64.h"
namespace google_breakpad {
@@ -164,6 +165,13 @@ Stackwalker* Stackwalker::StackwalkerForCPU(
memory, modules, supplier,
resolver);
break;
+
+ case MD_CONTEXT_AMD64:
+ cpu_stackwalker = new StackwalkerAMD64(system_info,
+ context->GetContextAMD64(),
+ memory, modules, supplier,
+ resolver);
+ break;
case MD_CONTEXT_SPARC:
cpu_stackwalker = new StackwalkerSPARC(system_info,
diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc
new file mode 100644
index 00000000..7a413963
--- /dev/null
+++ b/src/processor/stackwalker_amd64.cc
@@ -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
diff --git a/src/processor/stackwalker_amd64.h b/src/processor/stackwalker_amd64.h
new file mode 100644
index 00000000..a3e11358
--- /dev/null
+++ b/src/processor/stackwalker_amd64.h
@@ -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__