March 93 - INSIDE QUICKTIME AND COMPONENT-BASED MANAGERS
INSIDE QUICKTIME AND COMPONENT-BASED MANAGERS
BILL GUSCHWAN
Intercepting the processing of a QuickTime routine enables you to debug the routine,
use the routine in new ways, and better understand QuickTime architecture. To
intercept the routine, you need to know something about its low-level implementation.
This article discusses the low-level implementation of QuickTime routines, and also
describes tools and programming techniques that can be used to debug, modify, and
analyze QuickTime routines. Some of these techniques take advantage of the Component
Manager, and their usefulness will extend beyond QuickTime as future managers
capitalize on components.
As QuickTime routines pass through some common locations, they're accessible to
your application or to a debugger. A QuickTime routine begins with its function name,
as used in your application and defined in the interface files. It usually compiles as an
A-trap and maybe some assembly glue. The routine may call other Macintosh
routines, be affected by global data structures, pass through a grafPort's bottleneck,
or pass through a component's main function. Because you have access to these
locations, you can intercept the processing of the routine, perform your own special
processing, and then allow the normal execution of the routine to continue.
This article's examples use MacsBug and TMON Pro (TMON Professional v. 3.0.1 from
Icom Simulations, Inc.) to intercept and analyze routines. The tools discussed create
resources for both debuggers, though in some situations you'll want to use one
debugger over the other. For example, the language extensibility of TMON Pro's
built-in assembler provides capabilities that other debuggers don't provide. Now let's
get into the practical aspects of analyzing and debugging QuickTime routines.
QUICKTIME A-TRAPS
An A-trap is a two-byte opcode that always begins with the hexadecimal numeral A.
The remaining 12 bits in the opcode identify the particular routine you're calling,
along with other information about the call. A-traps interrupt the normal processing
of the CPU and cause it to jump through a low-memory vector to the trap dispatcher.
The trap dispatcher examines the bit pattern of the opcode to determine the actual
location of the Macintosh routine in memory, and then jumps to it. Almost all
Macintosh Toolbox routines use the A-trap mechanism to jump to their code.
In the early days of the Macintosh, there was one routine name per A-trap, but the
number of routines increased so dramatically that a second mechanism was introduced
to avoid exhausting all the A-traps. This mechanism uses the normal A-trap
mechanism to identify a grouping of routines(usually defined by a specific manager)
and uses selectors located on the stack or in a register to identify the specific routines
within the grouping. QuickTime uses only four A-traps:
• 0xAAAA: Movie Toolbox
• 0xA82A: Component Manager
• 0xAAA3: Image Compression Manager
• 0xABC2: Matrix routines
Using four A-traps for over 500 routines is possible because the interface glue can
push routine selectors into registers or onto the stack. QuickTime picks the routine it
needs to execute from the value of the selector. For example, with the Movie Toolbox,
QuickTime uses a word in the D0 register. So 0x303C and xxxx (the two-byte
selector) appear before the A-trap in the Movies.h file. This disassembles into
MOVE.W #$xxxx, D0. If you want to find out what other opcodes mean, try using the
TMON Pro assembler as described in "TMON Pro Assembler Demo.
On a separate note, components implement routines through selectors as well. In some
ways, a component is not unlike an A-trap. The ramifications of this are discussed
later in the section "Bottlenecks.
TRAPPING COMPILED APPLICATIONS
A QuickTime routine's A-trap provides a common location that your debugger can
interact with. Traditionally, Macintosh developers have used MacsBug to investigate
the flow of A-traps in compiled applications. Knowing the sequence of A-traps needed
to implement specific functionality provides invaluable information exceeding the
scope of even the best documentation.
Let's see what happens when we take the simple QuickTime debugging approach of
breaking on the four A-traps. For example, start with the 0xAAAA trap. If you
perform an " atb _AAAA" and run MoviePlayer, MacsBug is continually invoked. You
can use the debugger to see the selector value that identifies the routine, but unless
you have the interface files in front of you or you memorize the selector values, you
won't be able to tell which QuickTime routine is being called. You can probably
memorize a few routines like EnterMovies, which has a selector value of 1. You could
even record all the A-trap routines (using theatr command), print to a file, and
compare the traps against the interface files. However, these methods leave a lot to be
desired.
Because there's no one-to-one correspondence between A-traps and routines, you need
some tools to facilitate trapping QuickTime applications. To take advantage of trapping
compiled applications, you'd like to be able to do the following:
• Set the A-trap break on the routine name.
• Easily identify the routines in the debugger.
USING 'MXBM' RESOURCESYou can set A-trap breaks on QuickTime routine names
by creating MacsBug macros in the form of 'mxbm' resources. Unfortunately, MacsBug
doesn't ship with the 'mxbm' resources for QuickTime, and creating those resources by
hand would be tedious at best. So I wrote debugit, an MPW tool that converts standard
Macintosh C headers into the resources. The tool and the 'mxbm' resources that are
needed to set QuickTime A-trap breaks are on theDeveloper CD Seriesdisc and
theQuickTime Version 1.5 for Developersdisc. (Also supplied are the 'mxbm'
resources for several other managers that use A-traps with routine selectors.) You
simply place the resources in your Debugger Prefs file using a resource editor and
reboot.
Using MacsBug in this way is still limited because even though you can break on a
routine name, the names of the QuickTime routines aren't displayed when you're in
MacsBug -- only the assembly code is displayed.
TMON PRO ASSEMBLER DEMO
TMON Pro has an assembler/disassembler built in. You can enter TMON Pro, type
hexadecimal machine code, and watch as it's disassembled into assembly. To do this,
you need to make use of TMON Pro's typed windows, which provide alternative views of
the same location in memory. So, if you anchor an Assembly window and a Memory
window at some safe location in memory, you can type machine code in the Memory
window and watch the numbers translate into the assembly routines in the Assembly
window.
TMON Pro sets aside an area of memory for you to play with, identified by the variable
PlayMem. Here's a useful alias that you can install in your TMON script (it assumes
you use the script provided with TMON Pro):
alias PlayTime,
"TopWind .10 ðn New Memory HereHP, :playmem ð
BottomWind .6 ðn New Assembly HereHP,playmem ð
Open Registers #1=#0
Now you can type "PlayTime" at the command line and have a safe area in memory for
exploring the TMON Pro assembler. The PlayTime alias anchors the two windows to the
same place in memory and swaps out the registers so that you don't harm them while
you play (see Figure 1).
Figure 1 TMON Pro Windows
USING A TMON PRO USER AREA
You saw (in "TMON Pro Assembler Demo") how you can type machine code in TMON
Pro and watch it disassemble. While this is fun, its practical use for developers is
limited. The real power of the TMON Pro assembler comes from the extensibility of its
language. With a little work, you canuse TMON Pro to both break on routine names and
display routine names instead of assembly code in the debugger.
To extend the vocabulary of TMON Pro's interactive assembler, you need to create
TMON Pro assembler macros for the A-traps and glue, which TMON Pro disassembles
into the QuickTime function name. TMON Pro looks many instructions ahead to
disassemble the A-trap and glue into the routine name. If you create the requisite 'Asm