void StackAnalyzer::analyze() { std::vector<void *> buffer{64}; auto count = RtlCaptureStackBackTrace(base_skip_frames, buffer.size(), buffer.data(), NULL); if (count < buffer.size()) { buffer.resize(count); } this->stack_addrs = std::move(buffer); }
HPX_API_EXPORT std::size_t trace(void **array,std::size_t n) { #if _WIN32_WINNT < 0x0600 // for Windows XP/Windows Server 2003 if(n>=63) n=62; #endif return RtlCaptureStackBackTrace(ULONG(0),ULONG(n),array,nullptr); }
HPX_BACKTRACE_DECL std::size_t trace(void **array,std::size_t n) { #if _WIN32_WINNT < 0x0600 // for Windows XP/Windows Server 2003 if(n>=63) n=62; #endif return RtlCaptureStackBackTrace(ULONG(0),ULONG(n),array,NULL); }
void WTFGetBacktrace(void** stack, int* size) { #if OS(DARWIN) || (OS(LINUX) && defined(__GLIBC__) && !defined(__UCLIBC__)) *size = backtrace(stack, *size); #elif OS(WINDOWS) *size = RtlCaptureStackBackTrace(0, *size, stack, 0); #else *size = 0; #endif }
void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; uintptr_t ebp; struct frame *frame; uintptr_t callpc; pc_t caller = (pc_t) CPU[KeGetCurrentProcessorNumber()].cpu_dtrace_caller; CONTEXT Context; #if defined(__i386__) || !defined(windows) thread_t *td = curthread; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; ebp = td->ebp; frame = (struct frame *)ebp; while (depth < pcstack_limit) { if ((uintptr_t)frame < td->klimit || (uintptr_t) ((char *) frame - sizeof(struct frame)) >= td->kbase) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } frame = frame->f_frame; } #else // windows and amd64 depth += RtlCaptureStackBackTrace(aframes, pcstack_limit, (PVOID) pcstack, NULL); #endif for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } }
void Win32Callstack::Collect() { std::vector<PVOID> stack32; stack32.resize(64); USHORT num = RtlCaptureStackBackTrace(0, 63, &stack32[0], NULL); stack32.resize(num); while(!stack32.empty() && (uint64_t)stack32[0] >= (uint64_t)renderdocBase && (uint64_t)stack32[0] <= (uint64_t)renderdocBase + renderdocSize) { stack32.erase(stack32.begin()); } m_AddrStack.resize(stack32.size()); for(size_t i = 0; i < stack32.size(); i++) m_AddrStack[i] = (DWORD64)stack32[i]; }
/* * @implemented */ VOID NTAPI RtlGetCallersAddress(OUT PVOID *CallersAddress, OUT PVOID *CallersCaller) { USHORT FrameCount; PVOID BackTrace[2]; PULONG BackTraceHash = NULL; /* Get the tow back trace address */ FrameCount = RtlCaptureStackBackTrace(2, 2, &BackTrace[0],BackTraceHash); /* Only if user want it */ if (*CallersAddress != NULL) { /* only when first frames exist */ if (FrameCount >= 1) { *CallersAddress = BackTrace[0]; } else { *CallersAddress = NULL; } } /* Only if user want it */ if (*CallersCaller != NULL) { /* only when second frames exist */ if (FrameCount >= 2) { *CallersCaller = BackTrace[1]; } else { *CallersCaller = NULL; } } }
static NTSTATUS DebugRegister( IN PXENBUS_DEBUG_CONTEXT Context, IN const CHAR *Prefix, IN VOID (*Function)(PVOID, BOOLEAN), IN PVOID Argument OPTIONAL, OUT PXENBUS_DEBUG_CALLBACK *Callback ) { ULONG Length; KIRQL Irql; NTSTATUS status; *Callback = __DebugAllocate(sizeof (XENBUS_DEBUG_CALLBACK)); status = STATUS_NO_MEMORY; if (*Callback == NULL) goto fail1; (VOID) RtlCaptureStackBackTrace(1, 1, &(*Callback)->Caller, NULL); Length = (ULONG)__min(strlen(Prefix), MAXIMUM_PREFIX_LENGTH - 1); RtlCopyMemory((*Callback)->Prefix, Prefix, Length); (*Callback)->Function = Function; (*Callback)->Argument = Argument; AcquireHighLock(&Context->Lock, &Irql); InsertTailList(&Context->List, &(*Callback)->ListEntry); ReleaseHighLock(&Context->Lock, Irql); return STATUS_SUCCESS; fail1: Error("fail1 (%08x)\n", status); return status; }
int dtrace_getstackdepth(int aframes) { int depth = 0; struct frame *frame; uintptr_t ebp; uintptr_t callpc; thread_t *td = curthread; #if defined(windows) int pcstack_limit = 100; uint64_t pcstack[100]; #endif ebp = td->ebp; frame = (struct frame *)ebp; depth++; #ifdef __amd64 depth += RtlCaptureStackBackTrace(0, pcstack_limit, (PVOID) pcstack, NULL); #else for(;;) { if ((uintptr_t)frame < td->klimit || (uintptr_t) ((char *) frame - sizeof(struct frame)) >= td->kbase) break; depth++; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; frame = frame->f_frame; } #endif if (depth < aframes) return 0; else return depth - aframes; }
VOID NTAPI KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL, IN ULONG FrameCount OPTIONAL) { ULONG_PTR Frames[32]; ULONG RealFrameCount; /* If the caller didn't ask, assume 32 frames */ if (!FrameCount || FrameCount > 32) FrameCount = 32; if (Frame) { /* Dump them */ KeRosDumpStackFrameArray(Frame, FrameCount); } else { /* Get the current frames (skip the two. One for the dumper, one for the caller) */ RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL); DPRINT1("RealFrameCount =%lu\n", RealFrameCount); /* Dump them */ KeRosDumpStackFrameArray(Frames, RealFrameCount); /* Count left for user mode? */ if (FrameCount - RealFrameCount > 0) { /* Get the current frames */ RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL); /* Dump them */ KeRosDumpStackFrameArray(Frames, RealFrameCount); } } }
VOID RtlGetCallersAddress( OUT PVOID *CallersAddress, OUT PVOID *CallersCaller ) /*++ Routine Description: This routine returns the first to callers on the current stack. It should be noted that the function can miss some of the callers in the presence of FPO optimization. Arguments: CallersAddress - address to save the first caller. CallersCaller - address to save the second caller. Return Value: None. If the function does not succeed in finding the two callers it will zero the addresses where it was supposed to write them. Environment: X86, user mode and w/o having a macro with same name defined. --*/ { PVOID BackTrace[ 2 ]; ULONG Hash; USHORT Count; Count = RtlCaptureStackBackTrace( 2, 2, BackTrace, &Hash ); if (ARGUMENT_PRESENT( CallersAddress )) { if (Count >= 1) { *CallersAddress = BackTrace[ 0 ]; } else { *CallersAddress = NULL; } } if (ARGUMENT_PRESENT( CallersCaller )) { if (Count >= 2) { *CallersCaller = BackTrace[ 1 ]; } else { *CallersCaller = NULL; } } return; }
/** * Allocates a object. * * \param Object A variable which receives a pointer to the newly allocated object. * \param ObjectSize The size of the object. * \param Flags A combination of flags specifying how the object is to be allocated. * \li \c PHOBJ_RAISE_ON_FAIL An exception will be raised if the object cannot be * allocated. * \param ObjectType The type of the object. */ __mayRaise NTSTATUS PhCreateObject( __out PVOID *Object, __in SIZE_T ObjectSize, __in ULONG Flags, __in PPH_OBJECT_TYPE ObjectType ) { NTSTATUS status = STATUS_SUCCESS; PPH_OBJECT_HEADER objectHeader; #ifdef PHOBJ_STRICT_CHECKS /* Check the flags. */ if ((Flags & PHOBJ_VALID_FLAGS) != Flags) /* Valid flag mask */ { status = STATUS_INVALID_PARAMETER_3; } #else assert(!((Flags & PHOBJ_VALID_FLAGS) != Flags)); #endif #ifdef PHOBJ_STRICT_CHECKS if (NT_SUCCESS(status)) { #endif /* Allocate storage for the object. Note that this includes * the object header followed by the object body. */ objectHeader = PhpAllocateObject(ObjectType, ObjectSize, Flags); #ifndef PHOBJ_ALLOCATE_NEVER_NULL if (!objectHeader) status = STATUS_NO_MEMORY; #endif #ifdef PHOBJ_STRICT_CHECKS } #endif #ifndef PHOBJ_ALLOCATE_NEVER_NULL if (!NT_SUCCESS(status)) { if (!(Flags & PHOBJ_RAISE_ON_FAIL)) return status; else PhRaiseStatus(status); } #endif /* Object type statistics. */ _InterlockedIncrement((PLONG)&ObjectType->NumberOfObjects); /* Initialize the object header. */ objectHeader->RefCount = 1; // objectHeader->Flags is initialized by PhpAllocateObject. objectHeader->Size = ObjectSize; objectHeader->Type = ObjectType; REF_STAT_UP(RefObjectsCreated); #ifdef DEBUG { USHORT capturedFrames; capturedFrames = RtlCaptureStackBackTrace(1, 16, objectHeader->StackBackTrace, NULL); memset( &objectHeader->StackBackTrace[capturedFrames], 0, sizeof(objectHeader->StackBackTrace) - capturedFrames * sizeof(PVOID) ); } PhAcquireQueuedLockExclusive(&PhDbgObjectListLock); InsertTailList(&PhDbgObjectListHead, &objectHeader->ObjectListEntry); PhReleaseQueuedLockExclusive(&PhDbgObjectListLock); { PPH_CREATE_OBJECT_HOOK dbgCreateObjectHook; dbgCreateObjectHook = PhDbgCreateObjectHook; if (dbgCreateObjectHook) { dbgCreateObjectHook( PhObjectHeaderToObject(objectHeader), ObjectSize, Flags, ObjectType ); } } #endif /* Pass a pointer to the object body back to the caller. */ *Object = PhObjectHeaderToObject(objectHeader); return status; }
int trace(void **array,int n) { if(n>=63) n=62; return RtlCaptureStackBackTrace(0,n,array,0); }
EASYHOOK_NT_EXPORT LhBarrierCallStackTrace( PVOID* OutMethodArray, ULONG InMaxMethodCount, ULONG* OutMethodCount) { /* Description: Creates a call stack trace and translates all method entries back into their owning modules. Parameters: - OutMethodArray An array receiving the methods on the call stack. - InMaxMethodCount The length of the method array. - OutMethodCount The actual count of methods on the call stack. This will never be greater than 64. Returns: STATUS_NOT_IMPLEMENTED Only supported since Windows XP. */ NTSTATUS NtStatus; PVOID Backup = NULL; if(InMaxMethodCount > 64) THROW(STATUS_INVALID_PARAMETER_2, L"At maximum 64 modules are supported."); if(!IsValidPointer(OutMethodArray, InMaxMethodCount * sizeof(PVOID))) THROW(STATUS_INVALID_PARAMETER_1, L"The given module buffer is invalid."); if(!IsValidPointer(OutMethodCount, sizeof(ULONG))) THROW(STATUS_INVALID_PARAMETER_3, L"Invalid module count storage."); FORCE(LhBarrierBeginStackTrace(&Backup)); #ifndef DRIVER if(RtlCaptureStackBackTrace == NULL) RtlCaptureStackBackTrace = (PROC_RtlCaptureStackBackTrace*)GetProcAddress(hKernel32, "RtlCaptureStackBackTrace"); if(RtlCaptureStackBackTrace == NULL) THROW(STATUS_NOT_IMPLEMENTED, L"This method requires Windows XP or later."); #endif *OutMethodCount = RtlCaptureStackBackTrace(1, 32, OutMethodArray, NULL); RETURN; THROW_OUTRO: FINALLY_OUTRO: { if(Backup != NULL) LhBarrierEndStackTrace(Backup); return NtStatus; } }
void backtrace() { static struct sym_t { HANDLE proc; sym_t() { proc = GetCurrentProcess(); SymSetOptions( SYMOPT_DEFERRED_LOADS | // シンボルを参照する必要があるときまで読み込まない SYMOPT_LOAD_LINES | // 行番号情報を読み込む SYMOPT_UNDNAME // すべてのシンボルを装飾されていない形式で表します ); if(!SymInitialize(proc, 0, true)){ throw exception("error : SymInitialize"); } // cout << "<SymInitialize>" << endl; } ~sym_t() { SymCleanup(proc); // cout << "<SymCleanup>" << endl; } } s_sym; array<void*,8> addr; int count = RtlCaptureStackBackTrace(0, addr.size(), &addr[0], 0); cout << "---- BEGIN BACKTRACE ----" << endl; for(int Li = 1; Li < count; ++Li){ auto p = reinterpret_cast<uintptr_t>(addr[Li]); IMAGEHLP_MODULE module; ::memset(&module, 0, sizeof(module)); module.SizeOfStruct = sizeof(module); if(!SymGetModuleInfo(s_sym.proc, p, &module)){ throw exception("error : SymGetModuleInfo"); } char buffer[sizeof(IMAGEHLP_SYMBOL) + MAX_PATH]; ::memset(buffer, 0, sizeof(buffer)); auto symbol = reinterpret_cast<IMAGEHLP_SYMBOL*>(buffer); symbol->SizeOfStruct = sizeof(*symbol); symbol->MaxNameLength = MAX_PATH; DWORDx disp = 0; if(!SymGetSymFromAddr(s_sym.proc, p, &disp, symbol)){ throw exception("error : SymGetSymFromAddr"); } if(!strcmp(symbol->Name, "__tmainCRTStartup")){ break; } string text = "?"; IMAGEHLP_LINE line; ::memset(&line, 0, sizeof(line)); line.SizeOfStruct = sizeof(line); DWORD disp2 = 0; if(!SymGetLineFromAddr(s_sym.proc, p, &disp2, &line)){ line.FileName = "?"; line.LineNumber = 0; text = "?"; } else { text = getline(line.FileName, line.LineNumber); } cout << Li << " : 0x" << hex << setw(sizeof(uintptr_t) * 2) << setfill('0') << p << " : " << module.ModuleName << " : " << symbol->Name << " : " << line.FileName << "(" << dec << line.LineNumber << ")" << " : " << text.c_str() << endl; } cout << "---- END BACKTRACE ----" << endl << endl; }
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth' // frames have been traced. Populates the CallStack with one entry for each // stack frame traced. // // Note: This function uses a very efficient method to walk the stack from // frame to frame, so it is quite fast. However, unconventional stack frames // (such as those created when frame pointer omission optimization is used) // will not be successfully walked by this function and will cause the // stack trace to terminate prematurely. // // - maxdepth (IN): Maximum number of frames to trace back. // // - framepointer (IN): Frame (base) pointer at which to begin the stack trace. // If NULL, then the stack trace will begin at this function. // // Return Value: // // None. // VOID FastCallStack::getStackTrace (UINT32 maxdepth, const context_t& context) { UINT32 count = 0; UINT_PTR function = context.func; if (function != NULL) { count++; push_back(function); } /*#if defined(_M_IX86) UINT_PTR* framePointer = (UINT_PTR*)context.BPREG; while (count < maxdepth) { if (*framePointer < (UINT_PTR)framePointer) { if (*framePointer == NULL) { // Looks like we reached the end of the stack. break; } else { // Invalid frame pointer. Frame pointer addresses should always // increase as we move up the stack. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } } if (*framePointer & (sizeof(UINT_PTR*) - 1)) { // Invalid frame pointer. Frame pointer addresses should always // be aligned to the size of a pointer. This probably means that // we've encountered a frame that was created by a module built with // frame pointer omission (FPO) optimization turned on. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } if (IsBadReadPtr((UINT*)*framePointer, sizeof(UINT_PTR*))) { // Bogus frame pointer. Again, this probably means that we've // encountered a frame built with FPO optimization. m_status |= CALLSTACK_STATUS_INCOMPLETE; break; } count++; push_back(*(framePointer + 1)); framePointer = (UINT_PTR*)*framePointer; } #elif defined(_M_X64)*/ UINT32 maxframes = min(62, maxdepth + 10); UINT_PTR* myFrames = new UINT_PTR[maxframes]; ZeroMemory(myFrames, sizeof(UINT_PTR) * maxframes); ULONG BackTraceHash; maxframes = RtlCaptureStackBackTrace(0, maxframes, reinterpret_cast<PVOID*>(myFrames), &BackTraceHash); m_hashValue = BackTraceHash; UINT32 startIndex = 0; while (count < maxframes) { if (myFrames[count] == 0) break; if (myFrames[count] == context.fp) startIndex = count; count++; } count = startIndex; while (count < maxframes) { if (myFrames[count] == 0) break; push_back(myFrames[count]); count++; } delete [] myFrames; //#endif }
void PlatformStack::CaptureStackBackTrace(uint64* backTrace, uint32 maxDepth, void* context) { if (backTrace == NULL || maxDepth == 0) { return; } if (context) { CaptureStackTraceHelper(backTrace, maxDepth, (CONTEXT*)context); } else { #if USE_FAST_STACKTRACE //if (!GMaxCallstackDepthInitialized) //{ // DetermineMaxCallstackDepth(); //} PVOID winBackTrace[MAX_CALLSTACK_DEPTH]; uint16 numFrames = RtlCaptureStackBackTrace(0, maxDepth, winBackTrace, NULL); for (uint16 frameIndex = 0; frameIndex < numFrames; ++frameIndex) { backTrace[frameIndex] = (uint64)winBackTrace[frameIndex]; } while (numFrames < maxDepth) { backTrace[numFrames++] = 0; } #elif USE_SLOW_STACKTRACE InitSysStack(); CONTEXT helperContext; RtlCaptureContext(&helperContext); CaptureStackTraceHelper(backTrace, maxDepth, &helperContext); #elif _WIN64 // Raise an exception so CaptureStackBackTraceHelper has access to context record. __try { RaiseException(0, // Application-defined exception code. 0, // Zero indicates continuable exception. 0, // Number of arguments in args array (ignored if args is NULL) NULL); // Array of arguments } // Capture the back trace. __except (CaptureStackTraceHelper(backTrace, maxDepth, (GetExceptionInformation())->ContextRecord)) { } #else // Use a bit of inline assembly to capture the information relevant to stack walking which is // basically EIP and EBP. CONTEXT HelperContext; memset(&HelperContext, 0, sizeof(CONTEXT)); HelperContext.ContextFlags = CONTEXT_FULL; // Use a fake function call to pop the return address and retrieve EIP. __asm { call FakeFunctionCall FakeFunctionCall : pop eax mov HelperContext.Eip, eax mov HelperContext.Ebp, ebp mov HelperContext.Esp, esp } // Capture the back trace. CaptureStackTraceHelper(backTrace, maxDepth, &HelperContext); #endif } }
int callstack( int skip_frames, void** addresses, int num_addresses ) { return RtlCaptureStackBackTrace( skip_frames + 1, num_addresses, addresses, 0 ); }
LONG __cdecl WriteRefTraceLogEx( IN PTRACE_LOG Log, IN LONG NewRefCount, IN CONST VOID * Context, IN CONST VOID * Context1, // optional extra context IN CONST VOID * Context2, // optional extra context IN CONST VOID * Context3 // optional extra context ) /*++ Routine Description: Writes a new "extended" entry to the specified ref count trace log. The entry written contains the updated reference count, stack backtrace leading up to the current caller and extra context information. Arguments: Log - The log to write to. NewRefCount - The updated reference count. Context - An uninterpreted context to associate with the log entry. Context1 - An uninterpreted context to associate with the log entry. Context2 - An uninterpreted context to associate with the log entry. Context3 - An uninterpreted context to associate with the log entry. NOTE Context1/2/3 are "optional" in that the caller may suppress debug display of these values by passing REF_TRACE_EMPTY_CONTEXT for each of them. Return Value: Index of entry in log. --*/ { REF_TRACE_LOG_ENTRY entry; ULONG hash; DWORD cStackFramesSkipped; // // Initialize the entry. // RtlZeroMemory( &entry, sizeof(entry) ); // // Set log entry members. // entry.NewRefCount = NewRefCount; entry.Context = Context; entry.Thread = GetCurrentThreadId(); entry.Context1 = Context1; entry.Context2 = Context2; entry.Context3 = Context3; // // Capture the stack backtrace. Normally, we skip two stack frames: // one for this routine, and one for RtlCaptureBacktrace() itself. // For non-Ex callers who come in via WriteRefTraceLog, // we skip three stack frames. // if ( entry.Context1 == REF_TRACE_EMPTY_CONTEXT && entry.Context2 == REF_TRACE_EMPTY_CONTEXT && entry.Context3 == REF_TRACE_EMPTY_CONTEXT ) { cStackFramesSkipped = 2; } else { cStackFramesSkipped = 1; } RtlCaptureStackBackTrace( cStackFramesSkipped, REF_TRACE_LOG_STACK_DEPTH, entry.Stack, &hash ); // // Write it to the log. // return WriteTraceLog( Log, &entry ); } // WriteRefTraceLogEx
void* winpr_backtrace(DWORD size) { #if defined(HAVE_EXECINFO_H) t_execinfo* data = calloc(1, sizeof(t_execinfo)); if (!data) return NULL; data->buffer = calloc(size, sizeof(void*)); if (!data->buffer) { free(data); return NULL; } data->max = size; data->used = backtrace(data->buffer, size); return data; #elif defined(ANDROID) t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data)); if (!data) return NULL; data->buffer = calloc(size, sizeof(backtrace_frame_t)); if (!data->buffer) { free(data); return NULL; } pthread_once(&initialized, load_library); data->max = size; data->used = fkt->unwind_backtrace(data->buffer, 0, size); return data; #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP) HANDLE process = GetCurrentProcess(); t_win_stack* data = calloc(1, sizeof(t_win_stack)); if (!data) return NULL; data->max = size; data->stack = calloc(data->max, sizeof(PVOID)); if (!data->stack) { free(data); return NULL; } SymInitialize(process, NULL, TRUE); data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL); return data; #else LOGF(support_msg); return NULL; #endif }
USHORT RtlLogStackBackTrace( VOID ) /*++ Routine Description: This routine will capture the current stacktrace (skipping the present function) and will save it in the global (per process) stack trace database. It should be noted that we do not save duplicate traces. Arguments: None. Return Value: Index of the stack trace saved. The index can be used by tools to access quickly the trace data. This is the reason at the end of the database we save downwards a list of pointers to trace entries. This index can be used to find this pointer in constant time. A zero index will be returned for error conditions (e.g. stack trace database not initialized). Environment: User mode. --*/ { PSTACK_TRACE_DATABASE DataBase; RTL_STACK_TRACE_ENTRY StackTrace; PRTL_STACK_TRACE_ENTRY p, *pp; ULONG Hash, RequestedSize, DepthSize; if (RtlpStackTraceDataBase == NULL) { return 0; } Hash = 0; // // Capture stack trace. The try/except was useful // in the old days when the function did not validate // the stack frame chain. We keep it just ot be defensive. // try { StackTrace.Depth = RtlCaptureStackBackTrace( 1, MAX_STACK_DEPTH, StackTrace.BackTrace, &Hash ); } except(EXCEPTION_EXECUTE_HANDLER) { StackTrace.Depth = 0; } if (StackTrace.Depth == 0) { return 0; } // // Lock the global per-process stack trace database. // DataBase = RtlpAcquireStackTraceDataBase(); if (DataBase == NULL) { return( 0 ); } DataBase->NumberOfEntriesLookedUp++; try { // // We will try to find out if the trace has been saved in the past. // We find the right hash chain and then traverse it. // DepthSize = StackTrace.Depth * sizeof( StackTrace.BackTrace[ 0 ] ); pp = &DataBase->Buckets[ Hash % DataBase->NumberOfBuckets ]; while (p = *pp) { if (p->Depth == StackTrace.Depth && RtlCompareMemory( &p->BackTrace[ 0 ], &StackTrace.BackTrace[ 0 ], DepthSize ) == DepthSize ) { break; } else { pp = &p->HashChain; } } if (p == NULL) { // // We did not find the stack trace. We will extend the database // and save the new trace. // RequestedSize = FIELD_OFFSET( RTL_STACK_TRACE_ENTRY, BackTrace ) + DepthSize; p = RtlpExtendStackTraceDataBase( &StackTrace, RequestedSize ); // // If we managed to stack the trace we need to link it as the last // element in the proper hash chain. // if (p != NULL) { *pp = p; } } } except(EXCEPTION_EXECUTE_HANDLER) { // // bugbug (silviuc): We should not be here. Right? // p = NULL; } // // Release global trace db. // RtlpReleaseStackTraceDataBase(); if (p != NULL) { p->TraceCount++; return( p->Index ); } else { return( 0 ); } return 0; }
int appCaptureStackTrace(address_t* buffer, int maxDepth, int framesToSkip) { return RtlCaptureStackBackTrace(framesToSkip, maxDepth, (void**)buffer, NULL); }