From rusmv1!iraun1.ira.uka.de!sol.ctr.columbia.edu!zaphod.mps.ohio-state.edu!wupost!uunet!mcsun!ukc!slxsys!ibmpcug!demon!news Mon Sep  9 14:35:29 MET 1991
Article: 1525 of comp.sys.acorn
Path: rusmv1!iraun1.ira.uka.de!sol.ctr.columbia.edu!zaphod.mps.ohio-state.edu!wupost!uunet!mcsun!ukc!slxsys!ibmpcug!demon!news
From: pmoore@cix.compulink.co.uk (Paul Moore)
Newsgroups: comp.sys.acorn
Subject: Re: "C" __FUNC__
Message-ID: <1991Sep02.234251.24067@demon.co.uk>
Date: 2 Sep 91 23:42:51 GMT
Sender: news@demon.co.uk (C-News Owner)
Reply-To: Paul Moore <pmoore@cix.compulink.co.uk>
Organization: Gated to News by demon.co.uk
Lines: 178


In his message, Gavin.Flower@comp.vuw.ac.nz (Gavin Flower) writes:

> I would find it very useful, for diagnostic purposes,
> to have a macro __FUNC__ that would expand out
> to the name of function that contained it.

I can't do it as a macro, but here's a little assembler routine which
returns the name of the function which called it. It relies on the Arm
procedure call standard, plus the backtrace data stored by C (the stuff
which the -ff flag omits!). I don't know whether the format of the
backtrace data is "standard", but I've seen it documented in a couple
of places - anyone  at Acorn care to comment? See the chunk of data
between labels 'name' and 'caller' in the stuff below, for an example...

I know I shouldn't really include code here, but it's only teeny, so I
hope it's OK...

I include ObjAsm source code, and for those without ObjAsm, the
uuencoded object file, O.Caller. Just link the latter with your program,
and user as shown in the comments at the top of the source.

Enjoy!

Gustav

---------------------------------------------------------------------------
Paul Moore                  | "If you could have any amount of money...
pmoore@cix.compulink.co.uk  |  any amount of money at all...
gustav@tharr.UUCP           |  how much would you want?"
----------------------------| "All of it."
Opinions? Not me, surely?   | Cerebus, Church & State.
---------------------------------------------------------------------------

----------------------- ObjAsm source code -----------------------

; 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

---------- Uuencoded version of the compiled result...  ----------

begin 644 O.Caller
MQ<;+PP<````%````3T)*7TA%041\````+````$]"2E]!4D5!J````&0```!/
M0DI?4UE-5`P!```@````3T)*7U-44E0L`0``$````$]"2E])1$9./`$``"@`
M``!5;G5S960@(```````````56YU<V5D("```````````(#0XL5X`````0``
M``(````````````````````"(@``9```````````````8V%L;&5R```(``#_
M"Q"PX4@`CP(.\+`!```PXP4```H,$!'E```QXS``CP(.\+`!`0!`XO?__^H`
M$)'D_Q/!XPP00>($(#'E(CR@X?\`,^/[__\:_R3"XP(`0>`.\+#A````````
M```!```````````````(`````P````P`````````0V%L;&5R``!C86QL97(`
I`$%232!!3T8@36%C<F\@07-S96UB;&5R(%9E<G-I;VX@,2XT-@``````
`
end

-------------------------- End of code ---------------------------


