Use dbghelp to obtain the debugging methodology (essence) under the call stack-release)

Source: Internet
Author: User
Use dbghelp to obtain the debugging methodology under the call Stack -- Release

Author: Kevin lynx

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 log files, which are analyzed based on log files.
The running status when the program crashes. We can capture program errors through Seh, and then output some useful information as the information for our analysis of errors. Generally we need
The output information includes system information, CPU register information, stack information, and call stack. The call stack is the most useful part. It can help us locate it directly.
To the location 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
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
We can use inline assembly to obtain the content, but considering compatibility, inline assembly is not a good solution. We can use Microsoft's dbghelp
To obtain the 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 instructions of the current program.
Address. 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
The content of the EIP register, which cannot be accessed by the Software.) You can also use getthreadcontext to obtain the CPU registers in the current running state of the current thread.
Content. 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, as with the getthreadcontext function of msdn
The function may obtain the error 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, which contains
Context pointer, that is, to achieve the target, you can use the stackwalk function.

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. This involves the symfromaddr function, which can be returned based on an address.
Symbol name (function name ). 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 pai_filter (lpexception_pointers lpep)
{
/// Init dbghelp. dll
If (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 );
}
_ Effect (effec_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.cnblogs.com/protalfox/articles/84723.html
Http://www.codeproject.com/KB/debug/XCrashReportPt1.aspx
Http://www.codeproject.com/KB/applications/visualleakdetector.aspx

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.