News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Another debugging tool for y'all

Started by NoCforMe, March 18, 2015, 02:04:19 PM

Previous topic - Next topic

NoCforMe

I just finished this little project, thought I'd share it with you all here. It's a (fairly) simple debugging tool that gives you a window (literally) into data within your program that you'd like to peek in on. It has a scrollable display that shows the selected data as bytes, words or doublewords. You can mouse-select data items in the word or dword display modes. Keyboard selection is limited to forward- and back-cursor keys (but you can type an address into the "Go" field to go there).

After linking the module to your program, you first call its initialization routine, then invoke the debugger, telling it what you want to look at and how much data to display thus:


INVOKE InitDebugView, InstanceHandle

; do some stuff here in your program that's buggy ...

INVOKE DebugView, OFFSET data2display, dataLength, OFFSET debugIDmsg


I'm not claiming this is a rival to Olly or anything, maybe not even as kewl as the debugging features in MasmBasic, but who knows? you might just find it useful.

There are still some to-dos I didn't get around to (see comments in the code), but I tested it and it seems pretty solid. One warning: don't ask it to display data that's beyond what's allocated to your program, or it might crash trying to access invalid data.

Anyhow, give it a look-see, and of course reply back here with any criticisms, etc.

Edit: The attachment is now 2 messages down.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on March 18, 2015, 02:04:19 PMthe debugging features in MasmBasic

Thanks for the honorable mention ;-)

NoCforMe

I've uploaded a new zip which fixes some small problems I overlooked.

If you want to use this in your program, edit DebugView.asm and remove the externdef near the top (that's just for my testing purposes, to let the testbed program look at data within DebugView). There's also an include file which has prototypes for the two routines you need to call (InitDebugView and DebugView).
Assembly language programming should be fun. That's why I do it.

Antariy

Quote from: NoCforMe on March 18, 2015, 02:04:19 PM
There are still some to-dos I didn't get around to (see comments in the code), but I tested it and it seems pretty solid. One warning: don't ask it to display data that's beyond what's allocated to your program, or it might crash trying to access invalid data.

You may try to use the SEH macroses from the signature of my post, to protect your code from crashing. Also you may use IsBadReadPtr API to check the data you want to read and display.

NoCforMe

Thanks, but to be honest, that seems like overkill for this project. It's not intended for any "mission-critical" debugging, and it's up to the user (up to now, me) to make sure that the data they look at is in bounds.

Still, good to know that this exists. I've downloaded it and may play with it later.

BTW, where is IsBadReadPtr from? Is that your API, or part of Windows? I assume it's some sort of bounds-checking routine, yes?
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on March 19, 2015, 07:17:48 AMBTW, where is IsBadReadPtr from? Is that your API, or part of Windows?

IsBadXxxPtr should really be called CrashProgramRandomly

It still can be useful, especially in a debugging context.

Antariy

Jochen, that's a very subjective point of view which is very one-side shaped.

First thing: the stack growth will work with no dependency of that IsBadRead/WritePtr referenced to the guard page. The topic write was should check that before write that.
Second thing: the SEH handler actually might be implemented in such a was, that it will not silently handle the exception of access to the guard area, but will rather pass the exception further - i.e. it will return with the flag that the exception was not processed so Windows will continue to search the other exception handler in a chain of the handlers. So, if there were such a handler which was intended to catch specifically the guard page access exception - it will have opportunity to do that. So all will work as it should. You just need to write your own IsBadRead/WritePtr - this is really simple and trivial task, so it's not the matter of such a big and "smart" topic. With no difference to that who did write that topic - the topic has no any much idea on the topic it tells about and more over it's more confusing to many people that is useful. Rather that describe how to write a proper code to check that unknown memory locations, the code just write about fears of doing it - it's funny and is actual "informational shit", with no dependency who wrote that topic. And the "smart" advice that code should always crash - is not always applicable ::) The code MUST work propely, but how it will do so - is "undefined" - so such things as protection from crash while accessing inaccessible areas has its value in its fields, too. Wrong code is which silently hides the UNEXPECTED errors, but the code which expects possible errors and handles that in a right and robust way - is proper code.

NoCforMe

Quote from: jj2007 on March 19, 2015, 07:52:39 AM
IsBadXxxPtr should really be called CrashProgramRandomly

Hmm: from that blog (Raymond Chen's?):

Quote"But what should I do, then, if somebody passes me a bad pointer?"

You should crash.

No, really.

In the Win32 programming model, exceptions are truly exceptional. As a general rule, you shouldn't try to catch them. And even if you decide you want to catch them, you need to be very careful that you catch exactly what you want and no more.

Thus endeth today's Zen in programming lesson ...
Assembly language programming should be fun. That's why I do it.

jj2007

Alex and NoCforMe,

The discussion is old, see a 2009 thread, and it will remain controversial. I lean to the "let it crash" side, but I understand the argument "mission-critical code is not allowed to crash". A wise strategy is probably to let it crash in the debug but not in the release version. Plus, error checking wherever there is a minor risk to provoke one.

It seems, though, that the C/C++ crowd is scared of crashes - whenever you see some piece of C/C++ software in the debugger, the SEH is there. Which doesn't stop such software from hanging, as Adobe, Firefox and others demonstrate far too often. The "don't let it crash" philosophy ends up too often in lousy code.

Antariy

Jochen, here I agree with what you saying, yes, the SEH as it used in the not-well-mannered fashion is just one more reason to even more buggy and misproper code.
But when it used properly (for an instance to not allow code crash in the situation where the crash is expected and is ony of the PROPER ways of the algo which code implements) - SEH should be used and is proper thing.
The code, of course, should flag that the resouce accessed which caused crash is not available - not just silently continue work as if all was ok - the code should handle the exceptional condition, but not hide it - the way as SEH is frequently misused.

NoCforMe

Quote from: jj2007 on March 19, 2015, 11:52:13 AM
It seems, though, that the C/C++ crowd is scared of crashes - whenever you see some piece of C/C++ software in the debugger, the SEH is there. Which doesn't stop such software from hanging, as Adobe, Firefox and others demonstrate far too often. The "don't let it crash" philosophy ends up too often in lousy code.

I don't really want to get that deeply into that discussion--after all, this started out as a thread about MY code!--but philosophically speaking, I find myself agreeing with you here (even though I haven't really thought much about this issue until now).

The most convincing argument to me against using such measures as IsBadxxxPtr(), at least in production code as opposed to debugging, is that business of how it can stop the OS from expanding the stack when needed (by corrupting guard pages) and therefore causing further unintended consequences. As Chen puts it in his blog entry, you had ONE chance to fix things--and you blew it (because such exceptions are only raised once).

All this reminds me of similar error-handling measures during the bad old days of DOS; remember how you could redirect the "fatal error" vector to your code and (at least try to) deal with "Abort/Retry/Ignore" errors? (Usually because of an unreadable or unwritable floppy disk.)  I guess we've come a little ways since then, but it's still nowhere near what you'd call elegant ...
Assembly language programming should be fun. That's why I do it.

Antariy

The stack will grow properly if you use IsBadXXXPtr.
Just try this, it will take some time (maybe half of a minute) to walk through the 512 KBs (half of the default reserved stack size, but take notice that most of that 512 KB are not commited when the program become to check the bytes, so you will see that the program works - the stack grows).

.nolist
include \masm32\include\masm32rt.inc

.686
.xmm
include \masm32\macros\timers.asm
LOOP_COUNT = 10000


.data

.code

start:

    mov ebx,512*1024*1024

    @@:
    mov esi,esp
    invoke IsBadWritePtr,esi,1
    inc esi
    dec ebx
    jnz @B

    invoke MessageBox,0,CTXT("The proggie is still working"),CTXT("Message"),0
    invoke ExitProcess,0
   

end start


If you change the inner loop for an instance as so:

    @@:
    mov esi,esp
    invoke IsBadWritePtr,esi,4096
    add esi,4096
    sub ebx,4096
    jnz @B

The code will walk much more faster, and still it will show that the stack grows - since if you will trust Chen's words the proggie should crash just after couple of iterations of a second inner loop. But it does more that hundred iterations with no crash. And if you will change 512 KBs to let's say 700 KBs (from the default ~meg) it will work the same.

NoCforMe

Well, I have to admit this is over my head now. I'll have to take a look-see at this, figure out what's going on here.

In the meantime, has anyone used my little debugging tool? Like it? Hate it?
Assembly language programming should be fun. That's why I do it.

Antariy

I did not use it as there is no any project I'm working on now, just reading forum and posting some short code. But I think that it is useful to someone who is writing his code and wanting this kind of debugging control over the data variables/structures in the memory.