Captain Trojan
Captain Trojan

Reputation: 2921

Can you determine stack depth in C?

I was wondering if there is a function in C (let's dub it int get_stack_depth()), which returns the amount of functions currently being executed on the stack. For example:

int foo(){
    return get_stack_depth();
}

int bar2(){
    return get_stack_depth();
}

int bar1(){
    return bar2();
}

int bar(){
    return bar1();
}

int main(){
    get_stack_depth();      // = 0
    foo();                  // = 1
    bar();                  // = 3
    return 0;
}

I would like to use it for debugging info, where each printf would contain get_stack_depth() indents to increase readability. If this is compiler dependent, or anything-else dependent, I take all the constraints; right now I wonder whether this is supported at least somewhere.

EDIT: The answer at the suggested duplicate didn't help me at all, as the accepted answer here suggests, you cannot determine how many functions are on the stack based purely upon the size of the stack; the information is simply not there.

Upvotes: 3

Views: 2522

Answers (2)

yosef
yosef

Reputation: 134

Have you tried using backtrace()? for example:

#include <execinfo.h>
unsighed int getDepth(){
    const unsigned int max_depth = 200;
    void* buffer[max_depth];
    return backtrace(buffer, max_depth)-5;
}

The -5 is there because there are some functions above main (added by the libc) that I want to ignore. However, if you want to calculate that automatically, change my function to

int get_stack_depth(int set_caller_as_root){
    static int root_depth = 0;

    if (set_caller_as_root){
        root_depth = get_stack_depth(0) - 1;
    }

    const int max_depth = 200;
    void* buffer[max_depth];
    return backtrace(buffer, max_depth) - root_depth;
}

and update your code to

int foo(){
    return get_stack_depth(0);
}

int bar2(){
    return get_stack_depth(0);
}

int bar1(){
    return bar2();
}

int bar(){
    return bar1();
}

int main(){
    printf("%d\n", get_stack_depth(1));     // = 0
    printf("%d\n", foo());                  // = 1
    printf("%d\n", bar());                  // = 3
    return 0;
}

which yields the correct, expected results.

Note that execinfo.h is not installed on windows 10 by default (it is on linux).

Upvotes: 2

Michael Jarrett
Michael Jarrett

Reputation: 425

The exact mechanics of the stack in C are implementation-specific, so there is no single, correct, standard way to find the depth of the stack. There are some methods to simulate this behavior, though.

  1. Use a counter. Define a global unsigned depth, and in each function in which you care about the depth of the stack, inject depth++ at the beginning and depth-- at the end. This is obviously the more tedious method, and it's prone to a lot of frustrating issues if an increment or decrement is left off.

  2. Check the stack pointer. On x86 systems (virtually every desktop & laptop device), the stack grows downward, meaning that entering a function call will decrease the value of the stack pointer. In many cases (but not all, e.g. when optimization is enabled) the stack pointer register, %rsp, points to the "top" of the current function's stack frame. A rather hacky way to fetch this value is to assign it to a variable: register uint64_t rsp asm ("rsp");. The lower the value, the greater the depth on the stack.

    Unfortunately, the size of the decrement between function calls depends on how large the stack frame for that function is—if one function declares a large array as a local variable, then the stack pointer will be much lower for functions it calls, since more space is consumed by the array.

Ultimately the only reliable way I know of to find an accurate backtrace of function calls is to run the program in a debugger such as gdb and issue the backtrace command, which will print the current call stack. This kind of support just doesn't seem to be available to the program when it is run independent of any debugger.

Upvotes: 3

Related Questions