I finally figured out how to do this. I can now extract arbitrary addresses from forth words with little effort.
As far as I can tell, all words in the OF dictionary have at least some powerpc code in them. Even words such as value and buffer. Calls to another word are usually done with either the b or the bl instruction.
: get-bl-adr dup @ dup 7fffffc and dup 3000000 and if fc000000 or then swap 2 and if swap drop else + then ;
This useful function takes the address to a b or bl instruction and decodes it to get the address it points to. It is meant to be used like this:
' .registers c + get-bl-adr
This retrieves the execution token of the word called ci-regs. ci-regs returns the address of the buffer used to hold the registers of the client interface program in OF. This lets you read and/or modify those registers easily.
Annoyingly, ci-regs does not have an official name on most NewWorld systems. But the code I figured out lets me access it anyways. This means that the trick I am about to describe will (probably) work on all NewWorld Macs.
The following code displays register and call stack information every time the Trampoline calls the client interface function 'open':
: get-bl-adr dup @ dup 7fffffc and dup 3000000 and if fc000000 or then swap 2 and if swap drop else + then ;
' .registers c + get-bl-adr 8 + @ value reg-buf
: print-frame-info dup dup ." @" 8 u.r @ ." SP: " 8 u.r ." CR: " dup 4 + @ 8 u.r ." LR: " dup 8 + @ 8 u.r cr @ ;
: dumpcistack reg-buf 4 + @ begin print-frame-info dup 0= until drop ;
dev /openprom/client-services
: open .registers cr reg-buf 4 + @ ." cur-stack is " 8 u.r cr dumpcistack open ;
mac-boot
Here is an example of its output:
Client's Fix Pt Regs:
00 00000080 0010fcf8 deadbeef 001198c8 001198c4 00000001 0010ff34 001198c8
08 001198d4 0010fd5c 0010fda4 0010ff65 001198b8 00000000 00104800 001047e0
10 00000000 00104798 00000000 001170a0 9e9044d8 9e9044d8 00106b34 00218288
18 0026f1e0 00000000 00000000 001170a4 ffffffff 00119890 001198d8 0010fd60
Special Regs:
%IV: 00000300 %SRR0: 0020dc68 %SRR1: 00003030
%CR: 4884204c %LR: 0020dc68 %CTR: ff80a290 %XER: 00000000
%DAR: 00b94000 %DSISR: 42000000 %SDR1: 1ffe0000
cur-stack is 0010fcf8
@0010fcf8 SP: 0010fd38 CR: 00104798 LR: 00000000
@0010fd38 SP: 00110268 CR: 28242087 LR: 0020a910
@00110268 SP: 00110798 CR: 2884204c LR: 0020b558
@00110798 SP: 00110cc8 CR: 2824204c LR: 0020b480
@00110cc8 SP: 001111f8 CR: 28242086 LR: 0020b558
@001111f8 SP: 00111728 CR: 28242086 LR: 0020b480
@00111728 SP: 00111c58 CR: 28242044 LR: 0020b558
@00111c58 SP: 00112188 CR: 28442087 LR: 0020b558
@00112188 SP: 001126b8 CR: 28242087 LR: 0020b558
@001126b8 SP: 00112be8 CR: 28242087 LR: 0020b558
@00112be8 SP: 00113118 CR: 28242087 LR: 0020b558
@00113118 SP: 00113648 CR: 28242087 LR: 0020b558
@00113648 SP: 00113b78 CR: 28242087 LR: 0020b558
@00113b78 SP: 001140a8 CR: 28242087 LR: 0020b558
@001140a8 SP: 001145d8 CR: 28242087 LR: 0020b558
@001145d8 SP: 00114b08 CR: 28242087 LR: 0020b558
@00114b08 SP: 00115038 CR: 28242087 LR: 0020b558
@00115038 SP: 00115568 CR: 28242082 LR: 0020b558
@00115568 SP: 00115a98 CR: 28242082 LR: 0020b558
@00115a98 SP: 00115fc8 CR: 28242082 LR: 0020b558
@00115fc8 SP: 001164f8 CR: 28242082 LR: 0020b558
@001164f8 SP: 00116a28 CR: 28244082 LR: 0020b480
@00116a28 SP: 00116f78 CR: 8440004c LR: 00205644
@00116f78 SP: 00000000 CR: 00000000 LR: 00000000
I haven't gotten around to it yet, but the stack also stores function parameters and saved registers...