mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 818793 - Add a |aMaxFrames| parameter to NS_StackWalk. r=jlebar,glandium; sr=dbaron.
This commit is contained in:
parent
b6f32fe10b
commit
0ea79c11c5
@ -707,10 +707,10 @@ public:
|
||||
|
||||
class StackTrace
|
||||
{
|
||||
static const uint32_t MaxDepth = 24;
|
||||
static const uint32_t MaxFrames = 24;
|
||||
|
||||
uint32_t mLength; // The number of PCs.
|
||||
void* mPcs[MaxDepth]; // The PCs themselves.
|
||||
void* mPcs[MaxFrames]; // The PCs themselves.
|
||||
|
||||
public:
|
||||
StackTrace() : mLength(0) {}
|
||||
@ -751,13 +751,9 @@ private:
|
||||
static void StackWalkCallback(void* aPc, void* aSp, void* aClosure)
|
||||
{
|
||||
StackTrace* st = (StackTrace*) aClosure;
|
||||
|
||||
// Only fill to MaxDepth.
|
||||
// XXX: bug 818793 will allow early bailouts.
|
||||
if (st->mLength < MaxDepth) {
|
||||
st->mPcs[st->mLength] = aPc;
|
||||
st->mLength++;
|
||||
}
|
||||
MOZ_ASSERT(st->mLength < MaxFrames);
|
||||
st->mPcs[st->mLength] = aPc;
|
||||
st->mLength++;
|
||||
}
|
||||
|
||||
static int QsortCmp(const void* aA, const void* aB)
|
||||
@ -778,7 +774,7 @@ void
|
||||
StackTrace::Print(const Writer& aWriter, LocationService* aLocService) const
|
||||
{
|
||||
if (mLength == 0) {
|
||||
W(" (empty)\n");
|
||||
W(" (empty)\n"); // StackTrace::Get() must have failed
|
||||
return;
|
||||
}
|
||||
|
||||
@ -800,17 +796,33 @@ StackTrace::Get(Thread* aT)
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
|
||||
// On Linux, something similar can happen; see bug 824340.
|
||||
// So let's just release it on all platforms.
|
||||
nsresult rv;
|
||||
StackTrace tmp;
|
||||
{
|
||||
AutoUnlockState unlock;
|
||||
// In normal operation, skip=3 gets us past various malloc wrappers into
|
||||
// more interesting stuff. But in test mode we need to skip a bit less to
|
||||
// sufficiently differentiate some similar stacks.
|
||||
uint32_t skip = 2;
|
||||
nsresult rv = NS_StackWalk(StackWalkCallback, skip, &tmp, 0, nullptr);
|
||||
if (NS_FAILED(rv) || tmp.mLength == 0) {
|
||||
tmp.mLength = 0;
|
||||
}
|
||||
uint32_t skipFrames = 2;
|
||||
rv = NS_StackWalk(StackWalkCallback, skipFrames, MaxFrames, &tmp, 0,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (rv == NS_OK) {
|
||||
// Handle the common case first. All is ok. Nothing to do.
|
||||
} else if (rv == NS_ERROR_NOT_IMPLEMENTED || rv == NS_ERROR_FAILURE) {
|
||||
tmp.mLength = 0;
|
||||
} else if (rv == NS_ERROR_UNEXPECTED) {
|
||||
// XXX: This |rv| only happens on Mac, and it indicates that we're handling
|
||||
// a call to malloc that happened inside a mutex-handling function. Any
|
||||
// attempt to create a semaphore (which can happen in printf) could
|
||||
// deadlock.
|
||||
//
|
||||
// However, the most complex thing DMD does after Get() returns is to put
|
||||
// something in a hash table, which might call
|
||||
// InfallibleAllocPolicy::malloc_. I'm not yet sure if this needs special
|
||||
// handling, hence the forced abort. Sorry. If you hit this, please file
|
||||
// a bug and CC nnethercote.
|
||||
MOZ_CRASH();
|
||||
} else {
|
||||
MOZ_CRASH(); // should be impossible
|
||||
}
|
||||
|
||||
StackTraceTable::AddPtr p = gStackTraceTable->lookupForAdd(&tmp);
|
||||
@ -1670,7 +1682,8 @@ Init(const malloc_table_t* aMallocTable)
|
||||
// StackWalkInitCriticalAddress() isn't exported from xpcom/, so instead we
|
||||
// just call NS_StackWalk, because that calls StackWalkInitCriticalAddress().
|
||||
// See the comment above StackWalkInitCriticalAddress() for more details.
|
||||
(void)NS_StackWalk(NopStackWalkCallback, 0, nullptr, 0, nullptr);
|
||||
(void)NS_StackWalk(NopStackWalkCallback, /* skipFrames */ 0,
|
||||
/* maxFrames */ 1, nullptr, 0, nullptr);
|
||||
#endif
|
||||
|
||||
gStateLock = InfallibleAllocPolicy::new_<Mutex>();
|
||||
|
@ -77,7 +77,8 @@ ah_crap_handler(int signum)
|
||||
signum);
|
||||
|
||||
printf("Stack:\n");
|
||||
NS_StackWalk(PrintStackFrame, 2, nullptr, 0, nullptr);
|
||||
NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0,
|
||||
nullptr, 0, nullptr);
|
||||
|
||||
printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
|
||||
printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
|
||||
|
@ -796,10 +796,7 @@ static
|
||||
void StackWalkCallback(void* aPC, void* aSP, void* aClosure)
|
||||
{
|
||||
PCArray* array = static_cast<PCArray*>(aClosure);
|
||||
if (array->count >= array->size) {
|
||||
// too many frames, ignore
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(array->count < array->size);
|
||||
array->sp_array[array->count] = aSP;
|
||||
array->array[array->count] = aPC;
|
||||
array->count++;
|
||||
@ -828,6 +825,7 @@ void TableTicker::doBacktrace(ThreadProfile &aProfile, TickSample* aSample)
|
||||
platformData = aSample->context;
|
||||
#endif
|
||||
|
||||
uint32_t maxFrames = array.size - array.count;
|
||||
#ifdef XP_MACOSX
|
||||
pthread_t pt = GetProfiledThread(platform_data());
|
||||
void *stackEnd = reinterpret_cast<void*>(-1);
|
||||
@ -835,9 +833,12 @@ void TableTicker::doBacktrace(ThreadProfile &aProfile, TickSample* aSample)
|
||||
stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
|
||||
nsresult rv = NS_OK;
|
||||
if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
|
||||
rv = FramePointerStackWalk(StackWalkCallback, 0, &array, reinterpret_cast<void**>(aSample->fp), stackEnd);
|
||||
rv = FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0,
|
||||
maxFrames, &array,
|
||||
reinterpret_cast<void**>(aSample->fp), stackEnd);
|
||||
#else
|
||||
nsresult rv = NS_StackWalk(StackWalkCallback, 0, &array, thread, platformData);
|
||||
nsresult rv = NS_StackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
|
||||
&array, thread, platformData);
|
||||
#endif
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aProfile.addTag(ProfileEntry('s', "(root)"));
|
||||
|
@ -914,7 +914,7 @@ stack_callback(void *pc, void *sp, void *closure)
|
||||
* without doing anything (such as acquiring locks).
|
||||
*/
|
||||
static callsite *
|
||||
backtrace(tm_thread *t, int skip, int *immediate_abort)
|
||||
backtrace(tm_thread *t, int skipFrames, int *immediate_abort)
|
||||
{
|
||||
callsite *site;
|
||||
stack_buffer_info *info = &t->backtrace_buf;
|
||||
@ -929,7 +929,8 @@ backtrace(tm_thread *t, int skip, int *immediate_abort)
|
||||
/* Walk the stack, even if stacks_enabled is false. We do this to
|
||||
check if we must set immediate_abort. */
|
||||
info->entries = 0;
|
||||
rv = NS_StackWalk(stack_callback, skip, info, 0, NULL);
|
||||
rv = NS_StackWalk(stack_callback, skipFrames, /* maxFrames */ 0, info,
|
||||
0, NULL);
|
||||
*immediate_abort = rv == NS_ERROR_UNEXPECTED;
|
||||
if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
|
||||
t->suppress_tracing--;
|
||||
@ -961,10 +962,14 @@ backtrace(tm_thread *t, int skip, int *immediate_abort)
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
|
||||
*/
|
||||
|
||||
/* skip == 0 means |backtrace| should show up, so don't use skip + 1 */
|
||||
/* NB: this call is repeated below if the buffer is too small */
|
||||
/*
|
||||
* skipFrames == 0 means |backtrace| should show up, so don't use
|
||||
* skipFrames + 1.
|
||||
* NB: this call is repeated below if the buffer is too small.
|
||||
*/
|
||||
info->entries = 0;
|
||||
rv = NS_StackWalk(stack_callback, skip, info, 0, NULL);
|
||||
rv = NS_StackWalk(stack_callback, skipFrames, /* maxFrames */ 0, info,
|
||||
0, NULL);
|
||||
*immediate_abort = rv == NS_ERROR_UNEXPECTED;
|
||||
if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
|
||||
t->suppress_tracing--;
|
||||
@ -988,7 +993,8 @@ backtrace(tm_thread *t, int skip, int *immediate_abort)
|
||||
|
||||
/* and call NS_StackWalk again */
|
||||
info->entries = 0;
|
||||
NS_StackWalk(stack_callback, skip, info, 0, NULL);
|
||||
NS_StackWalk(stack_callback, skipFrames, /* maxFrames */ 0, info,
|
||||
0, NULL);
|
||||
|
||||
/* same stack */
|
||||
PR_ASSERT(info->entries * 2 == new_stack_buffer_size);
|
||||
|
@ -15,7 +15,8 @@ namespace mozilla {
|
||||
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, void **bp, void *stackEnd);
|
||||
uint32_t aMaxFrames, void *aClosure, void **bp,
|
||||
void *stackEnd);
|
||||
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,8 @@ my_malloc_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
|
||||
// stack shows up as having two pthread_cond_wait$UNIX2003 frames.
|
||||
const char *name = OnSnowLeopardOrLater() ? "new_sem_from_pool" :
|
||||
"pthread_cond_wait$UNIX2003";
|
||||
NS_StackWalk(stack_callback, 0, const_cast<char*>(name), 0, nullptr);
|
||||
NS_StackWalk(stack_callback, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
const_cast<char*>(name), 0, nullptr);
|
||||
}
|
||||
|
||||
// This is called from NS_LogInit() and from the stack walking functions, but
|
||||
@ -216,6 +217,7 @@ struct WalkStackData {
|
||||
void **pcs;
|
||||
uint32_t pc_size;
|
||||
uint32_t pc_count;
|
||||
uint32_t pc_max;
|
||||
void **sps;
|
||||
uint32_t sp_size;
|
||||
uint32_t sp_count;
|
||||
@ -393,6 +395,9 @@ WalkStackMain64(struct WalkStackData* data)
|
||||
data->sps[data->sp_count] = (void*)spaddr;
|
||||
++data->sp_count;
|
||||
|
||||
if (data->pc_max != 0 && data->pc_count == data->pc_max)
|
||||
break;
|
||||
|
||||
if (frame64.AddrReturn.Offset == 0)
|
||||
break;
|
||||
}
|
||||
@ -462,7 +467,8 @@ WalkStackThread(void* aData)
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData)
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData)
|
||||
{
|
||||
StackWalkInitCriticalAddress();
|
||||
static HANDLE myProcess = NULL;
|
||||
@ -471,7 +477,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
struct WalkStackData data;
|
||||
|
||||
if (!EnsureImageHlpInitialized())
|
||||
return NS_OK;
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
HANDLE targetThread = ::GetCurrentThread();
|
||||
data.walkCallingThread = true;
|
||||
@ -517,10 +523,11 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
data.pcs = local_pcs;
|
||||
data.pc_count = 0;
|
||||
data.pc_size = ArrayLength(local_pcs);
|
||||
data.pc_max = aMaxFrames;
|
||||
void *local_sps[1024];
|
||||
data.sps = local_sps;
|
||||
data.sp_count = 0;
|
||||
data.sp_size = ArrayLength(local_pcs);
|
||||
data.sp_size = ArrayLength(local_sps);
|
||||
data.platformData = aPlatformData;
|
||||
|
||||
if (aThread) {
|
||||
@ -572,7 +579,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
for (uint32_t i = 0; i < data.pc_count; ++i)
|
||||
(*aCallback)(data.pcs[i], data.sps[i], aClosure);
|
||||
|
||||
return NS_OK;
|
||||
return data.pc_count == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -898,6 +905,8 @@ struct bucket {
|
||||
struct my_user_args {
|
||||
NS_WalkStackCallback callback;
|
||||
uint32_t skipFrames;
|
||||
uint32_t maxFrames;
|
||||
uint32_t numFrames;
|
||||
void *closure;
|
||||
};
|
||||
|
||||
@ -931,7 +940,7 @@ myinit()
|
||||
|
||||
|
||||
static int
|
||||
load_address(void * pc, void * arg )
|
||||
load_address(void * pc, void * arg)
|
||||
{
|
||||
static struct bucket table[2048];
|
||||
static mutex_t lock;
|
||||
@ -949,15 +958,19 @@ load_address(void * pc, void * arg )
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
int stop = 0;
|
||||
if (ptr->next) {
|
||||
mutex_unlock(&lock);
|
||||
} else {
|
||||
(args->callback)(pc, args->closure);
|
||||
args->numFrames++;
|
||||
if (args->maxFrames != 0 && args->numFrames == args->maxFrames)
|
||||
stop = 1; // causes us to stop getting frames
|
||||
|
||||
ptr->next = newbucket(pc);
|
||||
mutex_unlock(&lock);
|
||||
}
|
||||
return 0;
|
||||
return stop;
|
||||
}
|
||||
|
||||
|
||||
@ -1020,7 +1033,8 @@ cs_operate(int (*operate_func)(void *, void *, void *), void * usrarg)
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData)
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData)
|
||||
{
|
||||
MOZ_ASSERT(!aThread);
|
||||
MOZ_ASSERT(!aPlatformData);
|
||||
@ -1033,9 +1047,11 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
|
||||
args.callback = aCallback;
|
||||
args.skipFrames = aSkipFrames; /* XXX Not handled! */
|
||||
args.maxFrames = aMaxFrames;
|
||||
args.numFrames = 0;
|
||||
args.closure = aClosure;
|
||||
cs_operate(load_address, &args);
|
||||
return NS_OK;
|
||||
return args.numFrames == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
@ -1100,11 +1116,13 @@ extern void *__libc_stack_end; // from ld-linux.so
|
||||
namespace mozilla {
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, void **bp, void *aStackEnd)
|
||||
uint32_t aMaxFrames, void *aClosure, void **bp,
|
||||
void *aStackEnd)
|
||||
{
|
||||
// Stack walking code courtesy Kipp's "leaky".
|
||||
|
||||
int skip = aSkipFrames;
|
||||
int32_t skip = aSkipFrames;
|
||||
uint32_t numFrames = 0;
|
||||
while (1) {
|
||||
void **next = (void**)*bp;
|
||||
// bp may not be a frame pointer on i386 if code was compiled with
|
||||
@ -1136,10 +1154,13 @@ FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
// but this should be sufficient for our use the SP
|
||||
// to order elements on the stack.
|
||||
(*aCallback)(pc, bp, aClosure);
|
||||
numFrames++;
|
||||
if (aMaxFrames != 0 && numFrames == aMaxFrames)
|
||||
break;
|
||||
}
|
||||
bp = next;
|
||||
}
|
||||
return NS_OK;
|
||||
return numFrames == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1149,7 +1170,8 @@ FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData)
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData)
|
||||
{
|
||||
MOZ_ASSERT(!aThread);
|
||||
MOZ_ASSERT(!aPlatformData);
|
||||
@ -1172,7 +1194,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
#else
|
||||
stackEnd = reinterpret_cast<void*>(-1);
|
||||
#endif
|
||||
return FramePointerStackWalk(aCallback, aSkipFrames,
|
||||
return FramePointerStackWalk(aCallback, aSkipFrames, aMaxFrames,
|
||||
aClosure, bp, stackEnd);
|
||||
|
||||
}
|
||||
@ -1188,6 +1210,9 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
struct unwind_info {
|
||||
NS_WalkStackCallback callback;
|
||||
int skip;
|
||||
int maxFrames;
|
||||
int numFrames;
|
||||
bool isCriticalAbort;
|
||||
void *closure;
|
||||
};
|
||||
|
||||
@ -1199,19 +1224,27 @@ unwind_callback (struct _Unwind_Context *context, void *closure)
|
||||
// TODO Use something like '_Unwind_GetGR()' to get the stack pointer.
|
||||
if (IsCriticalAddress(pc)) {
|
||||
printf("Aborting stack trace, PC is critical\n");
|
||||
/* We just want to stop the walk, so any error code will do.
|
||||
Using _URC_NORMAL_STOP would probably be the most accurate,
|
||||
but it is not defined on Android for ARM. */
|
||||
info->isCriticalAbort = true;
|
||||
// We just want to stop the walk, so any error code will do. Using
|
||||
// _URC_NORMAL_STOP would probably be the most accurate, but it is not
|
||||
// defined on Android for ARM.
|
||||
return _URC_FOREIGN_EXCEPTION_CAUGHT;
|
||||
}
|
||||
if (--info->skip < 0)
|
||||
if (--info->skip < 0) {
|
||||
(*info->callback)(pc, NULL, info->closure);
|
||||
info->numFrames++;
|
||||
if (info->maxFrames != 0 && info->numFrames == info->maxFrames) {
|
||||
// Again, any error code that stops the walk will do.
|
||||
return _URC_FOREIGN_EXCEPTION_CAUGHT;
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData)
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData)
|
||||
{
|
||||
MOZ_ASSERT(!aThread);
|
||||
MOZ_ASSERT(!aPlatformData);
|
||||
@ -1219,21 +1252,24 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
unwind_info info;
|
||||
info.callback = aCallback;
|
||||
info.skip = aSkipFrames + 1;
|
||||
info.maxFrames = aMaxFrames;
|
||||
info.numFrames = 0;
|
||||
info.isCriticalAbort = false;
|
||||
info.closure = aClosure;
|
||||
|
||||
_Unwind_Reason_Code t = _Unwind_Backtrace(unwind_callback, &info);
|
||||
#if defined(ANDROID) && defined(__arm__)
|
||||
// Ignore the _Unwind_Reason_Code on Android + ARM, because bionic's
|
||||
// _Unwind_Backtrace usually (always?) returns _URC_FAILURE. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=717853#c110.
|
||||
//
|
||||
// (Ideally, the #if above would be specifically for bionic, not for
|
||||
// Android + ARM, but we don't have a define specifically for bionic.)
|
||||
#else
|
||||
if (t != _URC_END_OF_STACK)
|
||||
(void)_Unwind_Backtrace(unwind_callback, &info);
|
||||
|
||||
// We ignore the return value from _Unwind_Backtrace and instead determine
|
||||
// the outcome from |info|. There are two main reasons for this:
|
||||
// - On ARM/Android bionic's _Unwind_Backtrace usually (always?) returns
|
||||
// _URC_FAILURE. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=717853#c110.
|
||||
// - If aMaxFrames != 0, we want to stop early, and the only way to do that
|
||||
// is to make unwind_callback return something other than _URC_NO_REASON,
|
||||
// which causes _Unwind_Backtrace to return a non-success code.
|
||||
if (info.isCriticalAbort)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
#endif
|
||||
return NS_OK;
|
||||
return info.numFrames == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1300,7 +1336,8 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails,
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData)
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData)
|
||||
{
|
||||
MOZ_ASSERT(!aThread);
|
||||
MOZ_ASSERT(!aPlatformData);
|
||||
|
@ -31,6 +31,7 @@ typedef void
|
||||
* @param aSkipFrames Number of initial frames to skip. 0 means that
|
||||
* the first callback will be for the caller of
|
||||
* NS_StackWalk.
|
||||
* @param aMaxFrames Maximum number of frames to trace. 0 means no limit.
|
||||
* @param aClosure Caller-supplied data passed through to aCallback.
|
||||
* @param aThread The thread for which the stack is to be retrieved.
|
||||
* Passing null causes us to walk the stack of the
|
||||
@ -42,18 +43,26 @@ typedef void
|
||||
* CONTEXT on Windows and should not be passed on other
|
||||
* platforms.
|
||||
*
|
||||
* Returns NS_ERROR_NOT_IMPLEMENTED on platforms where it is
|
||||
* unimplemented.
|
||||
* Returns NS_ERROR_UNEXPECTED when the stack indicates that the thread
|
||||
* is in a very dangerous situation (e.g., holding sem_pool_lock in
|
||||
* Mac OS X pthreads code). Callers should then bail out immediately.
|
||||
* Return values:
|
||||
* - NS_ERROR_NOT_IMPLEMENTED. Occurs on platforms where it is unimplemented.
|
||||
*
|
||||
* - NS_ERROR_UNEXPECTED. Occurs when the stack indicates that the thread
|
||||
* is in a very dangerous situation (e.g., holding sem_pool_lock in Mac OS X
|
||||
* pthreads code). Callers should then bail out immediately.
|
||||
*
|
||||
* - NS_ERROR_FAILURE. Occurs when stack walking completely failed, i.e.
|
||||
* aCallback was never called.
|
||||
*
|
||||
* - NS_OK. Occurs when stack walking succeeded, i.e. aCallback was called at
|
||||
* least once (and there was no need to exit with NS_ERROR_UNEXPECTED).
|
||||
*
|
||||
* May skip some stack frames due to compiler optimizations or code
|
||||
* generation.
|
||||
*/
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread, void *aPlatformData);
|
||||
uint32_t aMaxFrames, void *aClosure, uintptr_t aThread,
|
||||
void *aPlatformData);
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
|
@ -854,7 +854,8 @@ static void PrintStackFrame(void *aPC, void *aSP, void *aClosure)
|
||||
void
|
||||
nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
|
||||
{
|
||||
NS_StackWalk(PrintStackFrame, 2, aStream, 0, nullptr);
|
||||
NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream,
|
||||
0, nullptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -96,7 +96,8 @@ bool ValidWriteAssert(bool ok)
|
||||
// concurrently from many writes, so we use multiple temporary files.
|
||||
std::vector<uintptr_t> rawStack;
|
||||
|
||||
NS_StackWalk(RecordStackWalker, 0, reinterpret_cast<void*>(&rawStack), 0, nullptr);
|
||||
NS_StackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
reinterpret_cast<void*>(&rawStack), 0, nullptr);
|
||||
Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack);
|
||||
|
||||
nsPrintfCString nameAux("%s%s", sProfileDirectory,
|
||||
|
@ -137,7 +137,8 @@ GetChromeHangReport(Telemetry::ProcessedStack &aStack)
|
||||
DWORD ret = ::SuspendThread(winMainThreadHandle);
|
||||
if (ret == -1)
|
||||
return;
|
||||
NS_StackWalk(ChromeStackWalker, 0, reinterpret_cast<void*>(&rawStack),
|
||||
NS_StackWalk(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
reinterpret_cast<void*>(&rawStack),
|
||||
reinterpret_cast<uintptr_t>(winMainThreadHandle), nullptr);
|
||||
ret = ::ResumeThread(winMainThreadHandle);
|
||||
if (ret == -1)
|
||||
|
Loading…
Reference in New Issue
Block a user