writting a stack tracer?

Programming, for all ages and all languages.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: writting a stack tracer?

Post by bluemoon »

Sam111 wrote:your not telling me any thing new that I already don't know.
How about you think you knew it all but in fact you do not?
Sam111 wrote:Basically my question is given an arbitrary programs stack is their away to backtraces it to get the calling function stack / calling functions address?
Most stack trace technique rely on the assumption on stack pointer points to meaningful things.
If you don't know the calling convention, you cannot guess anything from the register states, for example, EBP may be anything.

However, for some calling convention and compile option, stack frame *may be* used.
You can expect [EBP+4] points to caller's return address, so it's possible to further resolve the caller symbol by looking which function block encloses the address.
you may also resolve parameters and local variable by looking on the stack.
Sam111 wrote: And I am assuming a function is something that uses at least the call asm instruction so the return address is in theory somewhere on the stack. (but may not use the stack necessary for passing parameters could use registers or other means)
It's that somewhere cause the trouble, it can be anywhere. Consider this:

Code: Select all

call foo
...
foo:
   push eax
   push ebx
   (crash and do stack trace here)
   ret
The return address is on [ESP+8] instead of [ESP]

You need a policy (ie. stack frame) to make sure where it is.
Sam111 wrote: Note: I don't consider storing in registers and jmp to a label to be a function
The CPU may think otherwise.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: writting a stack tracer?

Post by Combuster »

Oh and, because I'm ROFLing already.

Learn about LEAVEing. It does exactly what you can't. :twisted:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: writting a stack tracer?

Post by Sam111 »

push ebp
mov ebp, esp // ebp « esp
from this I see [ebp +8] has my return address always so if the calling convention is the standard cdecl , stdcall , fastcall ,...etc
Or at least something that uses a stack frame that doesn't modify the ebp inside the function it will always point to a place where I can get the function parameters and return address.

However if somebody wrote code to not use calling conventions and mov's something into the ebp in side their ffunction their would be no way of determining the return address from an offset of ebp.

And this stack trace would only work if you had physical access to what the ebp contained .. so if you where given a arbitary stack without the ability to see what the registers had in it then their would be no real definite way to find the return address you need at least to know whats in ebp.

So it looks like you need to have a debugger to have a stack tracer or at least access to the programs registers while executing and the ability to set break points.

In theory I think we are just looking at it from to different points of view.
1) I am looking at it from given a arbitary stack (or part of a stack in time dumped to a file) determine the calling functions from the stack
2) you are assuming I can execute it and see registers not just have a dump of a stack of data.

Either way I think I got my answer
1) NO in general
2) YES if you can have access to the ebp register , return function address is at [ebp + 8] under normal calling conventions provided inside the function ebp is not modified it is only modified when setting up stack frames when entering in functions.

Thank you for your help I know I can be a pain.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Re: writting a stack tracer?

Post by JamesM »

Hi,

I see that noone actually answered your question, possibly because it was written as a set of assumptions to which people then responded true/false/ridicule.
Either way I think I got my answer
1) NO in general
2) YES if you can have access to the ebp register , return function address is at [ebp + 8] under normal calling conventions provided inside the function ebp is not modified it is only modified when setting up stack frames when entering in functions.
In order to perform a reliable backtrace, you need to either:
a) Assume a calling convention is followed.
b) Assume debug information is present.

Debug information will tell you exactly how to crawl the stack. The problem is that it is not always available. Compilers on x64 tend to generate unwind tables only when -g is passed or if backtrace() is compiled in, to save space. It's also difficult to read due to the compression techniques it uses.

The easiest thing to do is assume a calling convention. For UNIX-based toolchains such as you will use to cross-compile, this will be cdecl. In order to backtrace, you also need to ensure the frame pointer is used. -fno-omit-frame-pointer will do this on GCC - frame pointers are on by default on 32-bit x86 GCC but disabled by default on 64-bit.

Then, you just need to crawl the frame pointer chain. Read the frame pointer - EBP on 32bit, RBP on 64bit. That will form a linked list taking you through the stack.

For every value of the frame pointer (every stack frame), you can find the return address for that stack frame in EBP+4 or RBP+8. *NOT EBP+8 AS YOU MENTIONED!*

Hope this helps.

James
User avatar
Sam111
Member
Member
Posts: 385
Joined: Mon Nov 03, 2008 6:06 pm

Re: writting a stack tracer?

Post by Sam111 »

I agreed I was thinking of both rbp x64 and x86 ebp and wrote the [ebp+8] instead of [ebp +4] and [rbp+8].
As you mention but I think we are now both on the same page.

And as for
-fno-omit-frame-pointer
That is what I was talking about they must use a stack frame and not effect the ebp or rbp inside the function (i.e other then pointing it to the next and previous stack frame on enter/leave of a function).

Weather the slower enter , leave commands are used or their equivalent push ,pop instruction blocks doesn't really matter interms of finding the return address.

Either way 90% of the time the stack will be a calling convention that is cdecl , stdcall ,...etc (that contains the stack frame unless of course you wrote custom asm,inline asm, or turned off -fno-omit-frame-pointer in the gcc compiler. But the odds of that is probably slim that they would do that.

Either way most of the time you should beable to get a stack trace given the ebp value and a dump of where the current stack is.
You wouldn't even need a debugger or anything just a program that would dump the current stack at a given time and the current ebp value.
From their you can try the standard calling convientions

But bottom line their is no general way to do it in all cases just mostly all cases based on the ebp and stack frames /(how they work in most cases)
he's begining to believe 8)
Now of course with out debug info like symbol table or code segment code you would only beable to determine the return address , function parameters/local variables to some extent and write it out like func1(a,b,c) = address ---> func2(a) = address --->..etc not knowing the names without a symbol table (but thats ok since names are just for show anyway :))
Last edited by Sam111 on Mon Mar 05, 2012 3:35 pm, edited 1 time in total.
User avatar
brain
Member
Member
Posts: 234
Joined: Thu Nov 05, 2009 5:04 pm
Location: UK
Contact:

Re: writting a stack tracer?

Post by brain »

I managed to come up with a stack trace in a few minutes of coding. imho its not too hard, read up on stack frames and the nm command. my os exports a symbol file at compile time that it reads on boot into an ordered linked list and in the fault handler it walks the stack frames on the stack displaying addresses, offsets and function names. once you know how, its simple. but, this does make your os specific to a particular compiler suite, or at least the backtrace code but as others already stated there isn't much way around that... let me know if you get what I'm saying, I may share source if you are interested.

Edit: deeper reading makes me think you already know this, but I've left this anyway for others who might search the threads for the same question.
Post Reply