Archived

This topic is now archived and is closed to further replies.

Shannon Barber

Call Stack information and exceptions

Recommended Posts

Null and Void    1088
My guess (read: guess, I''ve never done this =P) is that they derive all exceptions from a single class that contains a linked list. Every function (or method, or whatever) that catches the exception appends its name to the list. I could be completely wrong though.

[Resist Windows XP''s Invasive Production Activation Technology!]

Share this post


Link to post
Share on other sites
Kylotan    10008
(edit: ignore what was here previously: it made no sense cos I misread something).

I think they use macros at the start and end of each function: the first macro basically starts a try block, and the last macro is a catch block that outputs the function name before rethrowing the exception. Or something like that.

Edited by - Kylotan on January 12, 2002 3:45:36 PM

Share this post


Link to post
Share on other sites
Brannon    122
Under Win32, you can use the DBGHELP functions to walk the stack (ie. build a stack backtrace like in the debugger). If you have symbol files with your executable (even just the public symbols), you can use those to resolve function names, etc on the stack (and sometimes provide parameter info too).

If you have used windbg (from the Windows DDK/SDK), then you''re probably already familiar with this (the ''kb'' command in windbg generates the back trace).


-Brannon

Share this post


Link to post
Share on other sites
Shannon Barber    1681
I''ve used wind bag from time to time, but am not familar with every thing it can do.

Cool thanks Brannon, I''ll read up on using sysmbol files and minidumps - it should be possible to pin-point the line of your source a crash occured at and do a call-stack trace to show the execution in a release build using the symbol file generated by the compiler...

Share this post


Link to post
Share on other sites
LessBread    1415
Check out the MSDN "Under the Hood" articles from April and May of 1997 - the April article shows how to catch unhandled exceptions and walk the stack backwards from there - the May article shows how to use the ImageHelp.dll to correlate the stackwalk info with the debug info. Because Imagehlp.dll has been superceded by dbghelp.dll - you''ll have to put a little work into using the tricks from the second article.

‘But truth's a menace, science a public danger.’ Brave New World, Aldous Huxley

Share this post


Link to post
Share on other sites
Houdini    266
I basically agree with Kylotan, that I think they use macros to do it. However, you don''t need to use exception handling for it to work.

You could create Singleton a StackHistory class that is basically a LIFO container to keep track of stack information. Then create a StackEntry class that takes a string (the class/function) as it''s constructor parameter. This class will automatcially communicate with StackHistory to push this new entry in the constructor, and pop this entry in the destructor.

Since the destructor gets called automatically when the function exits then you only need one macro at the start of the function, and no ending macros, which would be a pain since many functions have multiple exit points.

Although you don''t need a macro, it''s very useful here because it allows you to automatically record the file/line number with the class/function name, as well as allowing you to turn off the stack tracing by redefining the macro.

BTW, this stack tracing approach also makes it very easy to add code that times each function, thus giving you your own profiler.

The reason I like this approach so much better than DBGHELP is because it''s platform independant, which is very important to me.


- Houdini

Share this post


Link to post
Share on other sites
Shannon Barber    1681
I have this funny feeling in my gut that tells me MiniDumpCallStack is approx. 10000000000000000000000000000000% faster than the daisy-chained exception/linked-list methods
Still, I wonder how they did it with Unreal ''cause the dialog box that pops up shows the whole decorated call-stack right in front of you.

The Dump method has the _added_ advantage that it requires the symbol file - this way clients can have automated error reporting, but they don''t have the symbols there to hack it (like they would with the ensueing string table the other methods would create). Also it could show the user what it''s sending, and it''ll look like a core-dump, like random crap to the untrained eye. But you have a nice little program that reads the dump and your symbol file and out pops:

printf("The buggy pos whacked the meat on line %l in file %s. Last editted by %s on %s.", iLine, szFile, szWhoDoneIt, szWhen);

And the rest of the call-stack ensues...

Share this post


Link to post
Share on other sites
Void    126
The dbghelp library doesn''t give very accurate results in release mode because of compiler optimizes away stack frames.

I believe the unreal uses their own push pop system. The Tips of the day at Flipcode has several of such systems.

Share this post


Link to post
Share on other sites
Brannon    122
That''s not entirely true. Yes, the compiler optimizes the hell out of the release binary, but the [release] symbols will still provide you with a stack dump. Having the program create a minidump is actually a great way to do it. Then you can get the minidump, open it in windbg (with your copy of the symbols), and debug it (get the stack trace, etc). I believe creating a minidump is *very* simple (what, one API call?).


-Brannon

Share this post


Link to post
Share on other sites
Chris Hargrove    256
Unreal''s system is done "manually" via macros, as mentioned above. This has its strengths and weaknesses. Personally, I prefer automated stack dumps when possible (like with DbgHelp on Win32).

I haven''t had many problems getting accurate stack dumps from release builds compared to debug builds, for the most part. Unfortunately, there are still a handful of issues that I don''t believe even the "Under the Hood" column or "Debugging Applications" book mentions, in terms of the StackWalk function.

For the context information passed into StackWalk, I''ve seen some examples which use GetThreadContext(). I haven''t had a whole lot of luck with this function personally, since the fact that it''s deeper inside Win32 affects the resulting context, and you have to filter out the lower calls manually. Even then, the context I got back didn''t seem to be accurate many times. So I would recommend writing your own __declspec(naked) context retrieval function instead.

Once you know your context is correct, StackWalk''s addresses are based on the return addresses stored on the stack, which are not really the "call" instructions but rather the instruction afterward. This distinction often results in line number information that is one or more lines off of the actual line you''re currently in (it''s reporting the line number connected to the instruction after the call, not the one making the call). This is a problem at the top of the stack too, since EIP will already be an instruction beyond the one that crashed. Now, while it''s difficult to deal with the TOS being off by a line or so (it''s usually close enough in practice), the other stack elements always follow "call" instructions so they''re easy to correct. MSVC always uses a 5-byte call instruction form, so for all StackWalk results other than the TOS, subtract 5 bytes from what it returns. This will move the instruction addresses from the instruction after the "call" back onto the "call" itself. This slight change has given me much more accurate stack dumps in many situations.

Share this post


Link to post
Share on other sites
Null and Void    1088
In case anyone cares, here''s my report on implementing Houdini''s method in my engine''s debug code. It works well, but their''s one gotcha. You have to keep in mind that multiple threads will mess with the results unless you keep them away from each other in seperate lists (which isn''t that hard, once you realize it ).

[Resist Windows XP''s Invasive Production Activation Technology!]

Share this post


Link to post
Share on other sites