News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Console output

Started by brixton, June 16, 2010, 10:19:21 PM

Previous topic - Next topic

brixton

Hi all,

I have written some code to count how many instructions are being processed for a process loaded using CreateProcess.  This involves setting the 'trap flag' and processing the EXCEPTION_SINGLE_STEP message after a WaitForDebugEvent call.  When I process the message, I increment a counter by one.  I found that this particular target process has 11939 instructions before a EXIT_PROCESS_DEBUG_EVENT message.  So I tried to pause the target process after, say, 11938 instructions.  This seems to work, but the target process is very simple:  it only prints out all 3-letter combinations to a console (aaa, aab, aac and so on).  I'd expect that after 11938 out of 11939 instructions, I'd have seen all the output on the console by now.  However, when I process the last instruction, the output then floods onto the console.  Am I seeing a delayed write (or flush) to the console here, ie. all at once at the end, or am I doing something wrong?  I have to admit, it all looks like it works fine, it's just this console writing which is confusing  :dazzled:

In pseudocode:

counter = 0
stopPoint = 11938
CreateProcess, addr target, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | CREATE_NEW_CONSOLE, NULL, NULL, addr startupInfo, addr targetProcessInfo
WaitForDebugEvent, addr lastDebugEvent, INFINITE
switch (lastDebugEvent.dwDebugEventCode)
    .
    .
    .
    case EXCEPTION_DEBUG_EVENT:    switch(lastDebugEvent.u.Exception.ExceptionRecord.ExceptionCode)
                                        .
                                        .
                                        .
                                        case EXCEPTION_SINGLE_STEP:   inc instructionCounter
                                                                      IF instructionCounter == stopPoint
                                                                        ; pause here
                                                                      ELSE
                                                                        invoke GetThreadContext,pi.hThread,addr context
                                                                        or context.regFlag,100h
                                                                        invoke SetThreadContext,pi.hThread, addr context
                                                                        invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,DBG_CONTINUE
If you love somebody, set them free.
If they return, they were always yours. If they don't, they never were..

Tedd

The console output will be buffered; usual policy is to flush after any newline character, and sometimes after some time delay. Also, there will probably be a flush when your process ends, as part of the console clean-up (for the case where the output didn't end with a newline.)
No snowflake in an avalanche feels responsible.

brixton

Hi Tedd,

Thanks for the reply.  I am largely following Iczelion's tutorial on single-stepping.  However, with my code, I tried a new exe: one which moves the mouse left by one pixel at a time until it reaches the left of the screen (this way I thought I could combat the flushing problem).  Again it stops near the end of the total number of instructions and THEN moves the mouse left constantly.  Surely this is wrong.. I can't believe that all these mouse moves will be 'flushed' at the end too  :dazzled:

While running Iczelion's single-step example (literally copy/pasted) on that same application which moves the mouse left, I started the mouse at random distances from the left of the screen - but I always get the same number of instructions processed (which has to be wrong, because it would require more SetCursorPos calls).  Now I'm very confused!
If you love somebody, set them free.
If they return, they were always yours. If they don't, they never were..

Tedd

Single-stepping effectively holds up the entire system while your process is using the CPU, even though other processes are running 'normally.'
I suppose anything done on behalf of your process will also be held up; most of it will just come down to timing. Also, screen updates are expected to happen so regularly that they're treated as low priority.
The count of instructions processed is only for your specific thread, not all instructions processed on your behalf. This won't include processing done by device drivers, GUI threads, and various other things. However, while they're running in your address-space (as part of your process) they will still be held up by your single-stepping.
No snowflake in an avalanche feels responsible.

brixton

Ah thanks Tedd,

So is there any way I can overcome this and single step as, say, Olly does?
If you love somebody, set them free.
If they return, they were always yours. If they don't, they never were..