Discussion:
Single-Stepping.
(too old to reply)
L. Spiro
2005-02-25 03:35:05 UTC
Permalink
I am writing a debugger with so-far great success, but something seems to be
wrong with my single-stepping routine.

Normally, without single-stepping, I do this:

//============
Breakpoint is hit.
Go to EXCEPTION_BREAKPOINT.
Change the value at the break from 0xCC back to its original value and set
EIP back one step.
Put the thread into single-stepping mode (EFlags |= 0x100).
Then ContinueDebugEvent() is called with DBG_CONTINUE.

Then EXCEPTION_SINGLE_STEP exception is thrown one step later.
I go back to the address of the break that was last hit and add the
breakpoint again.
I remove the single-step flag (EFlags &= ~0x100).
Then ContinueDebugEvent() is called with DBG_CONTINUE and the program
continues until another break is hit.
//============


This works.


Here is my logical pseudo code for single-stepping.

//============
::EXCEPTION_BREAKPOINT IS HANLED THE SAME WAY::

Then EXCEPTION_SINGLE_STEP exception is thrown one step later.
I check to see if this was hit because of a breakpoint from the last
instruction or because of single-stepping from the last instruction.
If it was a breakpoint, I add the 0xCC again.
If I am not in single-stepping mode, I continue as above by removing the
single-step flag and proceeding with DBG_CONTINUE.
If I am in single-step mode, I wait (on that thread) for the command to
either single-step or to continue normally (this waiting period happens
inside the EXCEPTION_SINGLE_STEP catch and before ContinueDebugEvent()).
If the user hits the single-step button, I set the single-step flag again
and call ContinueDebugEvent() with DBG_CONTINUE.
Otherwise I remove the single-step flag and call ContinueDebugEvent() with
DBG_CONTINUE.
//============


Is there something I am missing here?
After I give the command to single-step, the program, well, does something
else besides single-step (as far as I can tell).
To single-step a multi-threaded program, all threads must be set to
single-step, yes?
But if that is so, why does my first solution work when it only single-steps
one thread?

Or is it because that single thread single-steps, but others are still
running?


Usually what happens in my case is that I single step, but then the original
breakpoint is hit again one or two steps later, even though it should not be
anywhere near that breakpoint anymore.
Is it because it is hit on another thread then?

Is the purpose of single-stepping all threads just to make things work
logically or is there actually a Windows® implementation that prevents
single-stepping unless all threads are in single-stepping mode?


L. Spiro
Slava M. Usov
2005-02-25 11:43:38 UTC
Permalink
"L. Spiro" <***@discussions.microsoft.com> wrote in message news:0A789957-F592-4E50-94F1-***@microsoft.com...

[...]
Post by L. Spiro
After I give the command to single-step, the program, well, does something
else besides single-step (as far as I can tell).
After a single step exception, TF is automatically cleared in eflags. You
must set it again if you want to stay in the single step mode.

S
L. Spiro
2005-02-25 16:53:06 UTC
Permalink
Post by Slava M. Usov
After a single step exception, TF is automatically cleared in eflags. You
must set it again if you want to stay in the single step mode.
S
I do.
It’s in my pseudo code (“If the user hits the single-step button, I set the
single-step flag again and call ContinueDebugEvent() with DBG_CONTINUE.”).

But! Must I set it on all threads?

L. Spiro
Slava M. Usov
2005-02-25 18:51:44 UTC
Permalink
It's in my pseudo code ("If the user hits the single-step button, I set
the single-step flag again and call ContinueDebugEvent() with
DBG_CONTINUE.").
But! Must I set it on all threads?
If you want to single step one thread, set it on that thread. If you want to
single step the entire process, set it on every thread in the process. That
depends on your needs. As a person who uses debuggers frequently, I would
not want to single step multi-threaded processes entirely except in very
special circumstances.

S
Pavel Lebedinsky
2005-02-26 05:14:34 UTC
Permalink
Post by Slava M. Usov
It's in my pseudo code ("If the user hits the single-step button, I set
the single-step flag again and call ContinueDebugEvent() with
DBG_CONTINUE.").
But! Must I set it on all threads?
If you want to single step one thread, set it on that thread. If you want to
single step the entire process, set it on every thread in the process. That
depends on your needs. As a person who uses debuggers frequently, I would
not want to single step multi-threaded processes entirely except in very
special circumstances.
Usually debuggers single-step one thread, and the rest are running freely.

Some debuggers allow you to suspend all threads except the current one
when you single step. For example in windbg/cdb you can do this:

0:000> ~.t

Single-stepping every thread is indeed somewhat unusual.

Tony Proctor
2005-02-25 19:21:28 UTC
Permalink
The trace-bit applies to individual threads. Hence, each thread has it's own
concept of whether it is stepping or not. However, a BPT in shared code will
affect *all* threads executing that shared code. Hence, your BPT pseudo-code
will apply to all threads, irrespective of whether they're in stepping mode
or not.

Tony Proctor
Post by L. Spiro
I am writing a debugger with so-far great success, but something seems to be
wrong with my single-stepping routine.
//============
Breakpoint is hit.
Go to EXCEPTION_BREAKPOINT.
Change the value at the break from 0xCC back to its original value and set
EIP back one step.
Put the thread into single-stepping mode (EFlags |= 0x100).
Then ContinueDebugEvent() is called with DBG_CONTINUE.
Then EXCEPTION_SINGLE_STEP exception is thrown one step later.
I go back to the address of the break that was last hit and add the
breakpoint again.
I remove the single-step flag (EFlags &= ~0x100).
Then ContinueDebugEvent() is called with DBG_CONTINUE and the program
continues until another break is hit.
//============
This works.
Here is my logical pseudo code for single-stepping.
//============
Then EXCEPTION_SINGLE_STEP exception is thrown one step later.
I check to see if this was hit because of a breakpoint from the last
instruction or because of single-stepping from the last instruction.
If it was a breakpoint, I add the 0xCC again.
If I am not in single-stepping mode, I continue as above by removing the
single-step flag and proceeding with DBG_CONTINUE.
If I am in single-step mode, I wait (on that thread) for the command to
either single-step or to continue normally (this waiting period happens
inside the EXCEPTION_SINGLE_STEP catch and before ContinueDebugEvent()).
If the user hits the single-step button, I set the single-step flag again
and call ContinueDebugEvent() with DBG_CONTINUE.
Otherwise I remove the single-step flag and call ContinueDebugEvent() with
DBG_CONTINUE.
//============
Is there something I am missing here?
After I give the command to single-step, the program, well, does something
else besides single-step (as far as I can tell).
To single-step a multi-threaded program, all threads must be set to
single-step, yes?
But if that is so, why does my first solution work when it only single-steps
one thread?
Or is it because that single thread single-steps, but others are still
running?
Usually what happens in my case is that I single step, but then the original
breakpoint is hit again one or two steps later, even though it should not be
anywhere near that breakpoint anymore.
Is it because it is hit on another thread then?
Is the purpose of single-stepping all threads just to make things work
logically or is there actually a Windows® implementation that prevents
single-stepping unless all threads are in single-stepping mode?
L. Spiro
Loading...