This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to implement a function which will give the address of the calling function during runtime.

I am working on a complex project written in C for 8051 arhitecture with Keil C. And unfortunately no real debugger. There are many functions called from various c files. Some times hundereds of different c file. I want to implement a function which will give me the address of the calling function during runtime. Is there a way to read the call stack to exctract the callig function address? If a can get the adress a can check it from .m51 file and can understand which function call is active.

func1(void)
{ func_test();
};

func2(void)
{ func_test();
};

func3(void)
{ func_test();
};

func_test(void)
{ int get_call_func_address;

get_call_func_address = ???????; printf("Calling function adress is %d", get_call_func_address);

//Do other things...

}

main()
{ func1(); func2(); func3();
}

Best regards
Saltuk Alakus

Parents
  • Some things to consider.
    First consider this: what happens when a function is called?
    Second how can that be used to identify the calling function?
    Third consider what else you need to display.

    I believe a good understanding of the underlying architecture is necessary to do what you want.

    Here are some useful hints
    The stack (IE call stack) and everything about it and how to find it's bottom are needed.
    Your program model will also affects how the stack is used.
    You need to understand the format of the .M51 file and what for and where to look in it.

    I modified my STARTUP.A51 adding this information to it:

                    RSEG    ?STACK
                                    PUBLIC  __stack
    __stack:         DS      1
    


    The label __stack and PUBLIC __stack are the only additions needed.
    __stack should now be a constant available to your program.

    I choose __stack because it's odd enough looking someone won't assume that it is a variable. (and commented the heck out of where it was used).

    Next You need the REAL stack in your called function (func_test) and you need to be very careful how you use the stack (be sure you don't assign anything to the stack in other words). Be sure to have your processors <regXXX.h> file included for this to work (or it won't compile). The data on the stack is in little endian format. IE the MSB is at the top and LSB is beneath it.
    Also you should NOT use decimal numbers since the M51 file uses HEX numbers for the addresses. You'll be quite tired converting if you use decimals.

    unsigned char data *call_stack;
    
    call_stack = SP; // get the stack pointer
    printf("Call Stack addresses\n");
    do
    {
      printf("%02bX", *call_stack);
      call_stack--;
      printf("%02bX\n", *call_stack);
      call_stack--;
    }
    // if we haven't reached the bottom of the __stack
    // __stack is the constant start of the stack loaded
    // in the startup code see STARTUP.A51
    while(call_stack > __stack);
    printf("end of call stack\n");
    


    This will give you a complete list of the nesting of the function calls all the way to main from top to bottom (IE last function call to main).
    There is a reason you need this. Namely sometimes the Keil compiler changes a CALL to a JMP instruction. This is something you will miss completely if you just look at the prior address.

    Next this does not give you the calling address it gives you the address of the next instruction. So you can't assume the address you see is the line of code, it is the NEXT instruction. You will have to examine your addresses carefully in the M51 file (and sometimes this is quite tricky). Also the Keil compiler on ocassion does use the stack for pushing temp variables in certain situations, there is no easy way around this situation unfortunately.

    This method works as I've recently used it. I make no claim as to the fitness or safety the code is. IE it's as is and for your aggrandizement only. It is extremely dangerous to do anything with the stack, I don't recommend you do anything with SP, other than to get a copy (as the above code does).

    Also note this is not identical to the original code for various reasons not the least of which is clarity.

    Stephen

Reply
  • Some things to consider.
    First consider this: what happens when a function is called?
    Second how can that be used to identify the calling function?
    Third consider what else you need to display.

    I believe a good understanding of the underlying architecture is necessary to do what you want.

    Here are some useful hints
    The stack (IE call stack) and everything about it and how to find it's bottom are needed.
    Your program model will also affects how the stack is used.
    You need to understand the format of the .M51 file and what for and where to look in it.

    I modified my STARTUP.A51 adding this information to it:

                    RSEG    ?STACK
                                    PUBLIC  __stack
    __stack:         DS      1
    


    The label __stack and PUBLIC __stack are the only additions needed.
    __stack should now be a constant available to your program.

    I choose __stack because it's odd enough looking someone won't assume that it is a variable. (and commented the heck out of where it was used).

    Next You need the REAL stack in your called function (func_test) and you need to be very careful how you use the stack (be sure you don't assign anything to the stack in other words). Be sure to have your processors <regXXX.h> file included for this to work (or it won't compile). The data on the stack is in little endian format. IE the MSB is at the top and LSB is beneath it.
    Also you should NOT use decimal numbers since the M51 file uses HEX numbers for the addresses. You'll be quite tired converting if you use decimals.

    unsigned char data *call_stack;
    
    call_stack = SP; // get the stack pointer
    printf("Call Stack addresses\n");
    do
    {
      printf("%02bX", *call_stack);
      call_stack--;
      printf("%02bX\n", *call_stack);
      call_stack--;
    }
    // if we haven't reached the bottom of the __stack
    // __stack is the constant start of the stack loaded
    // in the startup code see STARTUP.A51
    while(call_stack > __stack);
    printf("end of call stack\n");
    


    This will give you a complete list of the nesting of the function calls all the way to main from top to bottom (IE last function call to main).
    There is a reason you need this. Namely sometimes the Keil compiler changes a CALL to a JMP instruction. This is something you will miss completely if you just look at the prior address.

    Next this does not give you the calling address it gives you the address of the next instruction. So you can't assume the address you see is the line of code, it is the NEXT instruction. You will have to examine your addresses carefully in the M51 file (and sometimes this is quite tricky). Also the Keil compiler on ocassion does use the stack for pushing temp variables in certain situations, there is no easy way around this situation unfortunately.

    This method works as I've recently used it. I make no claim as to the fitness or safety the code is. IE it's as is and for your aggrandizement only. It is extremely dangerous to do anything with the stack, I don't recommend you do anything with SP, other than to get a copy (as the above code does).

    Also note this is not identical to the original code for various reasons not the least of which is clarity.

    Stephen

Children
No data