Sign in to follow this  
CipherCraft

Incremental linking - messed up call stack?

Recommended Posts

Hey, I'm showing a call stack in our assert dialog, which is convenient to see how the assert got to be fired. And it works well... most of the time. The debug build, when needed, works like a charm. The release build (with symbol information) is not so friendly. When linking incrementally the callstack ends up being too short and only shows the assert handling code. But after a full link the stack trace is fully complete and sane. And this is true for each type of link, all the time. I've tried unloading modules in case they were left behind after the last run, but no joy. I can't find anything specific on my problem online; Google is currently not on speaking terms with me, apparently. [bawling] So... Any of you, please, tell me you've come across this before and know just the fix for this. tia, CipherCraft

Share this post


Link to post
Share on other sites
To understand this, we will need to have a look at how incremental linking works.
Normally when a function is added or removed, all addresses after its new location would have changed and you'd have to do a full re-link. Incremental linking avoids this by wiping out the removed function's code with 0xCC (int 3/breakpoint to ensure it's not called) or appending newly added functions on to the newly extended code segment. What makes this work is that functions are now called indirectly, via thunks. When a function is moved, only its thunk need be updated; other code that uses it is unaffected.

In your case, the stack trace is getting a return address, looking at the previous instruction and seeing a call to the thunk. Since it doesn't know to follow the ensuing JMP at the thunk function, you aren't getting the real call target.
For things to work with (evil) incremental builds, this logic will have to be added; you could also switch to StackWalk in such cases because it ought to be able to handle them.

HTH+HAND

Share this post


Link to post
Share on other sites
Quote:
Original post by Jan Wassenberg
To understand this, we will need to have a look at how incremental linking works.
Normally when a function is added or removed, all addresses after its new location would have changed and you'd have to do a full re-link. Incremental linking avoids this by wiping out the removed function's code with 0xCC (int 3/breakpoint to ensure it's not called) or appending newly added functions on to the newly extended code segment.


Right. That's my understanding also.

Quote:
Original post by Jan Wassenberg
What makes this work is that functions are now called indirectly, via thunks. When a function is moved, only its thunk need be updated; other code that uses it is unaffected.
In your case, the stack trace is getting a return address, looking at the previous instruction and seeing a call to the thunk. Since it doesn't know to follow the ensuing JMP at the thunk function, you aren't getting the real call target.


News to me! This explains alot. I have not found anything on thunks in this situation before. I'll try and read up; any good hints on where to start looking?
Are these the symbols that are marked as virtual by any chance?

Quote:
Original post by Jan Wassenberg
For things to work with (evil) incremental builds, this logic will have to be added; you could also switch to StackWalk in such cases because it ought to be able to handle them.


(evil) I know, but we need the 40 seconds we gain by using incremental. Or so I'm told. [wink]

StackWalk, hmmm.... Does it work better than StackWalk64, which I'm supposed to be using according to MSDN? Or am I missing your point?

++rating anyways, for providing just that spot of information that I needed to keep my sanity. [wink]

Thanks for taking the time and sorry for all the follow up questions.

Share this post


Link to post
Share on other sites
A small follow up.

- The thunking is done only for non-static functions; static functions are unaffected.
- The combination release / incremental:yes is deadly for reporting proper call stacks.

I still haven't found a solution. [sad] I would need to detect static functions and add some logic to find that extra JMP.

I'll have to put this on the back burner; other stuff has a higher priority. But I'd really like it to work all of the time.

CipherCraft

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this