From 9276b0d3017ad5ca93c8b593cacf317e1eaa114e Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Sat, 19 Dec 2009 21:43:53 +0000 Subject: Basic arm cpu support for processor. r=mark at http://breakpad.appspot.com/49011 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@454 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/processor/minidump.cc | 115 +++++++++++++++++++++++++++++++++++- src/processor/minidump_processor.cc | 5 ++ src/processor/stackwalker.cc | 8 +++ src/processor/stackwalker_arm.cc | 92 +++++++++++++++++++++++++++++ src/processor/stackwalker_arm.h | 80 +++++++++++++++++++++++++ 5 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 src/processor/stackwalker_arm.cc create mode 100644 src/processor/stackwalker_arm.h (limited to 'src/processor') diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 49118589..771edd64 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -620,6 +620,61 @@ bool MinidumpContext::Read(u_int32_t expected_size) { break; } + case MD_CONTEXT_ARM: { + if (expected_size != sizeof(MDRawContextARM)) { + BPLOG(ERROR) << "MinidumpContext arm size mismatch, " << + expected_size << " != " << sizeof(MDRawContextARM); + return false; + } + + scoped_ptr context_arm(new MDRawContextARM()); + + // 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_arm->context_flags = context_flags; + + size_t flags_size = sizeof(context_arm->context_flags); + u_int8_t* context_after_flags = + reinterpret_cast(context_arm.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextARM) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read arm 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 arm does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_arm->context_flags was already swapped. + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; + ++ireg_index) { + Swap(&context_arm->iregs[ireg_index]); + } + Swap(&context_arm->cpsr); + Swap(&context_arm->float_save.fpscr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; + ++fpr_index) { + Swap(&context_arm->float_save.regs[fpr_index]); + } + for (unsigned int fpe_index = 0; + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; + ++fpe_index) { + Swap(&context_arm->float_save.extra[fpe_index]); + } + } + context_.arm = context_arm.release(); + + break; + } + default: { // Unknown context type - Don't log as an error yet. Let the // caller work that out. @@ -685,6 +740,15 @@ const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const { return context_.ctx_sparc; } +const MDRawContextARM* MinidumpContext::GetContextARM() const { + if (GetContextCPU() != MD_CONTEXT_ARM) { + BPLOG(ERROR) << "MinidumpContext cannot get arm context"; + return NULL; + } + + return context_.arm; +} + void MinidumpContext::FreeContext() { switch (GetContextCPU()) { case MD_CONTEXT_X86: @@ -703,6 +767,10 @@ void MinidumpContext::FreeContext() { delete context_.ctx_sparc; break; + case MD_CONTEXT_ARM: + delete context_.arm; + break; + default: // There is no context record (valid_ is false) or there's a // context record for an unknown CPU (shouldn't happen, only known @@ -762,6 +830,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) { if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC) return_value = true; break; + + case MD_CONTEXT_ARM: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM) + return_value = true; + break; } BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " << @@ -967,6 +1040,36 @@ void MinidumpContext::Print() { break; } + case MD_CONTEXT_ARM: { + const MDRawContextARM* context_arm = GetContextARM(); + printf("MDRawContextARM\n"); + printf(" context_flags = 0x%x\n", + context_arm->context_flags); + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; + ++ireg_index) { + printf(" iregs[%2d] = 0x%x\n", + ireg_index, context_arm->iregs[ireg_index]); + } + printf(" cpsr = 0x%x\n", context_arm->cpsr); + printf(" float_save.fpscr = 0x%" PRIx64 "\n", + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; + ++fpr_index) { + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_arm->float_save.regs[fpr_index]); + } + for (unsigned int fpe_index = 0; + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; + ++fpe_index) { + printf(" float_save.extra[%2d] = 0x%" PRIx64 "\n", + fpe_index, context_arm->float_save.extra[fpe_index]); + } + + context_arm->float_save.fpscr); + break; + } + default: { break; } @@ -2727,8 +2830,8 @@ MinidumpContext* MinidumpException::GetContext() { scoped_ptr context(new MinidumpContext(minidump_)); - // Don't log as an error if we can still fall back on th thread's context - // (which must be possible if we got his far.) + // Don't log as an error if we can still fall back on the thread's context + // (which must be possible if we got this far.) if (!context->Read(exception_.thread_context.data_size)) { BPLOG(INFO) << "MinidumpException cannot read context"; return NULL; @@ -3006,6 +3109,10 @@ string MinidumpSystemInfo::GetCPU() { cpu = "x86"; break; + case MD_CPU_ARCHITECTURE_AMD64: + cpu = "x86-64"; + break; + case MD_CPU_ARCHITECTURE_PPC: cpu = "ppc"; break; @@ -3014,6 +3121,10 @@ string MinidumpSystemInfo::GetCPU() { cpu = "sparc"; break; + case MD_CPU_ARCHITECTURE_ARM: + cpu = "arm"; + break; + default: BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " << HexString(system_info_.processor_architecture); diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 24b03e9d..e2b5bd3d 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -308,6 +308,11 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { break; } + case MD_CPU_ARCHITECTURE_ARM: { + info->cpu = "arm"; + break; + } + default: { // Assign the numeric architecture ID into the CPU string. char cpu_string[7]; diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index 96ee6db0..c8f0da54 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -52,6 +52,7 @@ #include "processor/stackwalker_sparc.h" #include "processor/stackwalker_x86.h" #include "processor/stackwalker_amd64.h" +#include "processor/stackwalker_arm.h" namespace google_breakpad { @@ -181,6 +182,13 @@ Stackwalker* Stackwalker::StackwalkerForCPU( memory, modules, supplier, resolver); break; + + case MD_CONTEXT_ARM: + cpu_stackwalker = new StackwalkerARM(system_info, + context->GetContextARM(), + memory, modules, supplier, + resolver); + break; } BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc new file mode 100644 index 00000000..cf241c86 --- /dev/null +++ b/src/processor/stackwalker_arm.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2009, 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_arm.cc: arm-specific stackwalker. +// +// See stackwalker_arm.h for documentation. +// +// Author: Mark Mentovai, Ted Mielczarek + + +#include "processor/stackwalker_arm.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 { + + +StackwalkerARM::StackwalkerARM(const SystemInfo *system_info, + const MDRawContextARM *context, + MemoryRegion *memory, + const CodeModules *modules, + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : Stackwalker(system_info, memory, modules, supplier, resolver), + context_(context) { +} + + +StackFrame* StackwalkerARM::GetContextFrame() { + if (!context_ || !memory_) { + BPLOG(ERROR) << "Can't get context frame without context or memory"; + return NULL; + } + + StackFrameARM *frame = new StackFrameARM(); + + // The instruction pointer is stored directly in a register (r15), so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFrameARM::CONTEXT_VALID_ALL; + frame->instruction = frame->context.iregs[15]; + + return frame; +} + + +StackFrame* StackwalkerARM::GetCallerFrame( + const CallStack *stack, + const vector< linked_ptr > &stack_frame_info) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + StackFrameARM *last_frame = static_cast( + stack->frames()->back()); + + // TODO: Can't actually walk the stack on ARM without the CFI data. + // Implement this when the CFI symbol dumper changes have landed. + return NULL; +} + + +} // namespace google_breakpad diff --git a/src/processor/stackwalker_arm.h b/src/processor/stackwalker_arm.h new file mode 100644 index 00000000..4a4756b4 --- /dev/null +++ b/src/processor/stackwalker_arm.h @@ -0,0 +1,80 @@ +// Copyright (c) 2009, 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_arm.h: arm-specific stackwalker. +// +// Provides stack frames given arm register context and a memory region +// corresponding to an arm stack. +// +// Author: Mark Mentovai, Ted Mielczarek + + +#ifndef PROCESSOR_STACKWALKER_ARM_H__ +#define PROCESSOR_STACKWALKER_ARM_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 StackwalkerARM : public Stackwalker { + public: + // context is an arm context object that gives access to arm-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. + StackwalkerARM(const SystemInfo *system_info, + const MDRawContextARM *context, + MemoryRegion *memory, + const CodeModules *modules, + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); + + private: + // Implementation of Stackwalker, using arm context and stack conventions. + // TODO: currently stubbed out, needs CFI symbol dumper support + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame( + const CallStack *stack, + const vector< linked_ptr > &stack_frame_info); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextARM *context_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_ARM_H__ -- cgit v1.2.1