您的位置:首页 > 其它

Visual leak Detact 如何获取当前程序的堆栈

2013-05-11 15:54 302 查看
1、 // Get the pointer to this thread's thread local storage structure.

tls_t* tls = (tls_t*)TlsGetValue(m_tlsIndex);

Win32

  方法一:每个线程创建时系统给它分配一个LPVOID指针的数组(叫做TLS数组),这个数组从C编程角度是隐藏着的不能直接访问,需要通过一些C API函数调用访问。首先定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量。一个线程使用TLS时,第一步在线程内调用TlsAlloc()函数,为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量:

  global_dwTLSindex=TLSAlloc();

  注意,此步之后,当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制,所以在如此大费周折。

  第二步,为当前线程动态分配一块内存区域(使用LocalAlloc()函数调用),然后把指向这块内存区域的指针放入TLS数组相应的槽中(使用TlsValue()函数调用)。

  第三步,在当前线程的任何函数内,都可以通过TLS数组的索引变量,使用TlsGetValue()函数得到上一步的那块内存区域的指针,然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。

  最后,如果不再需要上述线程局部静态变量,要动态释放掉这块内存区域(使用LocalFree()函数),然后从TLS数组中放弃对应的槽(使用TlsFree()函数)。

2、如何获取具体的堆栈指针信息

VOID FastCallStack::getStackTrace (UINT32 maxdepth, const context_t& context)

{

UINT32 count = 0;

UINT_PTR* framePointer = context.fp;

#if defined(_M_IX86)

while (count < maxdepth) {

if (*framePointer < (UINT_PTR)framePointer) {

if (*framePointer == NULL) {

// 到达栈底

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;

}

}
3、dump具体的堆栈,格式化为我们所能读懂的,包括源文件的行号,函数信息。

// dump - Dumps a nicely formatted rendition of the CallStack, including

// symbolic information (function names and line numbers) if available.

void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const

{

// The stack was dumped already

if (m_resolved)

{

dumpResolved();

return;

}

if (m_status & CALLSTACK_STATUS_INCOMPLETE) {

// This call stack appears to be incomplete. Using StackWalk64 may be

// more reliable.


Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n"

L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n"

L" complete stack trace.\n");

}

IMAGEHLP_LINE64 sourceInfo = { 0 };

sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 };

WCHAR lowerCaseName [MAX_PATH];

WCHAR callingModuleName [MAX_PATH];

const size_t max_size = MAXREPORTLENGTH + 1;

// Iterate through each frame in the call stack.

for (UINT32 frame = start_frame; frame < m_size; frame++)

{

// Try to get the source file and line number associated with

// this program counter address.


SIZE_T programCounter = (*this)[frame];

g_symbolLock.Enter();

BOOL foundline = FALSE;

DWORD displacement = 0;

DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId());

foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo);

if (foundline && !showInternalFrames) {

wcscpy_s(lowerCaseName, sourceInfo.FileName);

_wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1);

if (isInternalModule(lowerCaseName)) {

// Don't show frames in files internal to the heap.

g_symbolLock.Leave();

continue;

}

}

// Initialize structures passed to the symbol handler.

SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer;

functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO);

functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH;

// Try to get the name of the function containing this program

// counter address.

DWORD64 displacement64 = 0;

LPWSTR functionName;

DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId());

if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) {

functionName = functionInfo->Name;

}

else {

// GetFormattedMessage( GetLastError() );

functionName = L"(Function name unavailable)";

displacement64 = 0;

}

g_symbolLock.Leave();

HMODULE hCallingModule = GetCallingModule(programCounter);

LPWSTR moduleName = L"(Module name unavailable)";

if (hCallingModule &&

GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0)

{

moduleName = wcsrchr(callingModuleName, L'\\');

if (moduleName == NULL)

moduleName = wcsrchr(callingModuleName, L'/');

if (moduleName != NULL)

moduleName++;

else

moduleName = callingModuleName;

}

// Use static here to increase performance, and avoid heap allocs. Hopefully this won't

// prove to be an issue in thread safety. If it does, it will have to be simply non-static.


static WCHAR stack_line[MAXREPORTLENGTH + 1] = L"";

int NumChars = -1;

// Display the current stack frame's information.

if (foundline) {

if (displacement == 0)

NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s\n",

sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName);

else

NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s + 0x%X bytes\n",

sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement);

}

else {

if (displacement64 == 0)

NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s\n",

programCounter, moduleName, functionName);

else

NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n",

programCounter, moduleName, functionName, (DWORD)displacement64);

}

Print(stack_line);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: