Forum

Advanced Topic 1 of 5: Debugging

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Advanced Topic 1 of 5: Debugging

Postby Baker » Tue Oct 19, 2010 2:44 am

I don't know how to take advantage of making a debug build. As a result, I am slower at debugging than I should be and this wastes valuable time.

This question is aimed at the true engine lords, of which I definitely not a member of. I know I have a ton to learn.

The way I debug at least on Windows involving a crash to get to the memory address of the crash and then check the .map file to see where I crashed. But in more complicated situations this isn't immediately helpful although my habit of frequent releases even of unstable builds helps me limit the scope of problems (usually).

As a result I generally shy away from aggressive changes.

I know there isn't a fine tuned question here.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby mh » Tue Oct 19, 2010 9:24 am

I always use the debug build and always run in the debugger during development. Quite religiously.

There's no real hard and fast science to it, just a lot of setting breakpoints, inspecting values of variables, selectively commenting out sections of code to try to isolate problems, and a hell of a lot of experience built up over the years so that I sometimes intuitively "know" where a bug is.

Debugging isn't just about crashes; it's also about correct behaviour. It's possible to have a program that doesn't crash but still behaves incorrectly.

Catching potential bugs before they happen is important. I like to build up new code incrementally in layers and test at each layer. Make sure that part of it is working right before moving on to the next. For the same reason I hate just copy/pasting huge chunks of new code in.

Using a really really good debugger (like the one in VC++ 2008) is an absolute must here.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby frag.machine » Tue Oct 19, 2010 11:18 am

I second mh here: debug build all the way, incremental steps, avoid dropping large chunks of code at once (specially if it's not your code).

Also, the habit of refactoring code helps to isolate problems. Instead spreading the same code snippet across all the program, encapsulate it to a function. Instead laying 200 or more lines of hard-to-grasp-in-a-look code in a single sprint, break it in smaller functions with clear, significative names. If performance is a concern, you may later turn it in a inline function (though most of the cases the compiler itself takes care of optmize things to you). This way, you can easily enable/disable any calls to that code (or make it return a fixed value for test purposes).

BTW, I am not an "engine lord"; I just suffered enough thru years of coding and learned those things the hard way. ;)
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Postby mh » Tue Oct 19, 2010 11:38 am

frag.machine wrote:Imost of the cases the compiler itself takes care of optmize things to you

This is a very good point. Trusting the compiler to do the right thing is an important discipline to learn. Modern optimizing compilers are actually really good at doing this. They can't read minds and they don't get it right all the time, but I'd say in easily over 95% of cases they can produce a much better result than a hyper-optimized hand-crafted spaghetti mess (and in 95% of the other 5% of times all they need is a simple hint - like a cast or a change of operator order - and they'll get there). And you'll be grateful in 6 months time when you have to come back to it and maintain the code too.

This goes hand in hand with keeping your code simple and clean. I mentioned the ProQuake messaging system elsewhere (I believe I may have used the phrase "fucking mess"), and the same applies to what I've seen of CSQC so far. This ain't simple and clean code. Sure it works, and it probably works very well, but imagine if you had to step through it in a debugger? Would you be happy doing that?

So debugging is always easier if your code is easier to debug. Sounds trite but it's true. I don't always do it myself, but approaching writing code with that thought (and the thought of maintaining it in 6 months time) in the back of your mind will make you infinitely grateful to yourself later on.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby Spike » Tue Oct 19, 2010 3:37 pm

if you want to make use of visual studio's fairly awesome debugging capabilities, make sure your project is set up for incremental compilation, function level compilation, and lots of other random edit+continue junk that is all over the place that keeps on randomly being disabled at random.
Once your project is set up, its basically just a case of 'select debug build, press f5'.
If you've got a debugger attached, and this applies for gdb or msvc, you probably want to run quake windowed. This is especially true for certain d3d api versions/options...
Once your program crashes, it'll take you to the line it crashed at.
If you actually found all the right options mentioned in the first paragraph, you can actually make your fix/changes, press alt+f10, then press f5, and it'll continue from where it crashed, but with your changes in place, without having to restart the entire damn thing! Seriously awesome!
There's no real reason to run it outside of a debugger, other than the fact that it runs a little slower (due to being a debug build). If your bottleneck is opengl then it won't really be visible anyway (just starting the ide first will, and the debugger loading debugging info from dlls).
f5: run
alt+f10: apply changes
f11: single step onto the next line (entering functions)
f10: single step onto the next line (don't step through called functions).
f9: toggle breakpoint on the current line
Really all you need.
FTE's svn has some extra minidump code in client/sys_win.c which can generate a dump file if it crashes on someone else's computer (its ifdefed - disabled in release builds). You can then open this file up on your computer and see the state of things as they were when they crashed on the other guy's computer. It can be quite useful, but it does require code changes to your engine in order to generate them (also requires external files to be unchanged from when the exe was written, the .pdb specifically, I think).

If you're debugging with gdb, make sure you compiled it with -g, preferably with -O0, and definitely not with -s (and not used the strip command either).
gdb --args myexe mycommandline
commands:
run: start running
next: single step (ignore function calls)
step: single step (step into functions)
cont: continue
info regi: register dump for debugging gcc bugs
bt: simple backtrace
bt full: backtrace that is actually useful
quit: give up and run away
break func: set a breakpoint on the first instruction of a function
break file line: set a breakpoint on a given file+line
watch variable: set a watchpoint on a variable
A simplistic aproach is to run it, let it crash, type bt full, then quit...
You can make a .gdbinit file containing commands to be run when gdb is started up, including 'set args=-window -game crashy -basedir myquakedir', 'file mybinary', 'run'.

If you're debugging on linux, I personally find that running it in valgrind is seriously awesome, although not without issues - specifically, ones caused by your graphics drivers being buggy shit. Use environment settings to configure indirect rendering and its much faster+sane, although you may loose certain GL extensions, so might impact debugging renderer changes.
Even if you think your code is fine, running it in valgrind often reveals some dirty little secrets. Just make sure they're *your* secrets before you start trying to fix them. :)

If you're using gcc to compile, there's an application called addr2line, which is a much faster alternative to what you currently do, and gives line numbers rather than just function names. Requires debugging info, the same as gdb does though.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby Spike » Tue Oct 19, 2010 3:51 pm

I feel I should point out that what I said in my previous post relates purely to debugging. It does not relate well to writing new code.
Writing new code should never be written while in a debugger!
You should only use edit+continue stuff for small fixes and typos, or selective breakpoints perhaps.
But if you're writing new code, you should ensure that it is written correctly, before you start hacking at it from a debugger.
Debuggers are for debugging. Keep that in mind and your code will contain less bugs.
(I personally find msvc6 more usable than msvc2005, purely because msvc2005 messes up so much with preprocessor defines, and doesn't let you browse quickly on a per-function basis without it being part of some class... hello C! while msvc2003 has clumsy/vb default keyboard shortcut settings on top of that).
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby r00k » Tue Oct 19, 2010 5:53 pm

F5 works fine for me, though when using F11 i get stuck on
this part so, I usually F10 past this...
Code: Select all
if (!GetCurrentDirectory(sizeof(cwd), cwd))
      Sys_Error ("Couldn't determine current directory");

   if (cwd[strlen(cwd)-1] == '/') //<------------------F11 drops here!!
      cwd[strlen(cwd)-1] = 0;


> glQrack.exe!strlen(unsigned char * buf=0xfffffffe) Line 63 Asm
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby mh » Tue Oct 19, 2010 6:05 pm

r00k wrote:F5 works fine for me, though when using F11 i get stuck on
this part so, I usually F10 past this...
Code: Select all
if (!GetCurrentDirectory(sizeof(cwd), cwd))
      Sys_Error ("Couldn't determine current directory");

   if (cwd[strlen(cwd)-1] == '/') //<------------------F11 drops here!!
      cwd[strlen(cwd)-1] = 0;


> glQrack.exe!strlen(unsigned char * buf=0xfffffffe) Line 63 Asm

And what value is in cwd at the time? Sounds like GetCurrentDirectory is working OK but strlen (cwd) is coming out at 0.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby Downsider » Wed Oct 20, 2010 12:28 am

From what I've read, the PSP has a rudimentary debugger, though I've never needed to use it and thus never have, but since you seem to be having issues regarding your PSP engine, I thought I would let you know.
User avatar
Downsider
 
Posts: 621
Joined: Tue Sep 16, 2008 1:35 am

Postby frag.machine » Wed Oct 20, 2010 1:07 am

Don't shoot me if it's a stupid question, but... have anyone checked if there is some kind of PSP SDK for development on PC ? Let's say, an emulator where one can debug an application or something like that ?
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Postby r00k » Wed Oct 20, 2010 5:19 am

mh wrote:And what value is in cwd at the time? Sounds like GetCurrentDirectory is working OK but strlen (cwd) is coming out at 0.



It seems that when using strlen or strcmp etc it drops out with "no source" but using Q_strlen, Q_strrchr, Q_strcmp works... :| maybe I'm ignoring a lib?
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Postby Baker » Fri Nov 05, 2010 6:43 pm

Downsider wrote:From what I've read, the PSP has a rudimentary debugger, though I've never needed to use it and thus never have, but since you seem to be having issues regarding your PSP engine, I thought I would let you know.


Actually, I'm not having issues with "my PSP engine" but rather the PSP engine itself seems to hate mods like X-Men: Ravages of Apocalpyse and several [what I consider to be] medium-sized Quake maps.

I get crashes because I've done a lot of testing against maps and mods that I would guess others don't do. And the crashes I get, I feel I shouldn't get.

With the PSP, the crashes I am getting appear to be related to the memory system. I get an invalid pointer in Mod_LoadVertexes when loading any of the X-Men: Ravages of Apocalypse maps even without the progs.dat ... which leads me to believe Hunk_HighAlloc butts heads with standard Hunk_Alloc as it is written. So I've been burying my head in memory management.

But I've never found the PSP debugger binary. I have looked for it.

[Some people think development of the PSP engine is a waste of time, I see it as a dress rehearsal for future such devices. And the PSP quite a great job --- if only it had more memory.]
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Baker » Fri Apr 08, 2011 11:40 pm

Just storing this here: For MSVC6, the settings I've been using for debug builds. Prior to a few weeks ago, I never utilized the debugger (what a shame).:

Compiler options:

/ZI "Compiler for edit and continue. If you want to use Edit and Continue debugging, you must use this option. Because most optimizations are incompatible with Edit and Continue, using /ZI disables any #pragma optimize statements in your code."

/Od "Disable Optimizations (Debug): This option turns off all optimizations in the program and speeds compilation. This option is the default. Because /Od suppresses code movement, it simplifies the debugging process."

Define _DEBUG - The compiler defines _DEBUG when you specify the /MTd or /MDd option. These options specify debug versions of the C run-time library. Uses C Run Time library.

Plus "Link incrementally" and "Generate debug info". To get information on globals, I just type the variable name in the watch window.

At some point I'll play with the debugger in gcc. I am aware there are a trillion extra debug capabilities in MSVC, but stop and continue and the ability to inspect and catch crashes on-the-fly is about all I need at this point.

Quite a shame that I couldn't figure out how to use the debug capabilities appropriately in the distant past.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Baker » Sat Apr 09, 2011 1:32 am

gdb's debug [in Code::Blocks IDE] isn't quite as intuitive as Visual Studio but it isn't bad once you get used to it. -g + -ggdb as compiler options.

http://wiki.codeblocks.org/index.php?ti ... de::Blocks

To watch a global, right click on the Watch window much like MSVC and type in the name.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest