diff options
author | mmentovai <mmentovai@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2007-09-26 18:28:05 +0000 |
---|---|---|
committer | mmentovai <mmentovai@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2007-09-26 18:28:05 +0000 |
commit | ea2bba970675e01f9964f82d3f44960c1aad05dc (patch) | |
tree | d3d6744bf2ef136f9a89748c96ab4e5c465eb7ff /src/processor | |
parent | Fix crash reason switching to allow proper behavior for Linux. Spotted by (diff) | |
download | breakpad-ea2bba970675e01f9964f82d3f44960c1aad05dc.tar.xz |
Add SPARC/Solaris support to client handler and processor (#201, 200).
Patch by Michael shang <satisfy123>. r=me, r=Alfred Peng.
http://groups.google.com/group/google-breakpad-discuss/browse_thread/thread/2fba07577f1fa35e
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@215 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor')
-rw-r--r-- | src/processor/minidump.cc | 163 | ||||
-rw-r--r-- | src/processor/minidump_processor.cc | 139 | ||||
-rw-r--r-- | src/processor/minidump_stackwalk.cc | 11 | ||||
-rw-r--r-- | src/processor/stackwalker.cc | 8 | ||||
-rw-r--r-- | src/processor/stackwalker_selftest.cc | 128 | ||||
-rw-r--r-- | src/processor/stackwalker_selftest_sol.s | 111 | ||||
-rw-r--r-- | src/processor/stackwalker_sparc.cc | 139 | ||||
-rw-r--r-- | src/processor/stackwalker_sparc.h | 86 |
8 files changed, 764 insertions, 21 deletions
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 93d4eb05..f4817044 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -450,6 +450,62 @@ bool MinidumpContext::Read(u_int32_t expected_size) { break; } + case MD_CONTEXT_SPARC: { + if (expected_size != sizeof(MDRawContextSPARC)) { + BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " << + expected_size << " != " << sizeof(MDRawContextSPARC); + return false; + } + + scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC()); + + // 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; + + 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 " << @@ -494,6 +550,14 @@ const MDRawContextPPC* MinidumpContext::GetContextPPC() const { return context_.ppc; } +const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const { + if (GetContextCPU() != MD_CONTEXT_SPARC) { + BPLOG(ERROR) << "MinidumpContext cannot get sparc context"; + return NULL; + } + + return context_.ctx_sparc; +} void MinidumpContext::FreeContext() { switch (GetContextCPU()) { @@ -505,6 +569,10 @@ void MinidumpContext::FreeContext() { delete context_.ppc; break; + case MD_CONTEXT_SPARC: + delete context_.ctx_sparc; + 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 @@ -552,6 +620,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) { if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC) return_value = true; break; + + case MD_CONTEXT_SPARC: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC) + return_value = true; + break; } BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " << @@ -672,6 +745,37 @@ void MinidumpContext::Print() { break; } + case MD_CONTEXT_SPARC: { + const MDRawContextSPARC* context_sparc = GetContextSPARC(); + printf("MDRawContextSPARC\n"); + printf(" context_flags = 0x%x\n", + context_sparc->context_flags); + for (unsigned int g_r_index = 0; + g_r_index < MD_CONTEXT_SPARC_GPR_COUNT; + ++g_r_index) { + printf(" g_r[%2d] = 0x%llx\n", + g_r_index, context_sparc->g_r[g_r_index]); + } + printf(" ccr = 0x%llx\n", context_sparc->ccr); + printf(" pc = 0x%llx\n", context_sparc->pc); + printf(" npc = 0x%llx\n", context_sparc->npc); + printf(" y = 0x%llx\n", context_sparc->y); + printf(" asi = 0x%llx\n", context_sparc->asi); + printf(" fprs = 0x%llx\n", context_sparc->fprs); + + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT; + ++fpr_index) { + printf(" float_save.regs[%2d] = 0x%llx\n", + fpr_index, context_sparc->float_save.regs[fpr_index]); + } + printf(" float_save.filler = 0x%llx\n", + context_sparc->float_save.filler); + printf(" float_save.fsr = 0x%llx\n", + context_sparc->float_save.fsr); + break; + } + default: { break; } @@ -1068,12 +1172,23 @@ bool MinidumpThreadList::Read(u_int32_t expected_size) { if (expected_size != sizeof(thread_count) + thread_count * sizeof(MDRawThread)) { - BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size << - " != " << - sizeof(thread_count) + thread_count * sizeof(MDRawThread); - return false; + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(thread_count) + 4 + + thread_count * sizeof(MDRawThread)) { + u_int32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size << + " != " << sizeof(thread_count) + + thread_count * sizeof(MDRawThread); + return false; + } } + if (thread_count > max_threads_) { BPLOG(ERROR) << "MinidumpThreadList count " << thread_count << " exceeds maximum " << max_threads_; @@ -1328,6 +1443,7 @@ string MinidumpModule::code_identifier() const { } case MD_OS_MAC_OS_X: + case MD_OS_SOLARIS: case MD_OS_LINUX: { // TODO(mmentovai): support uuid extension if present, otherwise fall // back to version (from LC_ID_DYLIB?), otherwise fall back to something @@ -1924,10 +2040,20 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) { if (expected_size != sizeof(module_count) + module_count * MD_MODULE_SIZE) { - BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size << - " != " << - sizeof(module_count) + module_count * MD_MODULE_SIZE; - return false; + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(module_count) + 4 + + module_count * MD_MODULE_SIZE) { + u_int32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size << + " != " << sizeof(module_count) + + module_count * MD_MODULE_SIZE; + return false; + } } if (module_count > max_modules_) { @@ -2155,9 +2281,20 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) { if (expected_size != sizeof(region_count) + region_count * sizeof(MDMemoryDescriptor)) { - BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size << - " != " << region_count * sizeof(MDMemoryDescriptor); - return false; + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(region_count) + 4 + + region_count * sizeof(MDMemoryDescriptor)) { + u_int32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size << + " != " << sizeof(region_count) + + region_count * sizeof(MDMemoryDescriptor); + return false; + } } if (region_count > max_regions_) { @@ -2526,6 +2663,10 @@ string MinidumpSystemInfo::GetOS() { os = "linux"; break; + case MD_OS_SOLARIS: + os = "solaris"; + break; + default: BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " << HexString(system_info_.platform_id); diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index e7f4b0e6..54e6b545 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -280,6 +280,11 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { break; } + case MD_CPU_ARCHITECTURE_SPARC: { + info->cpu = "sparc"; + break; + } + default: { // Assign the numeric architecture ID into the CPU string. char cpu_string[7]; @@ -332,6 +337,11 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { break; } + case MD_OS_SOLARIS: { + info->os = "Solaris"; + break; + } + default: { // Assign the numeric platform ID into the OS string. char os_string[11]; @@ -835,6 +845,135 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) { break; } + case MD_OS_SOLARIS: { + switch (exception_code) { + case MD_EXCEPTION_CODE_SOL_SIGHUP: + reason = "SIGHUP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGINT: + reason = "SIGINT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGQUIT: + reason = "SIGQUIT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGILL: + reason = "SIGILL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTRAP: + reason = "SIGTRAP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGIOT: + reason = "SIGIOT | SIGABRT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGEMT: + reason = "SIGEMT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGFPE: + reason = "SIGFPE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGKILL: + reason = "SIGKILL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGBUS: + reason = "SIGBUS"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSEGV: + reason = "SIGSEGV"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSYS: + reason = "SIGSYS"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPIPE: + reason = "SIGPIPE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGALRM: + reason = "SIGALRM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTERM: + reason = "SIGTERM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGUSR1: + reason = "SIGUSR1"; + break; + case MD_EXCEPTION_CODE_SOL_SIGUSR2: + reason = "SIGUSR2"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCLD: + reason = "SIGCLD | SIGCHLD"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPWR: + reason = "SIGPWR"; + break; + case MD_EXCEPTION_CODE_SOL_SIGWINCH: + reason = "SIGWINCH"; + break; + case MD_EXCEPTION_CODE_SOL_SIGURG: + reason = "SIGURG"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPOLL: + reason = "SIGPOLL | SIGIO"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSTOP: + reason = "SIGSTOP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTSTP: + reason = "SIGTSTP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCONT: + reason = "SIGCONT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTTIN: + reason = "SIGTTIN"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTTOU: + reason = "SIGTTOU"; + break; + case MD_EXCEPTION_CODE_SOL_SIGVTALRM: + reason = "SIGVTALRM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPROF: + reason = "SIGPROF"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXCPU: + reason = "SIGXCPU"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXFSZ: + reason = "SIGXFSZ"; + break; + case MD_EXCEPTION_CODE_SOL_SIGWAITING: + reason = "SIGWAITING"; + break; + case MD_EXCEPTION_CODE_SOL_SIGLWP: + reason = "SIGLWP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGFREEZE: + reason = "SIGFREEZE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTHAW: + reason = "SIGTHAW"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCANCEL: + reason = "SIGCANCEL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGLOST: + reason = "SIGLOST"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXRES: + reason = "SIGXRES"; + break; + case MD_EXCEPTION_CODE_SOL_SIGJVM1: + reason = "SIGJVM1"; + break; + case MD_EXCEPTION_CODE_SOL_SIGJVM2: + reason = "SIGJVM2"; + break; + default: + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + default: { BPLOG(INFO) << "Unknown exception reason " << reason; break; diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 35f0aa27..547914db 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -66,6 +66,7 @@ using google_breakpad::scoped_ptr; using google_breakpad::SimpleSymbolSupplier; using google_breakpad::StackFrame; using google_breakpad::StackFramePPC; +using google_breakpad::StackFrameSPARC; using google_breakpad::StackFrameX86; // Separator character for machine readable output. @@ -164,6 +165,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 == "sparc") { + const StackFrameSPARC *frame_sparc = + reinterpret_cast<const StackFrameSPARC*>(frame); + + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP) + sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence); + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP) + sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence); + 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 46d8384b..502f07d4 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -49,6 +49,7 @@ #include "processor/scoped_ptr.h" #include "processor/stack_frame_info.h" #include "processor/stackwalker_ppc.h" +#include "processor/stackwalker_sparc.h" #include "processor/stackwalker_x86.h" namespace google_breakpad { @@ -163,6 +164,13 @@ Stackwalker* Stackwalker::StackwalkerForCPU( memory, modules, supplier, resolver); break; + + case MD_CONTEXT_SPARC: + cpu_stackwalker = new StackwalkerSPARC(system_info, + context->GetContextSPARC(), + memory, modules, supplier, + resolver); + break; } BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << diff --git a/src/processor/stackwalker_selftest.cc b/src/processor/stackwalker_selftest.cc index 913bb0ab..247b37ce 100644 --- a/src/processor/stackwalker_selftest.cc +++ b/src/processor/stackwalker_selftest.cc @@ -49,7 +49,17 @@ // // Author: Mark Mentovai -#if defined(__GNUC__) && (defined(__i386__) || defined(__ppc__)) +#include "processor/logging.h" + +#if defined(__i386) && !defined(__i386__) +#define __i386__ +#endif +#if defined(__sparc) && !defined(__sparc__) +#define __sparc__ +#endif + +#if (defined(__SUNPRO_CC) || defined(__GNUC__)) && \ + (defined(__i386__) || defined(__ppc__) || defined(__sparc__)) #include <cstdio> @@ -61,7 +71,6 @@ #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/stack_frame.h" #include "google_breakpad/processor/stack_frame_cpu.h" -#include "processor/logging.h" #include "processor/scoped_ptr.h" using google_breakpad::BasicSourceLineResolver; @@ -71,6 +80,7 @@ using google_breakpad::scoped_ptr; using google_breakpad::StackFrame; using google_breakpad::StackFramePPC; using google_breakpad::StackFrameX86; +using google_breakpad::StackFrameSPARC; #if defined(__i386__) #include "processor/stackwalker_x86.h" @@ -78,7 +88,10 @@ using google_breakpad::StackwalkerX86; #elif defined(__ppc__) #include "processor/stackwalker_ppc.h" using google_breakpad::StackwalkerPPC; -#endif // __i386__ || __ppc__ +#elif defined(__sparc__) +#include "processor/stackwalker_sparc.h" +using google_breakpad::StackwalkerSPARC; +#endif // __i386__ || __ppc__ || __sparc__ #define RECURSION_DEPTH 100 @@ -117,6 +130,9 @@ class SelfMemoryRegion : public MemoryRegion { }; +#if defined(__GNUC__) + + #if defined(__i386__) // GetEBP returns the current value of the %ebp register. Because it's @@ -210,14 +226,87 @@ static u_int32_t GetPC() { } -#endif // __i386__ || __ppc__ +#elif defined(__sparc__) +// GetSP returns the current value of the %sp/%o6/%g_r[14] register, which +// by convention, is the stack pointer on sparc. Because it's implemented +// as a function, %sp itself contains GetSP's own stack pointer and not +// the caller's stack pointer. Dereference to obtain the caller's stack +// pointer, which the compiler-generated prolog stored on the stack. +// Because this function depends on the compiler-generated prolog, inlining +// is disabled. +static u_int32_t GetSP() __attribute__((noinline)); +static u_int32_t GetSP() { + u_int32_t sp; + __asm__ __volatile__( + "mov %%fp, %0" + : "=r" (sp) + ); + return sp; +} + +// GetFP returns the current value of the %fp register. Because it's +// implemented as a function, %fp itself contains GetFP's frame pointer +// and not the caller's frame pointer. Dereference %fp to obtain the +// caller's frame pointer, which the compiler-generated preamble stored +// on the stack (provided frame pointers are not being omitted.) Because +// this function depends on the compiler-generated preamble, inlining is +// disabled. +static u_int32_t GetFP() __attribute__((noinline)); +static u_int32_t GetFP() { + u_int32_t fp; + __asm__ __volatile__( + "ld [%%fp+56], %0" + : "=r" (fp) + ); + return fp; +} + +// GetPC returns the program counter identifying the next instruction to +// execute after GetPC returns. It obtains this information from the +// link register, where it was placed by the branch instruction that called +// GetPC. Because this function depends on the caller's use of a branch +// instruction, inlining is disabled. +static u_int32_t GetPC() __attribute__((noinline)); +static u_int32_t GetPC() { + u_int32_t pc; + __asm__ __volatile__( + "mov %%i7, %0" + : "=r" (pc) + ); + return pc + 8; +} + +#endif // __i386__ || __ppc__ || __sparc__ + +#elif defined(__SUNPRO_CC) + +#if defined(__i386__) +extern "C" { +extern u_int32_t GetEIP(); +extern u_int32_t GetEBP(); +extern u_int32_t GetESP(); +} +#elif defined(__sparc__) +extern "C" { +extern u_int32_t GetPC(); +extern u_int32_t GetFP(); +extern u_int32_t GetSP(); +} +#endif // __i386__ || __sparc__ + +#endif // __GNUC__ || __SUNPRO_CC + // CountCallerFrames returns the number of stack frames beneath the function // that called CountCallerFrames. Because this function's return value // is dependent on the size of the stack beneath it, inlining is disabled, // and any function that calls this should not be inlined either. +#if defined(__GNUC__) static unsigned int CountCallerFrames() __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +static unsigned int CountCallerFrames(); +#endif static unsigned int CountCallerFrames() { SelfMemoryRegion memory; BasicSourceLineResolver resolver; @@ -237,7 +326,15 @@ static unsigned int CountCallerFrames() { StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL, NULL, &resolver); -#endif // __i386__ || __ppc__ +#elif defined(__sparc__) + MDRawContextSPARC context = MDRawContextSPARC(); + context.pc = GetPC(); + context.g_r[14] = GetSP(); + context.g_r[30] = GetFP(); + + StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory, + NULL, NULL, &resolver); +#endif // __i386__ || __ppc__ || __sparc__ CallStack stack; stackwalker.Walk(&stack); @@ -257,7 +354,11 @@ static unsigned int CountCallerFrames() { #elif defined(__ppc__) StackFramePPC *frame_ppc = reinterpret_cast<StackFramePPC*>(frame); printf(" gpr[1] = 0x%08x\n", frame_ppc->context.gpr[1]); -#endif // __i386__ || __ppc__ +#elif defined(__sparc__) + StackFrameSPARC *frame_sparc = reinterpret_cast<StackFrameSPARC*>(frame); + printf(" sp = 0x%08x fp = 0x%08x\n", + frame_sparc->context.g_r[14], frame_sparc->context.g_r[30]); +#endif // __i386__ || __ppc__ || __sparc__ } #endif // PRINT_STACKS @@ -273,8 +374,12 @@ static unsigned int CountCallerFrames() { // have been reached, Recursor stops checking and returns success. If the // frame count check fails at any depth, Recursor will stop and return false. // Because this calls CountCallerFrames, inlining is disabled. +#if defined(__GNUC__) static bool Recursor(unsigned int depth, unsigned int parent_callers) __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +static bool Recursor(unsigned int depth, unsigned int parent_callers); +#endif static bool Recursor(unsigned int depth, unsigned int parent_callers) { unsigned int callers = CountCallerFrames(); if (callers != parent_callers + 1) @@ -291,7 +396,11 @@ static bool Recursor(unsigned int depth, unsigned int parent_callers) { // Because this calls CountCallerFrames, inlining is disabled - but because // it's main (and nobody calls it other than the entry point), it wouldn't // be inlined anyway. +#if defined(__GNUC__) int main(int argc, char** argv) __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +int main(int argc, char** argv); +#endif int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); @@ -299,9 +408,8 @@ int main(int argc, char** argv) { } -#else // __GNUC__ && (__i386__ || __ppc__) -// Not gcc? We use gcc's __asm__. -// Not i386 or ppc? We can only test stacks we know how to walk. +#else +// Not i386 or ppc or sparc? We can only test stacks we know how to walk. int main(int argc, char **argv) { @@ -314,4 +422,4 @@ int main(int argc, char **argv) { } -#endif // __GNUC__ && (__i386__ || __ppc__) +#endif // (__GNUC__ || __SUNPRO_CC) && (__i386__ || __ppc__ || __sparc__) diff --git a/src/processor/stackwalker_selftest_sol.s b/src/processor/stackwalker_selftest_sol.s new file mode 100644 index 00000000..648b0499 --- /dev/null +++ b/src/processor/stackwalker_selftest_sol.s @@ -0,0 +1,111 @@ +/* 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_selftest_sol.s + * On Solaris, the recommeded compiler is CC, so we can not use gcc inline + * asm, use this method instead. + * + * How to compile: as -P -L -D_ASM -D_STDC -K PIC -o \ + * src/processor/stackwalker_selftest_sol.o \ + * src/processor/stackwalker_selftest_sol.s + * + * Author: Michael Shang + */ + +#include <sys/asm_linkage.h> + +#if defined(__i386) + + +ENTRY(GetEBP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl 0x00000000(%ebp),%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + leave + ret +SET_SIZE(GetEBP) + +ENTRY(GetEIP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl 0x00000004(%ebp),%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + leave + ret +SET_SIZE(GetEIP) + +ENTRY(GetESP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl %ebp,%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + addl $0x00000008,%eax + leave + ret +SET_SIZE(GetESP) + + +#elif defined(__sparc) + + +ENTRY(GetPC) + save %sp, -120, %sp + mov %i7, %i4 + inccc 8, %i4 + mov %i4, %i0 + ret + restore +SET_SIZE(GetPC) + +ENTRY(GetSP) + save %sp, -120, %sp + mov %fp, %i4 + mov %i4, %i0 + ret + restore +SET_SIZE(GetSP) + +ENTRY(GetFP) + save %sp, -120, %sp + ld [%fp + 56], %g1 + mov %g1, %i0 + ret + restore +SET_SIZE(GetFP) + + +#endif // __i386 || __sparc diff --git a/src/processor/stackwalker_sparc.cc b/src/processor/stackwalker_sparc.cc new file mode 100644 index 00000000..b7b6f005 --- /dev/null +++ b/src/processor/stackwalker_sparc.cc @@ -0,0 +1,139 @@ +// 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_sparc.cc: sparc-specific stackwalker. +// +// See stackwalker_sparc.h for documentation. +// +// Author: Michael Shang + + +#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" +#include "processor/stackwalker_sparc.h" + +namespace google_breakpad { + + +StackwalkerSPARC::StackwalkerSPARC(const SystemInfo *system_info, + const MDRawContextSPARC *context, + MemoryRegion *memory, + const CodeModules *modules, + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : Stackwalker(system_info, memory, modules, supplier, resolver), + context_(context) { +} + + +StackFrame* StackwalkerSPARC::GetContextFrame() { + if (!context_ || !memory_) { + BPLOG(ERROR) << "Can't get context frame without context or memory"; + return NULL; + } + + StackFrameSPARC *frame = new StackFrameSPARC(); + + // 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 = StackFrameSPARC::CONTEXT_VALID_ALL; + frame->instruction = frame->context.pc; + + return frame; +} + + +StackFrame* StackwalkerSPARC::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; + } + + StackFrameSPARC *last_frame = static_cast<StackFrameSPARC*>( + stack->frames()->back()); + + // new: caller + // old: callee + // %fp, %i6 and g_r[30] is the same, see minidump_format.h + // %sp, %o6 and g_r[14] is the same, see minidump_format.h + // %sp_new = %fp_old + // %fp_new = *(%fp_old + 32 + 32 - 8), where the callee's %i6 + // %pc_new = *(%fp_old + 32 + 32 - 4) + 8 + // which is callee's %i7 plus 8 + + // 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_int32_t stack_pointer = last_frame->context.g_r[30]; + if (stack_pointer <= last_frame->context.g_r[14]) { + return NULL; + } + + u_int32_t instruction; + if (!memory_->GetMemoryAtAddress(stack_pointer + 60, + &instruction) || instruction <= 1) { + return NULL; + } + + u_int32_t stack_base; + if (!memory_->GetMemoryAtAddress(stack_pointer + 56, + &stack_base) || stack_base <= 1) { + return NULL; + } + + StackFrameSPARC *frame = new StackFrameSPARC(); + + frame->context = last_frame->context; + frame->context.g_r[14] = stack_pointer; + frame->context.g_r[30] = stack_base; + + // frame->context.pc is the return address, which is 2 instruction + // past the branch that caused us to arrive at the callee, which are + // a CALL instruction then a NOP instruction. + // frame_ppc->instruction to 8 less than that. Since all sparc + // instructions are 4 bytes wide, this is the address of the branch + // instruction. This allows source line information to match up with the + // line that contains a function call. Callers that require the exact + // return address value may access the %i7/g_r[31] field of StackFrameSPARC. + frame->context.pc = instruction + 8; + frame->instruction = instruction; + frame->context_validity = StackFrameSPARC::CONTEXT_VALID_PC | + StackFrameSPARC::CONTEXT_VALID_SP | + StackFrameSPARC::CONTEXT_VALID_FP; + + return frame; +} + + +} // namespace google_breakpad diff --git a/src/processor/stackwalker_sparc.h b/src/processor/stackwalker_sparc.h new file mode 100644 index 00000000..f051e5bb --- /dev/null +++ b/src/processor/stackwalker_sparc.h @@ -0,0 +1,86 @@ +// 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_sparc.h: sparc-specific stackwalker. +// +// Provides stack frames given sparc register context and a memory region +// corresponding to an sparc stack. +// +// Author: Michael Shang + + +#ifndef PROCESSOR_STACKWALKER_SPARC_H__ +#define PROCESSOR_STACKWALKER_SPARC_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 StackwalkerSPARC : public Stackwalker { + public: + // context is a sparc context object that gives access to sparc-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. + StackwalkerSPARC(const SystemInfo *system_info, + const MDRawContextSPARC *context, + MemoryRegion *memory, + const CodeModules *modules, + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); + + private: + // Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and + // stack conventions (saved %ebp at [%ebp], saved %eip at 4[%ebp], or + // alternate conventions as guided by stack_frame_info_). + // Implementation of Stackwalker, using ppc context (stack pointer in %r1, + // saved program counter in %srr0) and stack conventions (saved stack + // pointer at 0(%r1), return address at 8(0(%r1)). + // Implementation of Stackwalker, using sparc context (%fp, %sp, %pc) and + // stack conventions (saved %sp at) + 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 MDRawContextSPARC *context_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_SPARC_H__ |