home *** CD-ROM | disk | FTP | other *** search
- ; Trace back through the function call thread, and return the name of the
- ; function "n" calls up.
- ;
- ; e.g. if you have (in C)
- ;
- ; extern char *caller(int);
- ;
- ; void foo (void)
- ; {
- ; bar();
- ; }
- ;
- ; void bar (void)
- ; {
- ; char *f0 = caller(0);
- ; char *f1 = caller(1);
- ; }
- ;
- ; f0 should contain "bar", and f1 should contain "foo".
- ;
- ; I tend to use caller(1) to debug things like memory problems, where I
- ; use things like
- ;
- ; void *xmalloc(size_t size)
- ; {
- ; void *res = malloc(size);
- ; if (res == NULL)
- ; {
- ; fprintf(stderr, "Error calling malloc(%d) from %s\n",
- ; size, caller(1));
- ; exit(1);
- ; }
- ; return res;
- ; }
- ;
- ; [This use of caller(1) is OK - see below - as it is unlikely that anything
- ; will call xmalloc() and not use the result somehow...]
- ;
- ;
- ; NOTE: This routine RELIES on the Risc-OS Arm procedure call standard
- ; binding (APCS-R). In particular, it will NOT work on code
- ; compiled under Ansi C v2.00 or earlier!
- ;
- ; NOTE: The parameter "n" passed to caller() is NOT always what you might
- ; think! Basically, because Acorn C is very good at optimising tail-
- ; recursive function calls into simple branches. For example, in the
- ; example above, foo() would be optimised to a simple "B bar"
- ; instruction. So f1 will, in fact, be the name of foo()'s caller (or
- ; possibly even further up the calling tree!), rather than "foo".
- ; In general, caller(0) is always safe, and caller(1) is OK in most
- ; cases. caller(n) for n = 2 and above are more risky, basically
- ; getting worse as n increases.
- ;
- ; NOTE: If you "back up" into functions compiled without function names
- ; embedded in the code (eg, C library functions), caller(n) will
- ; CRASH. Sorry - but there is no way that I can see to recognise
- ; this situation...
- ;
- ; (Basically, the usual disclaimers all apply, in spades!).
- ;
-
- a1 RN 0
- a2 RN 1
- a3 RN 2
- a4 RN 3
- v1 RN 4
- v2 RN 5
- v3 RN 6
- v4 RN 7
- v5 RN 8
- v6 RN 9
- sl RN 10
- fp RN 11
- ip RN 12
- sp RN 13
- lr RN 14
- pc RN 15
-
- AREA |Caller|, CODE, READONLY
-
- EXPORT caller
-
- 01
- DCB "caller",0
- ALIGN
- DCD &FF000000 :OR: ( {PC} - %B01 )
-
- caller
- MOVS a2, fp ; If frame pointer is 0 then
- ADREQ a1, null ; there is no backtrace structure
- MOVEQS pc, lr
-
- 02 TEQ a1, #0 ; Go back a1 frames...
- BEQ %F03
- LDR a2, [a2, #-12] ; Get caller's frame pointer
- TEQ a2, #0 ; If 0, no backtrace structure
- ADREQ a1, null
- MOVEQS pc, lr
- SUB a1, a1, #1
- B %B02
-
- 03 LDR a2, [a2] ; Get caller's PC (return data save)
- BIC a2, a2, #&FC000003 ; Convert to an address
- SUB a2, a2, #12 ; Go to return data save instruction
-
- 04 LDR a3, [a2, #-4]! ; Get previous word
- MOV a4, a3, LSR #24 ; Test top 8 bits
- TEQ a4, #&FF ; If they're FF, we've found the name
- BNE %B04
-
- BIC a3, a3, #&FF000000 ; Get the name offset
- SUB a1, a2, a3 ; Point to the caller's name
- MOVS pc, lr ; Return
-
- null
- DCB "",0
- ALIGN
-
- END
-