[comp.sys.mac.programmer] Toolbox Patching

osborn@ux1.lbl.gov (James R Osborn) (05/29/91)

Just what exactly is the preferred method for applying a
tail patch to a Toolbox routine?  I've read all sorts of
stuff that waves its (metaphorically speaking) hands and
never explicitly says how to do it.  Maybe I've missed a
tech note that describes the process?

Here is something that I have done that worked but seems
incredibly unelegant and kludgey:

using an init (this part seems ok to me):

load the patch routine into the system heap with the init
DetachResource it
HNoPurge it
HLock it
save original trap address in the patch routine's header
set the trap address to point at the patch

then in the patch:

the patch routine gets passed the appropriate arguments
  for the trap being patched
do my preprocessing, whatever it is
set trap address to original trap address (from header)
call trap, passing appropriate arguments, and saving
  result (if necessary)
set trap address back to this patch
return result (if necessary)


Why did I do it this way?  Because I used C and was too lazy
to figure out how to call the trap routine directly myself
using assembly.  I presume the preferred method is to push
the appropriate arguments onto the stack (pascal fashion)
and then JSR to the original trap?  Then I wouldn't be
SetTrapAddress'ing all over the place.

Would my psuedo-code above then be preferred?  (Or am I totally
or even partially blowing it?  8^)

-- James

.------------------------------.--------------------------------------.
| James R. Osborn              | It just goes to show you it's always |
| Lawrence Berkeley Laboratory | something.  Either it's baffling     |
| osborn@ux1.lbl.gov           | tech notes or your mac is smoking.   |
| (415) 548-8464               | It's always something...             |
'------------------------------'--------------------------------------'

CXT105@psuvm.psu.edu (Christopher Tate) (05/29/91)

You might want to download the file "screensaversource.c.hqx" from the
anonymous ftp site at mac.archive.umich.edu.  It's the source code to
a screen saver that I wrote as a project for the Penn State Center for
Academic Computing.  As a screen saver it's no great shakes, but (IMHO)
it's a very clean example of a trap patch.

The code is written for THINK C.  If you're using MPW or Zortech, it'll
probably be kind of tricky to get it working.  THINK C, unlike the others,
generates A4-relative addressing for standalone code, to avoid having to
muck with A5.  However, the actual mechanics of the trap patch should be
fairly evident.

You can find that file in the directory "/mac/development/source".

Also, you may want to get hold of the Usenet Mac Programmers' Guide, a
compilation of useful stuff that has appeared here over the past couple
of years.  It's available from sumex-aim.stanford.edu, and possible from
mac.archive.umich.edu.  The editor is Matt Mora, mxmora@unix.sri.com,
in case you can't find a copy elsewhere.  The UMPG does have a fair
amount of info on trap patching and suchlike.

-------
Christopher Tate                           | Mercy (noun):
                                           |  The infrequent art of turning
  Bitnet: cxt105@psuvm                     |  thumbs-up on your opponent at
  Uucp:   ...!psuvax1!psuvm.bitnet!cxt105  |  the end of your rapier.

dplatt@ntg.com (Dave Platt) (05/30/91)

In article <13613@dog.ee.lbl.gov> osborn@ux1.lbl.gov (James R Osborn) writes:

>Just what exactly is the preferred method for applying a
>tail patch to a Toolbox routine?

There is NO preferred method for tail-patching.  It should not be done.

>                                   I've read all sorts of
>stuff that waves its (metaphorically speaking) hands and
>never explicitly says how to do it.

That's because you shouldn't.

The reason is as follows.  The Mac startup code installs a bunch of
patches, to correct bugs in the ROM toolbox routines and to add new
functionality.  Usually, these patches operate by replacing the affected
routine... when you call the modified trap, the patch code is executed
instead of the code in the ROM.

However, there are cases in which it's undesirable to install this sort
of patch... usually because the bug is buried deep in the middle of a
large routine, and it would be necessary to replace an entire
multi-kilobyte routine to fix the bug.  Instead, the Toolbox maintainers
examine the code in error, find a trap that _it_ calls, and then install
a head patch in that (secondary) trap.  The secondary patch checks the
stack to see where it's being called from.  If it's called from any
location other than the location of the bug, it does nothing... it just
jumps to the original trap-handler.  If it was called from the routine
that has the bug, it runs some code which corrects the effect of the bug
somehow, and then branches to the original trap-handler.

Now... consider what happens if _you_ install a tail-patch to the
secondary trap.  If that trap is called from the buggy code, then your
patch takes control, does something, and then calls the routine it had
superceded... which, in this case, will be the secondary bug-fixing
patch.  This patch will check to see whether it was called from the
location where the bug exists.  The answer will be "no"... because it
was called from _your_ patch.

The result?  If you install a tail-patch on a trap that Apple is using
as a secondary bug-fixer, then you will _disable_ Apple's bug fix!  The
machine on which you're running will probably exhibit odd symptoms, due
to the fact that a necessary patch has been partially or completely
disabled.


>Here is something that I have done that worked but seems
>incredibly unelegant and kludgey:
>
>using an init (this part seems ok to me):
>
>load the patch routine into the system heap with the init
>DetachResource it
>HNoPurge it
>HLock it
>save original trap address in the patch routine's header
>set the trap address to point at the patch
>
>then in the patch:
>
>the patch routine gets passed the appropriate arguments
>  for the trap being patched
>do my preprocessing, whatever it is
>set trap address to original trap address (from header)
>call trap, passing appropriate arguments, and saving
>  result (if necessary)
>set trap address back to this patch
>return result (if necessary)

This is the traditional way to do a tail patch.


>Why did I do it this way?  Because I used C and was too lazy
>to figure out how to call the trap routine directly myself
>using assembly.  I presume the preferred method is to push
>the appropriate arguments onto the stack (pascal fashion)
>and then JSR to the original trap?

As I say, there is _no_ preferred method.  It's a technique which should
not be used.

-- 
Dave Platt                                                VOICE: (415) 813-8917
              Domain: dplatt@ntg.com      UUCP: ...apple!ntg!dplatt
 USNAIL: New Technologies Group Inc. 2468 Embarcardero Way, Palo Alto CA 94303

osborn@ux1.lbl.gov (James R Osborn) (05/30/91)

In article <13613@dog.ee.lbl.gov> osborn@ux1.lbl.gov (James R Osborn) writes:
>
>Just what exactly is the preferred method for applying a
>tail patch to a Toolbox routine?  I've read all sorts of

 ^^^^^^^^^^
OOOPS!  I was blowing it in that I meant to say "HEAD PATCH"!   

>Would my psuedo-code above then be preferred?  (Or am I totally
>or even partially blowing it?  8^)
>
>-- James
>


So am I to understand correctly that my example (according to Dave
Platt) is an ok example of a "TAIL PATCH"?!  OOOOPS!  So I did a tail
patch when I meant to do a head patch - OOOOPS!

Now I think I understand the difference.  So what I really want is to
have the original trap finish up:

Set the trap address to point at my patch
do my thing in my patch
jmp to the original trap so that IT returns to the original caller

Is this right?

Sorry for the blooper  8^(
-- James

.------------------------------.--------------------------------------.
| James R. Osborn              | It just goes to show you it's always |
| Lawrence Berkeley Laboratory | something.  Either it's baffling     |
| osborn@ux1.lbl.gov           | tech notes or your mac is smoking.   |
| (415) 548-8464               | It's always something...             |
'------------------------------'--------------------------------------'

NO wonder my mac is smoking ....

alexr@apple.com (Alexander M. Rosenberg) (05/30/91)

I'm gonna get shot for this, but...

In article <772@goblin.ntg.com>, dplatt@ntg.com (Dave Platt) writes:
> 
> In article <13613@dog.ee.lbl.gov> osborn@ux1.lbl.gov (James R Osborn) writes:
> 
> >Just what exactly is the preferred method for applying a
> >tail patch to a Toolbox routine?
> 
> There is NO preferred method for tail-patching.  It should not be done.
> 

This isn't really true. Rule #627 about tail patching:

If your code _only_ works under System 7.0 anyway (and the patch installation
code aborts if you aren't under 7.0), then _most_ tail patches are safe.

Before you try to tail patch something, watch what SetTrapAddress does. You
may notice that it preserves "come-from" patches (the kind you don't want to
tail patch) for _most_ traps.

Again:

1.) Check before you try.

2.) Only 7.0.

3.) Not official (read: may change).

---------------------------------------------------------------------------
-  Alexander M. Rosenberg  - INTERNET: alexr@apple.com      - Yoyodyne    -
-  330 1/2 Waverley St.    - UUCP:ucbvax!apple!alexr        - Propulsion  -
-  Palo Alto, CA 94301     -                                - Systems     -
-  (415) 329-8463          - Nobody is my employer so       - :-)         -
-  (408) 974-3110          - nobody cares what I say.       -             -

chuck@brain.UUCP (Chuck Shotton) (05/30/91)

In article <772@goblin.ntg.com>, dplatt@ntg.com (Dave Platt) writes:
> This is the traditional way to do a tail patch.
> [deleted]
> As I say, there is _no_ preferred method.  It's a technique which should
> not be used.
> 

Is there a preferred method for patching traps at all? 

-----------------------------------------------------------------------
Chuck Shotton                 Internet:   cshotton@girch1.med.uth.tmc.edu