Use dbghelp to obtain the debugging methodology under Call Stack-release

Source: Internet
Author: User

When the software is released to the user as the release mode, it is difficult to find the cause when the program crashes. A common method is to output a LOG file and analyze the running status of the program when it crashes. We can capture program errors through SEH, and then output some useful information as the information for our analysis of errors. Generally, the output information includes the system information, CPU register information, stack information, and call stack information. The call stack is the most useful part, which can help us locate where the program crashes (where it crashes ). (Codeproject's common opening remarks on this topic
== #)

To obtain the call stack (the so-called call stack), you need to view the content of the (unwind) stack. We cocould conceivably attempt to unwind the stack ourselves using inline assembly. But stack frames can be organized in different ways, depending on compiler optimizations and calling conventions,
So it cocould become complicated to do it that way. (from the vld Documentation)

To obtain the stack content, we can use inline assembly to obtain the content, but considering compatibility, inline assembly is not a good solution. We can use stack1_64 in dbghelp of Microsoft to obtain stack content.

Stack1_64 declaration:
BOOL stack1_64 (
DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);

For more information about each parameter, see MSDN. The ContextRecord parameter specifies the content of each register of the CPU.

StackFrame specifies the stack frame content. I don't know what stack frame is. (=) The stackwritable 64 function requires you to specify the address of the current frame and the instruction address of the current program. Both information is filled in ContextRecord and then passed to the stackhistory 64 function.

So how can we get the current stack frame address and the current program instruction address?

As mentioned above, you can use inline assembly. (For the program instruction address, because you want to obtain the content of the EIP register, and this register cannot be accessed by the software) You can also use GetThreadContext to obtain the content of each CPU register in the current running state of the current thread at one time. In addition, the current frame address is placed in the EBP register, and the current program instruction address is placed in the EIP register. However, like MSDN's description of the GetThreadContext function, this function may obtain the wrong register content (You
Cannot get a valid context for a running thread ).

Another way to get Context (including EBP and EIP) is to use SEH (structured exception handling) and get it using GetExceptionInformation in _ blocks T.

GetExceptionInformation returns an LPEXCEPTION_POINTERS pointer pointing to a prediction_pointers structure. This structure contains a Context pointer to achieve the target. StackWalk function can be used.

In addition, you can directly use the StackWalk function, and the StackWalk is define as stackbench 64 (related to windows ).

After unwind stack, You can further obtain the content of a stack frame, such as the function name. The SymFromAddr function is involved here. This function can return a symbolic name (function name) based on an address ). There is also an interesting function: SymGetLineFromAddr, which can obtain the source code file name and row number corresponding to the function.

Of course, all of this depends on the program database file (pdb) generated by vc and the dbghelp. dll that provides the preceding API functions.

Refer to a simple piece of code:

///#include <windows.h>#include <stdio.h>#include <dbghelp.h>#pragma comment( lib, "dbghelp.lib" )void dump_callstack( CONTEXT *context ){STACKFRAME sf;memset( &sf, 0, sizeof( STACKFRAME ) );sf.AddrPC.Offset = context->Eip;sf.AddrPC.Mode = AddrModeFlat;sf.AddrStack.Offset = context->Esp;sf.AddrStack.Mode = AddrModeFlat;sf.AddrFrame.Offset = context->Ebp;sf.AddrFrame.Mode = AddrModeFlat;DWORD machineType = IMAGE_FILE_MACHINE_I386;HANDLE hProcess = GetCurrentProcess();HANDLE hThread = GetCurrentThread();for( ; ; ){if( !StackWalk(machineType, hProcess, hThread, &sf, context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) ){break;}if( sf.AddrFrame.Offset == 0 ){break;}BYTE symbolBuffer[ sizeof( SYMBOL_INFO ) + 1024 ];PSYMBOL_INFO pSymbol = ( PSYMBOL_INFO ) symbolBuffer;pSymbol->SizeOfStruct = sizeof( symbolBuffer );pSymbol->MaxNameLen = 1024;DWORD64 symDisplacement = 0;if( SymFromAddr( hProcess, sf.AddrPC.Offset, 0, pSymbol ) ){printf( "Function : %s\n", pSymbol->Name );}else{printf( "SymFromAdd failed!\n" );}IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };DWORD dwLineDisplacement;if( SymGetLineFromAddr( hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo ) ){printf( "[Source File : %s]\n", lineInfo.FileName ); printf( "[Source Line : %u]\n", lineInfo.LineNumber ); }else{printf( "SymGetLineFromAddr failed!\n" );}}}DWORD excep_filter( LPEXCEPTION_POINTERS lpEP ){/**//// init dbghelp.dllif( SymInitialize( GetCurrentProcess(), NULL, TRUE ) ){printf( "Init dbghelp ok.\n" );}dump_callstack( lpEP->ContextRecord );if( SymCleanup( GetCurrentProcess() ) ){printf( "Cleanup dbghelp ok.\n" );}return EXCEPTION_EXECUTE_HANDLER;}void func1( int i ){int *p = 0;*p = i;}void func2( int i ){func1( i - 1 );}void func3( int i ){func2( i - 1 );}void test( int i ){func3( i - 1 );}int main(){__try{test( 10 );}__except( excep_filter( GetExceptionInformation() ) ){printf( "Some exception occures.\n" );}return 0;}

The above code needs to be optimized in release mode. Otherwise, the call stack is incorrectly displayed (some functions are removed ?), The pdb file is also required.

References:
Http://www.codeproject.com/KB/threads/StackWalker.aspx
Http://www.codeproject.com/KB/debug/XCrashReportPt1.aspx

Http://www.codeproject.com/KB/applications/visualleakdetector.aspx

Http://www.cnblogs.com/protalfox/articles/84723.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.