diff --git a/toolkit/xre/nsSigHandlers.cpp b/toolkit/xre/nsSigHandlers.cpp index 74ddeb9122c8..fb0cddefd837 100644 --- a/toolkit/xre/nsSigHandlers.cpp +++ b/toolkit/xre/nsSigHandlers.cpp @@ -56,7 +56,7 @@ static const int kClientChannelFd = 3; extern "C" { -static void PrintStackFrame(void *aPC, void *aClosure) +static void PrintStackFrame(void *aPC, void *aSP, void *aClosure) { char buf[1024]; nsCodeAddressDetails details; diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 7d401d0f616d..946a5a8ce2c6 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -586,7 +586,7 @@ typedef struct { } PCArray; static -void StackWalkCallback(void* aPC, void* aClosure) +void StackWalkCallback(void* aPC, void* aSP, void* aClosure) { PCArray* array = static_cast(aClosure); if (array->count >= array->size) { @@ -610,7 +610,7 @@ void TableTicker::doBacktrace(ThreadProfile &aProfile, TickSample* aSample) }; // Start with the current function. - StackWalkCallback(aSample->pc, &array); + StackWalkCallback(aSample->pc, aSample->sp, &array); #ifdef XP_MACOSX pthread_t pt = GetProfiledThread(platform_data()); diff --git a/tools/trace-malloc/lib/nsTraceMalloc.c b/tools/trace-malloc/lib/nsTraceMalloc.c index d2e0d4c90b9a..180f24e163ac 100644 --- a/tools/trace-malloc/lib/nsTraceMalloc.c +++ b/tools/trace-malloc/lib/nsTraceMalloc.c @@ -893,7 +893,7 @@ calltree(void **stack, size_t num_stack_entries, tm_thread *t) * reverse it in calltree. */ static void -stack_callback(void *pc, void *closure) +stack_callback(void *pc, void *sp, void *closure) { stack_buffer_info *info = (stack_buffer_info*) closure; diff --git a/xpcom/base/nsStackWalk.cpp b/xpcom/base/nsStackWalk.cpp index 2409b370527f..6ffbd04a4a7f 100644 --- a/xpcom/base/nsStackWalk.cpp +++ b/xpcom/base/nsStackWalk.cpp @@ -51,7 +51,7 @@ malloc_logger_t(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, extern malloc_logger_t *malloc_logger; static void -stack_callback(void *pc, void *closure) +stack_callback(void *pc, void *sp, void *closure) { const char *name = reinterpret_cast(closure); Dl_info info; @@ -210,6 +210,9 @@ struct WalkStackData { void **pcs; PRUint32 pc_size; PRUint32 pc_count; + void **sps; + PRUint32 sp_size; + PRUint32 sp_count; }; void PrintError(char *prefix, WalkStackData* data); @@ -288,6 +291,7 @@ WalkStackMain64(struct WalkStackData* data) HANDLE myProcess = data->process; HANDLE myThread = data->thread; DWORD64 addr; + DWORD64 spaddr; STACKFRAME64 frame64; // skip our own stack walking frames int skip = (data->walkCallingThread ? 3 : 0) + data->skipFrames; @@ -349,10 +353,12 @@ WalkStackMain64(struct WalkStackData* data) ); LeaveCriticalSection(&gDbgHelpCS); - if (ok) + if (ok) { addr = frame64.AddrPC.Offset; - else { + spaddr = frame64.AddrStack.Offset; + } else { addr = 0; + spaddr = 0; PrintError("WalkStack64"); } @@ -368,6 +374,10 @@ WalkStackMain64(struct WalkStackData* data) data->pcs[data->pc_count] = (void*)addr; ++data->pc_count; + if (data->sp_count < data->sp_size) + data->sps[data->sp_count] = (void*)spaddr; + ++data->sp_count; + if (frame64.AddrReturn.Offset == 0) break; } @@ -484,6 +494,10 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, data.pcs = local_pcs; data.pc_count = 0; data.pc_size = ArrayLength(local_pcs); + void *local_sps[1024]; + data.sps = local_sps; + data.sp_count = 0; + data.sp_size = ArrayLength(local_pcs); if (aThread) { // If we're walking the stack of another thread, we don't need to @@ -512,6 +526,9 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, data.pcs = (void**) _alloca(data.pc_count * sizeof(void*)); data.pc_size = data.pc_count; data.pc_count = 0; + data.sps = (void**) _alloca(data.sp_count * sizeof(void*)); + data.sp_size = data.sp_count; + data.sp_count = 0; ::PostThreadMessage(gStackWalkThread, WM_USER, 0, (LPARAM)&data); walkerReturn = ::SignalObjectAndWait(data.eventStart, data.eventEnd, INFINITE, FALSE); @@ -526,7 +543,10 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, ::CloseHandle(myThread); for (PRUint32 i = 0; i < data.pc_count; ++i) - (*aCallback)(data.pcs[i], aClosure); + (*aCallback)(data.pcs[i], data.sps[i], aClosure); + + if (data.sp_size > ArrayLength(local_sps)) + free(data.sps); return NS_OK; } @@ -823,9 +843,9 @@ static struct bucket * newbucket ( void * pc ); static struct frame * cs_getmyframeptr ( void ); static void cs_walk_stack ( void * (*read_func)(char * address), struct frame * fp, - int (*operate_func)(void *, void *), + int (*operate_func)(void *, void *, void *), void * usrarg ); -static void cs_operate ( void (*operate_func)(void *, void *), +static void cs_operate ( void (*operate_func)(void *, void *, void *), void * usrarg ); #ifndef STACK_BIAS @@ -953,13 +973,13 @@ csgetframeptr() static void -cswalkstack(struct frame *fp, int (*operate_func)(void *, void *), +cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, void *), void *usrarg) { while (fp != 0 && fp->fr_savpc != 0) { - if (operate_func((void *)fp->fr_savpc, usrarg) != 0) + if (operate_func((void *)fp->fr_savpc, NULL, usrarg) != 0) break; /* * watch out - libthread stacks look funny at the top @@ -973,7 +993,7 @@ cswalkstack(struct frame *fp, int (*operate_func)(void *, void *), static void -cs_operate(int (*operate_func)(void *, void *), void * usrarg) +cs_operate(int (*operate_func)(void *, void *, void *), void * usrarg) { cswalkstack(csgetframeptr(), operate_func, usrarg); } @@ -1087,7 +1107,11 @@ FramePointerStackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames, return NS_ERROR_UNEXPECTED; } if (--skip < 0) { - (*aCallback)(pc, aClosure); + // Assume that the SP points to the BP of the function + // it called. We can't know the exact location of the SP + // but this should be sufficient for our use the SP + // to order elements on the stack. + (*aCallback)(pc, (bp), aClosure); } bp = next; } @@ -1144,6 +1168,7 @@ unwind_callback (struct _Unwind_Context *context, void *closure) { unwind_info *info = static_cast(closure); void *pc = reinterpret_cast(_Unwind_GetIP(context)); + // TODO Use something like 'unw_get_reg(&cursor, UNW_REG_SP, &sp)' to get sp if (IsCriticalAddress(pc)) { printf("Aborting stack trace, PC is critical\n"); /* We just want to stop the walk, so any error code will do. @@ -1152,7 +1177,7 @@ unwind_callback (struct _Unwind_Context *context, void *closure) return _URC_FOREIGN_EXCEPTION_CAUGHT; } if (--info->skip < 0) - (*info->callback)(pc, info->closure); + (*info->callback)(pc, NULL, info->closure); return _URC_NO_REASON; } diff --git a/xpcom/base/nsStackWalk.h b/xpcom/base/nsStackWalk.h index 600c3900a4fb..3a0c47d7d825 100644 --- a/xpcom/base/nsStackWalk.h +++ b/xpcom/base/nsStackWalk.h @@ -15,8 +15,11 @@ PR_BEGIN_EXTERN_C +// aSP will be the best approximation possible of what the stack pointer will be +// pointing to when the execution returns to executing that at that PC. +// If no approximation can be made it will be NULL. typedef void -(* NS_WalkStackCallback)(void *aPC, void *aClosure); +(* NS_WalkStackCallback)(void *aPC, void *aSP, void *aClosure); /** * Call aCallback for the C/C++ stack frames on the current thread, from diff --git a/xpcom/base/nsTraceRefcntImpl.cpp b/xpcom/base/nsTraceRefcntImpl.cpp index 3325d9bbbb13..90b27583b189 100644 --- a/xpcom/base/nsTraceRefcntImpl.cpp +++ b/xpcom/base/nsTraceRefcntImpl.cpp @@ -836,7 +836,7 @@ static void InitTraceLog(void) extern "C" { -static void PrintStackFrame(void *aPC, void *aClosure) +static void PrintStackFrame(void *aPC, void *aSP, void *aClosure) { FILE *stream = (FILE*)aClosure; nsCodeAddressDetails details; diff --git a/xpcom/threads/HangMonitor.cpp b/xpcom/threads/HangMonitor.cpp index aff31d3f91a3..397882012373 100644 --- a/xpcom/threads/HangMonitor.cpp +++ b/xpcom/threads/HangMonitor.cpp @@ -106,7 +106,7 @@ Crash() #ifdef REPORT_CHROME_HANGS static void -ChromeStackWalker(void *aPC, void *aClosure) +ChromeStackWalker(void *aPC, void *aSP, void *aClosure) { MOZ_ASSERT(aClosure); Telemetry::HangStack *callStack =