Usually debugging an application is straight forward: fire it up with a debugger. Even if the application requires some context (environment variables, specific directory, arguments etc.), it’s not that difficult as either it’s scriptable or the IDE will offer a plethora of options.
Now what to do if it comes to debug an application with a tortuous launch procedure, e. g. through a number of scripts and/or some helper processes? Certainly one may eventually find a way to force IDE/debugger to handle it but as a lazy programmer you don’t want to go through all of this just for the sake of dirty debugging, do you?
A dirty solution for a dirty debugging is to start the application with whatever requires it to start, make it wait for us and our dirty debugger to attach and then continue under the debugger control. This approach assumes that we can edit our application source code and rebuild it more easily than finding a way to start it with the debugger. This includes a situation when we just want to debug a code in a tiny library that is loaded by some unpleasant application.
Good. Now let’s get down to the dirty details.
I know, it looks utterly silly but it expresses the concept. It will loop until someone tells it to stop. The point is that someone is a “third person”, like in a crime story. We’ll see later who it is and how they tell the loop to stop.
An improved version of the silly loop is a daft loop:
This one at least exposes its folly only when the environment variable
is visible to the application process. Put the loop somewhere in your
application/library code where you want to start your debugging session. This
will work even for an optimized code as there’s not much the compiler can do
about the code around bDbg variable. Good for us.
To make this example more interesting, let’s compile it with optimizations so
referring directly to
bDbg variable is impossible (the compiler in this mode
doesn’t “allocate” it as an entity in the generated code). This might be
reasonable if we want to debug an optimized program when we investigate program
crash which doesn’t occur when compiled with debug information (due to different
process memory layout imposed). So here we go with the command line (Linux, x86
OK, I know it’s lame but I’m Intel syntax (l)user. That’s what I’ve been taught in the nursery school.
Now let’s see how our silly loop looks in the disassembly.
Rather boring. Execute two instructions in a busy loop. Let’s have a look at
first 20 lines of the
Now all we want to do is to force program to continue execution from the
instruction that succeeds the jump instruction
<main+37> that led us to the busy
loop. Let’s continue here:
<main+43>. Shall we?
Now we should be able to set breakpoints, watchpoints etc. and start debugging. In this simple example I just let the program to continue until it exits.
If the program is compiled with debug information so that referring to bDbg variable is possible, all the chaff above can be reduced to