Debugging Tips
Volume Number: 10
Issue Number: 5
Column Tag: PowerPC Series
Debugging Tips for Mixed Mode 
So that’s what I’m looking at when I crash!
By Dave Falkenburg, Apple Computer, Inc.
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
About the author
For having such short legs, Dave runs well - he’s part of the team which just
shipped Power Macintosh in record time. As keeper of the secrets of the Process
Manager, he’s something of a nexus for the myriad parts of the Macintosh which all
seem to come together in that cauldron of code, a veritable witch’s brew of bat wings
and furless pets. Among other accomplishments, he’s the guy who gave Ron Avitzur his
first PowerPC 601 book.
When writing for Power Macs...
You’ll need several tools. The obvious ones are a Power Macintosh and a
development environment. Also handy, and not so obvious, are some bits and pieces.
develop Issue #17 contains the dis dcmd. ETO #13 and recent developer CDs have
MacsBug 6.5d6 (or later), and it has support for the new Power Macintosh Memory
Manager.
When developing native applications for the Power Macintosh family, it’s pretty
likely that you will stumble upon bugs which get introduced due to misuse of Mixed
Mode Universal Procedure Pointers (UPPs).
Both the calling conventions and instruction set of any function are encoded
within a data structure when that function has been “wrapped” by a UPP - two
essential details which Mixed Mode needs in order to make your applications and
plug-in modules work without knowing the sordid details of the emulator.
In the 68K Macintosh world, parameters to functions generally go on the stack or
in registers, or sometimes both. PowerPC code generally puts all parameters in
registers. On 68K, Pascal and C also have different calling conventions- each language
passes parameters in the reverse order of it’s peer, and Pascal also insists on the
callee cleaning up parameters. PowerPC has a single calling convention, which Mixed
Mode will happily deal with.
Another important point is that PowerPC ProcPtrs aren’t pointers to code, but in
fact, point at a data structure called a transition vector. This essentially makes them
“ProcHandles”. We can take advantage of that when we diagnose crashes.
Another essential thing we rely on is the fact that the PowerPC and 680x0
instruction sets aren’t very similar - if you are looking at some sort of code in
MacsBug, il or dis will probably tell you what kind of code you are looking at. For example, if we look at 680x0 code with dis, we will see something like
the following.
dis 00142028
00142028
00142028 **undefined** | 4e754e56
0014202c **undefined** | fffc48e7
00142030 twi TO_LT|TO_GT,23622098,0x2a2e | 0f082a2e
00142034 **undefined** | 000c286e
00142038 **undefined** | 0010382e
0014203c **undefined** | 0014200d
00142040 subfic r16,r21,0x2a78 | 22152a78
00142044 **undefined** | 0b7c2a81
The same code as viewed with il looks more familiar:
il 0014202A
+15DA 0014202A LINK A6,#$FFFC | 4E56 FFFC
+15DE 0014202E MOVEM.L D4-D7/A4,-(A7) | 48E7 0F08
+15E2 00142032 MOVE.L $000C(A6),D5 | 2A2E 000C
+15E6 00142036 MOVEA.L $0010(A6),A4 | 286E 0010
+15EA 0014203A MOVE.W $0014(A6),D4 | 382E 0014
+15EE 0014203E MOVE.L A5,D0 | 200D
If you aren’t already familiar with the Mixed Mode Manager or the PowerPC
Runtime Architecture, you’ll might want to read more about it in Inside Macintosh:
RISC System Software before reading on.
UPP Basics
Emulated code can always call UPPs “blindly”, that is, without needing to use
CallUniversalProc.
This was a necessary design principle for the emulator, because older
applications, and large portions of the Macintosh Toolbox have no idea they are running
on a PowerPC 601 microprocessor most of the time. JSR-ing through a UPP
essentially executes a trap instruction which transfers control to Mixed Mode. Mixed
Mode converts parameters, calls the PowerPC subroutine, and the returns to the
emulated caller after translating the result code.
This may seem like magic, but is actually more mundane than mysterious. A UPP
data structure starts with a trap (0xAAFE, a.k.a. _MixedModeMagic). When you’re
executing 68K code, and it JSRs through a UPP, the trap gets handled by Mixed Mode.
Mixed Mode checks the rest of the data structure to figure out whether it’s 68K code,
PowerPC code, or both. Mixed Mode then transfers control to the destination code,
moving parameters from one mode to the other. So it might move 68K registers
and/or stack arguments into PowerPC registers, or vice versa. What gets moved
depends on the contents of the procInfo, a data structure which describes where
parameters live, and where they should go.
PowerPC code must always use CallUniversalProc to call code which was passed
as a ProcPtr of unknown type. All code which doesn’t look like a UPP is assumed to be
68K code. This allows a PowerPC-based Dialog Manager to automatically call a
ModalFilterProc regardless of whether or not the application is 68K code or PowerPC
code.
Mixed Mode relies on the procInfo field in order to convert parameters and
function result.
The biggest opportunity for making a mistake is in the creation of procInfo
values. Much of the work has been done for you by Apple engineers in the Universal
Headers. They defined constants and CallXXXProc macros for most of the Toolbox and
OS routines which accept a ProcPtr, and it’s far more trouble-free to use them than to
create your own.
UPP Symptoms
We’ll discuss the problems you can stumble across by breaking down the three
major cases that Mixed Mode must deal with:
68K -> PowerPC, PowerPC -> 68K, and PowerPC -> PowerPC.
In almost all cases, a bad procInfo value is usually fatal, and very difficult to
debug. Your program’s stack can be completely munged beyond all repair. It’s far
easier to check your procInfos up front than to debug a bad one at run time! Always use
the uppXXX, NewXXXProc, and CallXXXProc macros in the Universal Headers to keep
you from screwing this up.
Bad procInfo values usually show up as either a crash with the PC pointing two
bytes into the RoutineDescriptor data structure, or as mysterious crashes which have
unexplained side effects. Remember those Macintosh 128K crashes when you
accidentally slammed into the sound/disk pages? You won’t have any easier of a time
figuring out how you got there, and you don’t even get to see the technicolor snowcrash
or hear the machine-gun sounds.
Here are a variety of situations where something can go wrong. I’ll treat each
one separately.
Calling from 68K to PowerPC
Problem: Calling a PowerPC ProcPtr that hasn’t been wrapped in a
UPP.
You will see a 68K illegal instruction, and the PC will be somewhere in code
where every third longword is a zero.
What’s happening is that Mixed Mode never got the chance to switch modes for
you, so you’re still trying to execute this code with the 68K emulator. That’s
eventually going to generate an error, because the PowerPC instruction set is so
different from the 68K instruction set. You can tell if this is what happened by doing a
dis PC^ in MacsBug. You’ll need the dis dcmd that came with develop Issue #17, or
future developer CDs. If you see something like “mflr r0” then this is probably what
happened.
Problem: Calling a UPP with a bad procInfo
Check your procInfos, because bad ones will almost always get you. I’ve told you
this already, and Imay repeat it a time or two. Check out Inside Macintosh: RISC System
Software, or for information about creating procInfo values.
Calling from PowerPC to 68K
Problem: Calling 68K code as PowerPC code (i.e. you forgot to use
CallUniversalProc)
This will manifest itself as a “spurious interrupt” or “bus error” in older
versions of MacsBug. This usually turns up as a random jump into space. Remember
that PowerPC ProcPtrs are really ProcHandles and the caller will actually dereference
your “LINK #-xx,A6” and try to use it as a pointer.
Take a look at your PC. Are you executing in the 0x4E560000 to 0x4E56FFFF
range? If you are, odds are good that you did a jump into what turns out to have been a
LINK instruction which was incorrectly treated as an address. LINK’s opcode is
0x4E56.
Problem: Calling a UPP with a bad procInfo
Check your procInfos. An incorrectly-formed procInfo will get you. It is OK to
call 68K code directly with CallUniversalProc. That’s because anything that doesn’t
begin with the MixedMode trap instruction is assumed to be 68K code, and that
particular instruction was carefully chosen to not be a likely value to hit by accident.
Calling from PowerPC to PowerPC
I bet you didn’t think of this case. It arises when a PowerPC-based manager must
support both emulated callers, and PowerPC callers.
Problem: Calling a UPP without CallUniversalProc from PowerPC Code
All routine descriptors start with 0xAAFE, which is not only a trap, but also an
illegal instruction for the PowerPC microprocessor.
This will manifest itself as either a PowerPC Illegal Instruction (a.k.a. spurious
interrupt, for you MacsBug fans) or bus error depending on what is going on inside
Mixed Mode at the time. This is similar to the Calling 68K code as PowerPC code above.
If you get an illegal instruction, you can try doing a dm PC-2 and see if you find an
0xAAFE hanging around.
Problem: Calling a PowerPC procPtr as if it were a UPP
This case is pretty easy to spot - you will die in MacsBug with a 68K illegal
instruction error. If you do a dis PC (using those wonderful PowerPC dcmds), you can
see that the emulator is running, but for some reason the PC is pointing at “mflr r0”
and something like “lwz r3,10(r1)”, two things a 680x0 emulator doesn’t know how
to do!
Problem: Calling a routine descriptor with a bad procInfo
Check your procInfos. Got the idea?
More tips and tricks
When developing native applications for Power Macintosh, try to do the following
things to avoid getting into the trouble described above.
• Source level debugging and single stepping are your friends - become familiar
with one of the PowerPC-capable debuggers: CodeWarrior, Macintosh Debugger
for PowerPC, or Jasik’s Debugger. Keep your eyes open for others, as well.
• Try to understand everywhere you use ProcPtrs in your code. This is where all
those seemingly useless naming conventions we all use really pay off, like
naming call function pointers XXXProcPtr, or all global variables gXXX.
• Use the macros provided by in the Universal Headers to avoid botching procInfos.
You can also make your code “universal” by using these macros. That means that
you can compile for 68K or PowerPC without any further modification of your
source code.
Remember, you don’t need to use UPPs internally within your application if the
code type is always known - UPPs are only needed when code can be called from either
side of the mixed mode boundary. Supporting both emulated and PowerPC plug in
modules is a good example of when to use a UPP.
Happy debugging!
For more information on items mentioned above:
CodeWarrior - a development environment from Metrowerks for both 68K and
PowerPC, and it runs native on either platform. Available from the Mail Order Store.
See page 89 for details, or call 310/575-4343.
Macintosh Debugger for PowerPC - a two-machine debugger from Apple. Requires one
Power Macintosh (to debug) and any other Macintosh to do the driving.
Jasik’s Debugger - a two-headed debugger from Steve Jasik, famous for his personal
support. Available from the Mail Order Store. See page 89 for details, or call
310/575-4343. Jasik Designs may be reached at 415/322-1386.
dis dcmd - develop Issue #17, available from Apple.
Debugging On PowerPC, by Dave Falkenburg and Brian Topping - develop Issue #17,
available from Apple.
MacsBug 6.5d6 - ETO #13 and recent developer CDs.