From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
Subject: Musings on the Think C Debugger
Organization: Kalamazoo College
Date: Thu, 13 Aug 1992 19:16:22 GMT

I often wonder, while I use this way-cool debugger, exactly how it
works.  I'm not a really-low-level Mac hacker, so I have to make a lot
of guesses, and it'd be nice if someone could point out my mistakes.


The source-level debugger works great with my low-level debugger, which
happens to be Macsbug.  There's this kind of separation of levels:  the
debugger switch gets intercepted by Macsbug, as does cmd-power (via
Programmer's Key).  Yet _Debugger, _DebugStr, etc. traps drop me into
Think Debugger.  I'm presuming that the Think Debugger simply patches
those traps, in the context of my app's heap.

But the debugger switch thing confuses me a little.  It's a high-level
interrupt, right?--that's what the NMI means--and so gets routed through
the interrupt vector table that starts at $0000 (or should I say
$0008?).  Bus errors go through the same table.  So the Think Debugger
sets a hook to its own routines at $0008, the bus error vector, and lets
Macsbug keep _its_ hook at the rest of the vectors.  Right?

What other vectors get replaced?  I've seen bus errors, address errors,
and illegal instruction errors get trapped by "ThD", but e.g.
stack-collided-with-heap errors still drop into Macsbug.


Context switching.  If I set a breakpoint, I guess ThD drops a
_Debugger_ trap at that word, and makes sure to flush the instruction
cache and so forth.  When it hits it, it figures out where it came from,
loads in the appropriate source file, and puts the arrow in the right
place.  Ok so far?

Now, as far as the PM is concerned, it's still running _my_app_--last
it knew, it returned from a WaitNextEvent call in my app's event loop,
and you'd think it would expect to get another WaitNextEvent from
_my_app_ again.  Doesn't it get confused when ThD suddenly starts
calling WNE?

OK, I step one instruction.  I guess ThD writes in a _Debugger_ trap,
jumps to my code, executes it, it hits the trap, and the handler
restores the old code that was there.  But how does it do the context
switch?  How does it bring my app's windows to the front?

While my app's sitting at a breakpoint, I flip into ZTerm and check on
my download.  (I can download while doing source-level debugging;  I
love it!)  Now, ZTerm's calling WNE, and each time it does so, the
Process Manager code sends a null event to one background app.  What
happens when my app gets one?  Has the ThD put in code around my event
loop that catches those null events before they get passed on to the
rest of my app, and simply ignores them?  What happens if I have more
than one place where I call WNE?

I'm still sitting at a breakpoint.  When my windows need updating,
doesn't the system "return" from my app's WNE call (which was never
really made in the first place) with an update event?


How does ThD redraw my windows for me!?


Is there some automatic way that the ThD knows what lo-mem globals etc.
to swap in and out when it hits a breakpoint?  Or do the programmers at
Symantec know about some undocumented system call that'll do a context
switch for you?


That's all I can think of now.  Sorry to ramble but it's such a
confusing beast, and I'd like to think that I have _some_ clue about
what's going on behind the scenes.
-- 
 Jamie McCarthy      Internet: k044477@kzoo.edu      AppleLink: j.mccarthy
 Pull down the monuments, and send a postcard back
 For nineteen-ninety-five, I will have the starter pack      - Gang of Four