Bug 766579 - Part 1: Add SP param to NS_StackWalk. r=dbaron

--HG--
extra : rebase_source : dd4905ffadf5fe9327449fffdfbc665b05d74a6a
This commit is contained in:
Benoit Girard 2012-06-27 16:08:21 -04:00
parent ec268d38f1
commit 325b77e999
7 changed files with 46 additions and 18 deletions

View File

@ -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;

View File

@ -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<PCArray*>(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());

View File

@ -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;

View File

@ -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<char *>(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<unwind_info *>(closure);
void *pc = reinterpret_cast<void *>(_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;
}

View File

@ -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

View File

@ -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;

View File

@ -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 =