Tracing through, modifying variables in memory to hit some obscure branch of code. Rarely edit and continue, for some reason I can't quite trust it to keep sane state, so full runs after a change.
When impossible to trace (gdb on windows is way too slow for example, hitting a breakpoint takes 30 seconds each time) then printf. Junk code and throws off timing in case of multithreading bugs, but sometimes it is the only way.
Disassembler debuggers when having to debug release builds without debug information (Olydbg is nice when it works).
Proper logging is nice when it is available, takes effort to setup and use, but very valuable when needed.
Sending stacktraces of crashes home is even nicer.
Asserts spreaded around where needed.
Minidumps for crashes on users machines. (Reproducible crashes are the best. If bugs can't be relied to show up on time then what can?)