tags:

views:

61

answers:

2

Hello,

I am working on this small project where I'd like to generate the call graph of an application - I am not planning to do anything complex, it is mainly for fun/experience. I am working on x64 platform.

The first goal I set myself is to be able to measure the time spent in each function of my test application. So far my strategy has been to use _penter() and _pexit() - _penter() is a function that will get called at the start of every method or function and conversely _pexit() will get called at the end of every method or function.

With these two functions I can record each function call as well as the time spent in each of them. What I'd like to do next is get the address of each function being called.
For example if we consider the following callstack (very simplified):


main()  
....myFunction()  
........_penter()
 

I am in _penter and I want to get the address of the calling function, myFunction(). I already found a way to do it in the case of non-leaf functions, I simply use RtlLookupFunctionEntry. However this solution doesn't seem to work for leaf functions because they don't provide any unwind data.

One thing I was thinking about is to go up one more level in the callstack, in main(), and decode the CALL procedure manually - that would involve getting a pointer to the instruction calling myFunction().

I was wondering if any of you would know how to get the address of the current function in the case of leaf functions. I have this gut feeling that my current approach is a bit overcomplicated.

Thanks,

Clem

A: 

I believe SymGetSymFromAddr64, probably along with StackWalk64 should get you (most of?) what you want.

Jerry Coffin
Yes, it worked!
Clem
+1  A: 

Hmm, x64 code, no assembly hacks at your disposal unless you use ml64.exe. There's one intrinsic that ought to help here, _ReturnAddress() gives you the code location of the call to your __penter() function. The instruction after it btw. That should be enough to help you identify the caller.

Hans Passant
+1 correct. Functions do not overlap, so in the MAP file you can look up the highest function address lower than the _ReturnAddress().
MSalters
If I get it right your solution involves reading the MAP file and then getting the function address based on the return address of _penter. The solution I had in mind would not require to read an external file. Still, I'll give it a go. Thanks!
Clem
Use the dbghelp API.
Hans Passant