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
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
I think you need to explain why you think you need to do this?
"If I can get the adress I can check it from .m51 file and can understand which function call is active."
So you're talking about a debugging aid?
So you should probably be looking into a uVision debug function, rather than trying to do this in your embedded code? See: http://www.keil.com/support/man/docs/uv3/uv3_debug_functions.htm
Again, if you explained what you're actually trying to achieve, then people would be able to provide appropriate suggestions...
Hello,
Simply bacause I have to debug the code on the running hardware. But there is no hardware debugger for my platform.I can only debug by simple printf or putstring to display some simple debug message.
Running code on PC is not appropriate. Bacause there are harware dependent code areas and simulating on pc is not possible.
Bear in mind that this is likely to have a serious impact on performance!!
You could try a couple of debug trace macros; eg,
#define ENTER(fn) printf( fn )
and
#define EXIT(fn) printf( fn )
thus:
whatever my_func( whatever ) { ENTER( "my_func" ); : : // your code here : : EXIT( "my_func" ); }
I think this macro will inform when the function is called but who calls the function is still not known.
Saltuk, what you are trying to do is something extraordinary: you want to be able to log just about any possible call tree in your program. The point is that this is not required if your software is organized properly: for example, if you have state machines in your program, you can simplify your requirement significantly because knowing the state of the state machine and the signal that it received, yields knowledge of the executed function! what you want to do is going to have, even if it works, such a huge impact on performance that it might distort the value of the data your acquire itself!
one more comment: I also used to work with such huge projects. I never needed this kind of logging due to: * proper documentation * encapsulation * clear protocols between modules
Printing a string for each enter/leave is too expensive for most applications.
A slightly cheaper solution that is sometimes possible is to add a software stack with pointers to function names. This stack of function names can then be printed when needed. The bad part is that a number of functions may have multiple exit points making it very easy to create leaks, where the function name stack doesn't gets popped at all times.
One partial solution is to use a ring-buffer instead of a stack and dump a limited number of entries - unless recursive calls are used, any duplicated function names in the dump would represent a function that sometimes fails to pop its information before returning.
For max flexibility, the ring buffer could store one or two integers together with the string pointer, allowing important state information to be queued also.
This solution consumes resonable amounts of processing power, but for a C51 processor, the stack/ring buffer may consume too much RAM.
Per, Why "13Per Westermark" and not "Per Westermark" ?
Because I sometime start to write before the page has loaded fully, and guess which field that always have the focus on load?
All it takes is the phone to call or something and I will not notice this. All following posts will then use an incorrect name until I notice it and corrects it.
It is a bit funny actually: Most people posts multiple times, but this forum thinks the most prioritized field is the first name. A little bit of javascript to move the focus to the 'Message' in case the name and email can be auto-filled using a cookie would be practival. Or the MCU field in case the user is creating a new thread.
A little bit of javascript could also detect most unformatted source code and require the poster to correct.
"I think this macro will inform when the function is called..."
Yes, that's right!
"...but who calls the function is still not known."
Yes it is - by examining the preceding trace!