27

The early Apple Macintosh computers (original Mac, Mac 512K, Mac Plus) all came with a "Programmer's Switch" installed on the side. I believe this persisted for a long time, with the switch being present on many Macintosh computers for perhaps a decade.

I know that the switch triggers a CPU interrupt, and that this would be used to immediately halt execution and present a debugger interface.

How, exactly, was this enabled and/or controlled by the system software? How can a user modify this behavior? And how was it possible for software developers to override the switch to prevent "hackers" from gaining access to their assembly source code?

6
  • 2
    I don't have a complete answer, but there's no enabling of the programmer's switch, it just generates a higher-priority interrupt than does the internal hardware and therefore takes precedence. A text-based debugger is built into the ROM of the Macintosh 512ke/Plus; I don't know what happens with the original 128k/512k ROM. Are you sure that software developers could override this switch? It feels like a waste of time given that the relatively fast move to hard disks means software wasn't otherwise copy protected, so you could always just disassemble the binary. – Tommy Apr 15 at 16:11
  • 10
    The "switch" was a snap-in piece of plastic that granted the mechanical ability to reach the buttons... The buttons were present and active on every Mac. If you didn't have a Programmer's Switch, you just used a credit card. – Harper - Reinstate Monica Apr 15 at 16:19
  • 18
    "how was it possible for software developers to override the switch to prevent "hackers" from gaining access to their assembly source code?" -- The binary doesn't contain the "assembly source code", just the instructions after assembly. Raw machine code. You don't need a debugger or anything fancy to get to it. Just open the program with a hex editor. Actually making sense of such code is a dark art. There are obfuscation tools out there to make it even harder. But if a dark wizard wanted to disassemble your code, they could and would. With or without a debugger. – RETRAC Apr 15 at 19:08
  • 2
    Worth noting also the interrupt button (along with a reset) was present on Macs all the way through including to the G4 towers. – Simon27 Apr 16 at 9:20
  • 3
    @RETRAC: There are corner cases where interrupting a live system helps, e.g. compressed self-extracting executables, or self-modifying in some way. Without a more-powerful machine (or an interpreter that can use disk storage) that can fully simulate the Mac, this might be the most convenient way to see the actual instructions that really run, if they're not just loaded from a disk file. (And if it lets you single-step, that helps a lot understanding asm.) But yeah, this just gives you machine code which you can disassemble, not asm comments or meaningful names for symbols / branch targets. – Peter Cordes Apr 17 at 4:32
37

The early Apple Macintosh computers (original Mac, Mac 512K, Mac Plus) all came with a "Programmer's Switch" installed on the side.

Yes and no. While the switch was there, it was on the inside, so, not really accessible. Only after being 'enhanced' with the so called 'Programmers Key Aid', a snap on after market piece of plastic, griping into the ventilation slots and providing a pin to press the inside switch.

Well, or by using any small object capable of transferring the needed force (~5N).

I know that the switch triggers a CPU interrupt, and that this would be used to immediately halt execution and present a debugger interface.

Pressing that button raised an NMI (*1). Prior to the Mac Plus hitting NMI ended in the System Error Handler reporting a 'No Debugger Installed' error box. That is as long as no NMI handler (like MacsBug) was installed.

How, exactly, was this enabled and/or controlled by the system software?

It could not be disabled. That's the whole point of having an NMI.

How can a user modify this behavior?

Placing a different code (pointer) at the NMI vector.

And how was it possible for software developers to override the switch to prevent "hackers" from gaining access to their assembly source code?

Assembler source code? Serious, who would deliver the source code of an application?

Also, keep in mind, the classic Mac was a real mode OS. Independent of the CPU used, all memory was shared memory, so a programs code (and data) could be read from any other program (with MacsBug being way more comfortable than MicroBug). So no protection to circumvent in the first place


The NMI function was always there with 68k Macs, but it was the Mac Plus ROM that first contained the so called MicroBug, an always available minimalist debugger. In a developer/debugging environment one would install MacsBug, which hooked NMI. Then again, Bugs may as well happen on user machines, or, as we all know only when the debugger is not installed/active. MicroBug offered a built-in help for these situations to at least peek around and gather basic information. Apple describes its usefulness and handling in Technote 1136.

One noteworthy point is that MicroBug was less integrated and more intrusive to the GUI, as it used GUI functions, but could only react to a very limited number of events, whereas MacsBug used his own screen drawing keeping all GUI data untouched.


*1 - NMI stands for Non Maskable Interrupt, an interrupt that can not be disabled, like any other, but will always make the CPU execute the assigned function. Rather handy to revitalize an otherwise dead system.

5
  • Comments are not for extended discussion; this conversation has been moved to chat. – Chenmunka Apr 17 at 17:42
  • 1
    MacsBug was actually an immensely useful piece of software, especially when it came to understanding what was actually going on on the machine level. The ability to stop and analyze things at the press of a button (later G4 macs actually had that NMI button installed in the front), even while executing OS functions, provided an ideal means to debug system freezes and performance issues. Moreover, its code stepping display was arranged much better than even current gdb output. I still miss MacsBug at times... – cmaster - reinstate monica Apr 17 at 22:05
  • 1
    @cmaster-reinstatemonica "Better than GDB" is a pretty low bar to clear. Anyone who's ever worked with a modern debugger (Visual Studio, Eclipse, JetBrains, etc) and with GDB knows that GDB is abysmal by comparison. – Mason Wheeler Apr 18 at 13:12
  • @MasonWheeler Yes. But one should expect a debugger that is still in wide use today, and which has several decades of active development under its belt, to be significantly better than a discontinued niche debugger that only ever saw real use in the last millennium. – cmaster - reinstate monica Apr 18 at 13:46
  • @cmaster-reinstatemonica Why? I mean, serious, why should it evolve past the bare minimum? It's Unix. it's always only made so far that it barely works, supported by endless scripts. – Raffzahn Apr 18 at 14:42
24

The "programmer's switch" is more technically known as the NMI (Non Maskable Interrupt) switch. It is mapped to a priority 7 interrupt on the 68K CPU, which means it is capable of interrupting anything besides another priority 7 event. When pressed, the CPU saves all its state on the stack, switches to privileged mode, then looks at the interrupt vector table to see what address to find the routine to handle a priority 7 interrupt exception.

Software is capable of changing that address to point to whatever routines might be useful. A common use on the Mac was installing MacsBug, which saved a copy of the screen before overwriting it with a debugger interface; this could be used to step through code, examine memory and variables, and so on.

When the routine ends, it executes a return from exception RTE instruction which reloads the CPU state from the stack and restores the previous execution mode. Before doing this, MacsBug would also restore the screen.

2
  • Would it break if the stack pointer was invalid? No, it doesn't, apparently M68k interrupt vectors contain a stack pointer for the interrupt handler to use instead of the current stack, along with a code pointer. sites.google.com/site/motorolarch/content-section/… / gendev.spritesmind.net/forum/viewtopic.php?t=2202. – Peter Cordes Apr 17 at 4:55
  • Ah, cse.dmu.ac.uk/~sexton/WWWPages/exceptions.html is a clearer description of what exactly gets saves on the supervisor stack. Program counter, then SR (status register), but it doesn't mention the stack pointer. Anyway, hardware interrupt handling only actually saves PC, SR (status register), and maybe SP; it's up to the interrupt handler to manually save as much of the CPU state as it save/restore around its use. Saving/restoring "all its state" happens because of code in the handler, so that's a useful approximation for this answer, but I was curious of the low-level. – Peter Cordes Apr 17 at 5:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.