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
This commit is contained in:
parent
278946c3b5
commit
ea2bba9706
17 changed files with 1044 additions and 40 deletions
|
@ -94,6 +94,8 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/processor/stackwalker.cc \
|
||||
src/processor/stackwalker_ppc.cc \
|
||||
src/processor/stackwalker_ppc.h \
|
||||
src/processor/stackwalker_sparc.cc \
|
||||
src/processor/stackwalker_sparc.h \
|
||||
src/processor/stackwalker_x86.cc \
|
||||
src/processor/stackwalker_x86.h
|
||||
|
||||
|
@ -159,6 +161,7 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||
src/processor/process_state.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
src_processor_pathname_stripper_unittest_SOURCES = \
|
||||
|
@ -189,6 +192,7 @@ src_processor_stackwalker_selftest_LDADD = \
|
|||
src/processor/pathname_stripper.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
## Non-installables
|
||||
|
@ -217,6 +221,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
|||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
|
||||
|
@ -268,6 +273,7 @@ EXTRA_DIST = \
|
|||
src/common/windows/pdb_source_line_writer.h \
|
||||
src/common/windows/string_utils-inl.h \
|
||||
src/common/windows/string_utils.cc \
|
||||
src/processor/stackwalker_selftest_sol.s \
|
||||
src/processor/testdata/minidump2.dmp \
|
||||
src/processor/testdata/minidump2.dump.out \
|
||||
src/processor/testdata/minidump2.stackwalk.machine_readable.out \
|
||||
|
|
15
Makefile.in
15
Makefile.in
|
@ -113,6 +113,7 @@ am_src_libbreakpad_la_OBJECTS = src/processor/basic_code_modules.lo \
|
|||
src/processor/process_state.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
src_libbreakpad_la_OBJECTS = $(am_src_libbreakpad_la_OBJECTS)
|
||||
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
|
||||
|
@ -156,6 +157,7 @@ src_processor_minidump_processor_unittest_DEPENDENCIES = \
|
|||
src/processor/pathname_stripper.lo \
|
||||
src/processor/process_state.lo src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
am_src_processor_minidump_stackwalk_OBJECTS = \
|
||||
src/processor/minidump_stackwalk.$(OBJEXT)
|
||||
|
@ -170,6 +172,7 @@ src_processor_minidump_stackwalk_DEPENDENCIES = \
|
|||
src/processor/process_state.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
am_src_processor_pathname_stripper_unittest_OBJECTS = \
|
||||
src/processor/pathname_stripper_unittest.$(OBJEXT)
|
||||
|
@ -199,6 +202,7 @@ src_processor_stackwalker_selftest_DEPENDENCIES = \
|
|||
src/processor/call_stack.lo src/processor/logging.lo \
|
||||
src/processor/minidump.lo src/processor/pathname_stripper.lo \
|
||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
SCRIPTS = $(noinst_SCRIPTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(top_builddir)/src@am__isrc@
|
||||
|
@ -422,6 +426,8 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/processor/stackwalker.cc \
|
||||
src/processor/stackwalker_ppc.cc \
|
||||
src/processor/stackwalker_ppc.h \
|
||||
src/processor/stackwalker_sparc.cc \
|
||||
src/processor/stackwalker_sparc.h \
|
||||
src/processor/stackwalker_x86.cc \
|
||||
src/processor/stackwalker_x86.h
|
||||
|
||||
|
@ -468,6 +474,7 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||
src/processor/process_state.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
src_processor_pathname_stripper_unittest_SOURCES = \
|
||||
|
@ -502,6 +509,7 @@ src_processor_stackwalker_selftest_LDADD = \
|
|||
src/processor/pathname_stripper.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
noinst_SCRIPTS = $(check_SCRIPTS)
|
||||
|
@ -529,6 +537,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
|||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@ -575,6 +584,7 @@ EXTRA_DIST = \
|
|||
src/common/windows/pdb_source_line_writer.h \
|
||||
src/common/windows/string_utils-inl.h \
|
||||
src/common/windows/string_utils.cc \
|
||||
src/processor/stackwalker_selftest_sol.s \
|
||||
src/processor/testdata/minidump2.dmp \
|
||||
src/processor/testdata/minidump2.dump.out \
|
||||
src/processor/testdata/minidump2.stackwalk.machine_readable.out \
|
||||
|
@ -717,6 +727,8 @@ src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
|
|||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/stackwalker_ppc.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/stackwalker_sparc.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/stackwalker_x86.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/$(am__dirstamp):
|
||||
|
@ -860,6 +872,8 @@ mostlyclean-compile:
|
|||
-rm -f src/processor/stackwalker_ppc.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker_ppc.lo
|
||||
-rm -f src/processor/stackwalker_selftest.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker_sparc.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker_sparc.lo
|
||||
-rm -f src/processor/stackwalker_x86.$(OBJEXT)
|
||||
-rm -f src/processor/stackwalker_x86.lo
|
||||
|
||||
|
@ -887,6 +901,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.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_sparc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_x86.Plo@am__quote@
|
||||
|
||||
.cc.o:
|
||||
|
|
|
@ -73,4 +73,5 @@ $(BIN_DIR)/exception_handler_test:$(EXCEPTION_TEST_OBJ)
|
|||
$(CXX) $(CPPFLAGS) $(LDFLAGS) $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(BIN) *.o *.out *.dmp core
|
||||
rm -f $(BIN) *.o *.out *.dmp core ../../minidump_file_writer.o\
|
||||
../../../common/*.o ../../../common/solaris/*.o
|
||||
|
|
|
@ -60,7 +60,7 @@ bool MinidumpGenerator::WriteLwpStack(uintptr_t last_esp,
|
|||
UntypedMDRVA *memory,
|
||||
MDMemoryDescriptor *loc) {
|
||||
uintptr_t stack_bottom = lwp_lister_->GetLwpStackBottom(last_esp);
|
||||
if (stack_bottom > last_esp) {
|
||||
if (stack_bottom >= last_esp) {
|
||||
int size = stack_bottom - last_esp;
|
||||
if (size > 0) {
|
||||
if (!memory->Allocate(size))
|
||||
|
@ -74,6 +74,28 @@ bool MinidumpGenerator::WriteLwpStack(uintptr_t last_esp,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if TARGET_CPU_SPARC
|
||||
bool MinidumpGenerator::WriteContext(MDRawContextSPARC *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
if (!context || !regs)
|
||||
return false;
|
||||
|
||||
context->context_flags = MD_CONTEXT_SPARC_FULL;
|
||||
|
||||
context->ccr = (unsigned int)(regs[32]);
|
||||
context->pc = (unsigned int)(regs[R_PC]);
|
||||
context->npc = (unsigned int)(regs[R_nPC]);
|
||||
context->y = (unsigned int)(regs[R_Y]);
|
||||
context->asi = (unsigned int)(regs[36]);
|
||||
context->fprs = (unsigned int)(regs[37]);
|
||||
|
||||
for ( int i = 0 ; i < 32 ; ++i ){
|
||||
context->g_r[i] = (unsigned int)(regs[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif TARGET_CPU_X86
|
||||
bool MinidumpGenerator::WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
if (!context || !regs)
|
||||
|
@ -100,23 +122,41 @@ bool MinidumpGenerator::WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
|
||||
bool MinidumpGenerator::WriteLwpStream(lwpstatus_t *lsp, MDRawThread *lwp) {
|
||||
prfpregset_t fp_regs = lsp->pr_fpreg;
|
||||
prgregset_t *gregs = &(lsp->pr_reg);
|
||||
UntypedMDRVA memory(&writer_);
|
||||
if (!WriteLwpStack((*gregs)[UESP],
|
||||
#if TARGET_CPU_SPARC
|
||||
if (!WriteLwpStack((*gregs)[R_SP],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
// Write context
|
||||
TypedMDRVA<MDRawContextSPARC> context(&writer_);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
// should be the thread_id
|
||||
lwp->thread_id = lsp->pr_lwpid;
|
||||
lwp->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextSPARC));
|
||||
#elif TARGET_CPU_X86
|
||||
if (!WriteLwpStack((*gregs)[UESP],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
// Write context
|
||||
TypedMDRVA<MDRawContextX86> context(&writer_);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
lwp->thread_id = lwp_lister_->getpid();
|
||||
// should be the thread_id
|
||||
lwp->thread_id = lsp->pr_lwpid;
|
||||
lwp->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextX86));
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
return WriteContext(context.get(), (int *)gregs, &fp_regs);
|
||||
}
|
||||
|
||||
|
@ -220,11 +260,11 @@ bool MinidumpGenerator::WriteLwpListStream(MDRawDirectory *dir) {
|
|||
if (lwp_count < 0)
|
||||
return false;
|
||||
TypedMDRVA<MDRawThreadList> list(&writer_);
|
||||
if (!list.AllocateObjectAndArray(lwp_count, sizeof(MDRawThread)))
|
||||
if (!list.AllocateObjectAndArray(lwp_count - 1, sizeof(MDRawThread)))
|
||||
return false;
|
||||
dir->stream_type = MD_THREAD_LIST_STREAM;
|
||||
dir->location = list.location();
|
||||
list.get()->number_of_threads = lwp_count;
|
||||
list.get()->number_of_threads = lwp_count - 1;
|
||||
|
||||
LwpInfoCallbackCtx context;
|
||||
context.generator = this;
|
||||
|
@ -351,8 +391,8 @@ bool MinidumpGenerator::WriteSystemInfoStream(MDRawDirectory *dir) {
|
|||
|
||||
bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *dir) {
|
||||
ucontext_t uc;
|
||||
prgregset_t *gregs;
|
||||
prfpregset_t fp_regs;
|
||||
gregset_t *gregs;
|
||||
fpregset_t fp_regs;
|
||||
|
||||
if (getcontext(&uc) != 0)
|
||||
return false;
|
||||
|
@ -369,8 +409,34 @@ bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *dir) {
|
|||
|
||||
gregs = &(uc.uc_mcontext.gregs);
|
||||
fp_regs = uc.uc_mcontext.fpregs;
|
||||
#if TARGET_CPU_SPARC
|
||||
exception.get()->exception_record.exception_address = ((unsigned int *)gregs)[1];
|
||||
// Write context of the exception.
|
||||
TypedMDRVA<MDRawContextSPARC> context(&writer_);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
exception.get()->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextSPARC));
|
||||
|
||||
// On Solaris i386, gregset_t = prgregset_t, fpregset_t = prfpregset_t
|
||||
// But on Solaris Sparc are diffrent, see sys/regset.h and sys/procfs_isa.h
|
||||
context.get()->context_flags = MD_CONTEXT_SPARC_FULL;
|
||||
context.get()->ccr = ((unsigned int *)gregs)[0];
|
||||
context.get()->pc = ((unsigned int *)gregs)[1];
|
||||
context.get()->npc = ((unsigned int *)gregs)[2];
|
||||
context.get()->y = ((unsigned int *)gregs)[3];
|
||||
context.get()->asi = ((unsigned int *)gregs)[19];
|
||||
context.get()->fprs = ((unsigned int *)gregs)[20];
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
context.get()->g_r[i] = 0;
|
||||
}
|
||||
for (int i = 1; i < 16; ++i) {
|
||||
context.get()->g_r[i] = ((unsigned int *)gregs)[i + 3];
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif TARGET_CPU_X86
|
||||
exception.get()->exception_record.exception_address = (*gregs)[EIP];
|
||||
|
||||
// Write context of the exception.
|
||||
TypedMDRVA<MDRawContextX86> context(&writer_);
|
||||
if (!context.Allocate())
|
||||
|
@ -378,6 +444,7 @@ bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *dir) {
|
|||
exception.get()->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextX86));
|
||||
return WriteContext(context.get(), (int *)gregs, &fp_regs);
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *dir) {
|
||||
|
|
|
@ -32,6 +32,14 @@
|
|||
#ifndef CLIENT_SOLARIS_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
#define CLIENT_SOLARIS_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
|
||||
#if defined(sparc) || defined(__sparc__)
|
||||
#define TARGET_CPU_SPARC 1
|
||||
#elif defined(i386) || defined(__i386__)
|
||||
#define TARGET_CPU_X86 1
|
||||
#else
|
||||
#error "cannot determine cpu type"
|
||||
#endif
|
||||
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "client/solaris/handler/solaris_lwp.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
@ -69,8 +77,13 @@ class MinidumpGenerator {
|
|||
MDMemoryDescriptor *loc);
|
||||
|
||||
// Write CPU context based on provided registers.
|
||||
#if TARGET_CPU_SPARC
|
||||
bool WriteContext(MDRawContextSPARC *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs);
|
||||
#elif TARGET_CPU_X86
|
||||
bool WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs);
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
|
||||
// Write information about a lwp.
|
||||
// Only processes lwp running normally at the crash.
|
||||
|
|
|
@ -217,7 +217,7 @@ int SolarisLwp::Lwp_iter_all(int pid,
|
|||
lwpsinfo_t *Lpsp;
|
||||
long nstat;
|
||||
long ninfo;
|
||||
int rv;
|
||||
int rv = 0;
|
||||
|
||||
/*
|
||||
* The /proc/pid/lstatus file has the array of lwpstatus_t's and the
|
||||
|
@ -240,8 +240,9 @@ int SolarisLwp::Lwp_iter_all(int pid,
|
|||
sp = NULL;
|
||||
}
|
||||
if (callback_param &&
|
||||
!(rv = (callback_param->call_back)(sp, callback_param->context)))
|
||||
!(callback_param->call_back)(sp, callback_param->context))
|
||||
break;
|
||||
++rv;
|
||||
Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
|
||||
}
|
||||
|
||||
|
@ -279,7 +280,8 @@ int SolarisLwp::ListModules(
|
|||
return -1;
|
||||
|
||||
/*
|
||||
* Determine number of mappings.
|
||||
* Determine number of mappings, this value must be
|
||||
* larger than the actual module count
|
||||
*/
|
||||
size = status.st_size;
|
||||
if ((num = (int)(size / sizeof (prmap_t))) > MAP_MAX) {
|
||||
|
@ -287,9 +289,6 @@ int SolarisLwp::ListModules(
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!callback_param)
|
||||
return num; // return the Module count
|
||||
|
||||
if (read(fd, (void *)maps, size) < 0) {
|
||||
print_message2(2, "failed to read %d\n", fd);
|
||||
return -1;
|
||||
|
@ -297,7 +296,8 @@ int SolarisLwp::ListModules(
|
|||
|
||||
prmap_t *_maps;
|
||||
int _num;
|
||||
|
||||
int module_count = 0;
|
||||
|
||||
/*
|
||||
* Scan each mapping - note it is assummed that the mappings are
|
||||
* presented in order. We fill holes between mappings. On intel
|
||||
|
@ -313,15 +313,17 @@ int SolarisLwp::ListModules(
|
|||
memset(&module, 0, sizeof (module));
|
||||
module.start_addr = _maps->pr_vaddr;
|
||||
module.size = _maps->pr_size;
|
||||
if (name && (strcmp(name, "a.out") != 0))
|
||||
if ((strlen(name) > 0) && (strcmp(name, "a.out") != 0)) {
|
||||
strncpy(module.name, name, sizeof (module.name) - 1);
|
||||
++module_count;
|
||||
}
|
||||
if (callback_param &&
|
||||
(!callback_param->call_back(module, callback_param->context))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
return module_count;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -215,6 +215,87 @@ typedef struct {
|
|||
|
||||
#define MD_CONTEXT_CPU_MASK 0xffffffc0
|
||||
|
||||
/*
|
||||
* SPARC support, see (solaris)sys/procfs_isa.h also
|
||||
*/
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* FPU floating point regs */
|
||||
u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
|
||||
u_int64_t filler;
|
||||
u_int64_t fsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
|
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
u_int32_t context_flags;
|
||||
u_int32_t flag_pad;
|
||||
/*
|
||||
* General register access (SPARC).
|
||||
* Don't confuse definitions here with definitions in <sys/regset.h>.
|
||||
* Registers are 32 bits for ILP32, 64 bits for LP64.
|
||||
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
|
||||
*/
|
||||
|
||||
/* 32 Integer working registers */
|
||||
|
||||
/* g_r[0-7] global registers(g0-g7)
|
||||
* g_r[8-15] out registers(o0-o7)
|
||||
* g_r[16-23] local registers(l0-l7)
|
||||
* g_r[24-31] in registers(i0-i7)
|
||||
*/
|
||||
u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
|
||||
|
||||
/* several control registers */
|
||||
|
||||
/* Processor State register(PSR) for SPARC V7/V8
|
||||
* Condition Code register (CCR) for SPARC V9
|
||||
*/
|
||||
u_int64_t ccr;
|
||||
|
||||
u_int64_t pc; /* Program Counter register (PC) */
|
||||
u_int64_t npc; /* Next Program Counter register (nPC) */
|
||||
u_int64_t y; /* Y register (Y) */
|
||||
|
||||
/* Address Space Identifier register (ASI) for SPARC V9
|
||||
* WIM for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t asi;
|
||||
|
||||
/* Floating-Point Registers State register (FPRS) for SPARC V9
|
||||
* TBR for for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t fprs;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
|
||||
MDFloatingSaveAreaSPARC float_save;
|
||||
|
||||
} MDRawContextSPARC; /* CONTEXT_SPARC */
|
||||
|
||||
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_SPARC 0x10000000
|
||||
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001)
|
||||
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002)
|
||||
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
|
||||
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008)
|
||||
|
||||
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \
|
||||
MD_CONTEXT_SPARC_INTEGER)
|
||||
|
||||
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \
|
||||
MD_CONTEXT_SAPARC_FLOATING_POINT | \
|
||||
MD_CONTEXT_SAPARC_EXTRA)
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X'
|
||||
|
@ -929,6 +1010,54 @@ typedef enum {
|
|||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */
|
||||
} MDExceptionCodeLinux;
|
||||
|
||||
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */
|
||||
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */
|
||||
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */
|
||||
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */
|
||||
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occured */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */
|
||||
} MDExceptionCodeSolaris;
|
||||
|
||||
typedef struct {
|
||||
u_int32_t thread_id; /* Thread in which the exception
|
||||
* occurred. Corresponds to
|
||||
|
|
|
@ -177,7 +177,8 @@ class MinidumpContext : public MinidumpStream {
|
|||
// NULL.
|
||||
const MDRawContextX86* GetContextX86() const;
|
||||
const MDRawContextPPC* GetContextPPC() const;
|
||||
|
||||
const MDRawContextSPARC* GetContextSPARC() const;
|
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print();
|
||||
|
||||
|
@ -204,6 +205,9 @@ class MinidumpContext : public MinidumpStream {
|
|||
MDRawContextBase* base;
|
||||
MDRawContextX86* x86;
|
||||
MDRawContextPPC* ppc;
|
||||
// on Solaris SPARC, sparc is defined as a numeric constant,
|
||||
// so variables can NOT be named as sparc
|
||||
MDRawContextSPARC* ctx_sparc;
|
||||
} context_;
|
||||
};
|
||||
|
||||
|
|
|
@ -98,6 +98,30 @@ struct StackFramePPC : public StackFrame {
|
|||
int context_validity;
|
||||
};
|
||||
|
||||
struct StackFrameSPARC : public StackFrame {
|
||||
// to be confirmed
|
||||
enum ContextValidity {
|
||||
CONTEXT_VALID_NONE = 0,
|
||||
CONTEXT_VALID_PC = 0 << 0,
|
||||
CONTEXT_VALID_SP = 0 << 1,
|
||||
CONTEXT_VALID_FP = 0 << 2,
|
||||
CONTEXT_VALID_ALL = -1
|
||||
};
|
||||
|
||||
StackFrameSPARC() : 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.
|
||||
MDRawContextSPARC 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;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) <<
|
||||
|
|
|
@ -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__)
|
||||
|
|
111
src/processor/stackwalker_selftest_sol.s
Normal file
111
src/processor/stackwalker_selftest_sol.s
Normal file
|
@ -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
|
139
src/processor/stackwalker_sparc.cc
Normal file
139
src/processor/stackwalker_sparc.cc
Normal file
|
@ -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
|
86
src/processor/stackwalker_sparc.h
Normal file
86
src/processor/stackwalker_sparc.h
Normal file
|
@ -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__
|
Loading…
Reference in a new issue