Manually fetch the call stack in C + +

Source: Internet
Author: User

When the core of our program is dropped, it is very advantageous to locate the problem if the function call stack gets to the core. You can use the SEH mechanism under Windows, and use the Coredump file with GDB under Linux.

However, sometimes the stack is destroyed due to some errors, and the call stack is not taken.

Some basic preparatory knowledge this article is no longer detailed, you can refer to the following articles:

    • Analysis of acquiring principle of function call stack
    • Registers, function calls, and stack frames

Information you need to know:

    • The corresponding instruction of a function call call is essentially pressing the address of the next instruction into the stack and then jumping to the destination function address
    • The function return instruction ret is to take an address out of the stack and then jump to that address
    • The EBP register always points to the position in the stack where the information about the current executing function (local variables) is located, and ESP always points to the top of the stack
    • Each function entry will hold the caller's EBP value, and the EBP value will be reset at the exit to enable the field preservation of the function call and on-site recovery.
    • The 64-bit machine adds a lot of registers so that the parameters of the function call can be passed through the register most of the time, while the register name changes, for example, EBP becomes RBP

A description of the stack in the function call is available:

To map the code together:

void G () {    int *p = 0;    Long a = 0x1234;    printf ("%p%x\n", &a, a);    printf ("%p%x\n", &p, p);    f ();    *p = 1;} void B (int argc, char **argv) {    printf ("%p%p\n", &ARGC, &ARGV);    g ();} int main (int argc, char **argv) {    B (argc, argv);    return 0;}

At the function g() break point, look at the contents of the stack (64-bit machine):

(GDB) p $RBP $ = (void *) 0x7fffffffe370 (GDB) p &p$3 = (int * *) 0x7fffffffe368 (GDB) p $rsp $4 = (void *) 0x7fffffffe360 (gdb) X/8ag $rbp -160x7fffffffe360:0x1234  0x00x7fffffffe370:0x7fffffffe390  0x400631 <b (int, char**) +43 >0x7fffffffe380:0x7fffffffe498  0x1a561cbc00x7fffffffe390:0x7fffffffe3b0  0x40064f <main (int, Char * *) +27>

The corresponding stack diagram:

You can look at 0x400631 <b(int, char**)+43> the code in the example and in 0x40064f <main(int, char**)+27> :

(GDB) Disassemble 0x400631 ... 0x0000000000400627 <b (int, char**) +33>: callq  0x400468 <[email protected]>0x000000000040062c <b ( int, char**) +38>: Callq  0x4005ae <g () >0x0000000000400631 <b (int, char**) +43>: Leaveq                           # Call's next instruction ... (GDB) Disassemble 0x40064f ... 0x000000000040063f <main (int, char**) +11>:      mov    %rsi,-0x10 (%RBP) 0x0000000000400643 <main (int, Char * *) +15>:      mov    -0x10 (%RBP),%rsi0x0000000000400647 <main (int, char**) +19>      : mov    -0x4 (%RBP) ,%edi0x000000000040064a <main (int, char**) +22>:      callq  0x400606 <b (int, char**) > 0x000000000040064f <main (int, char**) +27>:      mov    $0x0,%eax         # Call's next instruction ...

Incidentally, for each function entry and exit, the corresponding setting RBP code is:

(GDB) disassemble g ... 0x00000000004005ae <g () +0>:     push   %RBP               # Saves the caller's RBP to the stack 0x00000000004005af <g () +1>:     mov    %RSP,%RBP          # Set your own RBP ... 0x0000000000400603 <g () +85>:    leaveq                    # equivalent to: Movq%rbp,%rsp                                                          #         POPQ%rbp0x0000000000400604 <g ( ) +86>:    retq                      

As seen above, the RBP of all functions in the call stack can be found through the current RSP or RBP, and the function address can be found RBP . Because, at any time, the RBP point to the stack position is the RBP of the previous function, and at any time the previous position in the RBP stack is the function return address.

Thus we can build ourselves an example that will result in gdb not getting the call stack:

void F () {    long *p = 0;    p = (long*) (&p + 1); Get G () RBP    *p = 0;  Destroy G () rbp}void g () {    int *p = 0;    Long a = 0x1234;    printf ("%p%x\n", &a, a);    printf ("%p%x\n", &p, p);    f ();    *p = 1; Writing 0 addresses results in one core}void b (int argc, char **argv) {    printf ("%p%p\n", &ARGC, &ARGV);    g ();} int main (int argc, char **argv) {    B (argc, argv);    return 0;}

Run the program using GDB:

Program received signal SIGSEGV, segmentation fault.g () at ebp.c:3737          *p = 1; (GDB) Btcannot access memory at address 0x8 (GDB) p $RBP $ = (void *) 0x0

btUnable to get the stack, in the function g() RBP is rewritten as 0,gdb from 0 offset an address length that is 0x8, try to get the address of the function from the 0x8 memory location, and then prompt Cannot access memory at address 0x8 .

RBP There is a problem, we can get the call stack manually via RSP. because RSP is not compromised, getting the call stack via RSP requires offsetting some of the space occupied by local variables:

(GDB) p $RSP $ = (void *) 0x7fffffffe360 (gdb) x/8ag $rsp +16             # g () Local variables accounted for 16 bytes 0x7fffffffe370:0x7fffffffe390  0x400631 <b (int, char**) +43>0x7fffffffe380:0x7fffffffe498  0x1a561cbc00x7fffffffe390:0x7fffffffe3b0  0x40064f <main (int, char**) +27>0x7fffffffe3a0:0x7fffffffe498  0x100000000

Based on the above, you can manually find the call stack:

G () 0x400631 <b (int, char**) +43>0x40064f <main (int, char**) +27>

The above example essentially destroys the stack, and only destroys the saved RBP. In the real situation, the stack can be destroyed more, which can lead to manual positioning is also more difficult.

A broken stack can also cause more problems, such as overwriting a function return address, which can cause RIP errors, such as a stack imbalance. There are also many reasons for the stack being destroyed, such as a partial array out of bounds, an object on the Delete/free stack, and so on.

Omit-frame-pointer

It is relatively easy to get the call stack using RBP. But now the compiler can set it up without using RBP (GCC uses-fomit-frame-pointer,msvc with/oy), and not setting its RBP for functions means you can save several instructions. Inside the function, the offset of the RSP is used to locate the local variables, including the local variables in the nested scope, even if the program is actually running without entering the scope.

For example:

void F2 () {    int a = 0x1234;    if (a > 0) {        int b = 0xFF;        b = A;    }}

The generated code used in GCC -fomit-frame-pointer is:

(GDB) disassemble f2dump of assembler code for function F2:0x00000000004004a5 <f2+0>:      movl   $0x1234,-0x8 (% RSP)    # int a = 0X12340X00000000004004AD <f2+8>:      cmpl   $0x0,-0x8 (%RSP)       0x00000000004004b2 <f2 +13>:     jle    0x4004c4 <f2+31>      0x00000000004004b4 <f2+15>:     movl   $0xff,-0x4 (%RSP)      # int b = 0XFF0X00000000004004BC <f2+23>:     mov    -0x8 (%RSP),%eax0x00000000004004c0 <f2+27>:     mov    %eax,-0x4 (%RSP) 0x00000000004004c4 <f2+31>:     retq

You can find f2() RBP instructions such as no operations.

Original address: http://codemacro.com/2014/09/02/stack-frame/
Written by Kevin Lynx posted athttp://codemacro.com

Manually fetch the call stack in C + +

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.