wbp@cuuxb.UUCP (Walt Pesch) (12/05/86)
In article <810@hropus.UUCP> jgy@hropus.UUCP writes: >Can anyone help me with the following problem: I'm looking for a few >lines of C or assembly code which can be used at the top of a function >to get the address of the function which called it. I can then map >this address to the calling functions name using "nm". Oh, well, you asked! Time to get down into the mud... For System V, the following dirty trick should work: When defining the actual function, which is normally passed "n" variables, define the function to have "n+1" variables. By the nature of the stack frame, the "n+1"'th variable will contain the program address for returning. Back up x words for the length of the jump instruction, and call "nm"... good luck. This is an interesting way to get at the entire stack frame, and needless to say, all sorts of fun! A generic System V stack frame look like: <n words of passing parameters> program address (address after call) saved ap (start of previous frame) saved fp (start of previous frame's automatics and temporaries) <n words for saving registers> <automatic and temporary variables> | | Stack Growth V I don't know if the same trick will work with BSD or any of the other <a-hem> variants. And life is too short to RTFS the BSD internals, so I'll leave it to someone else to comment on how to do "it" on other forms of Unix. Walt Pesch {ihnp4,akgua,et al}!cuuxb!wbp cuuxb!wbp@lll-crg
gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/05/86)
In article <961@cuuxb.UUCP> wbp@cuuxb.UUCP (Walt Pesch) writes: >... A generic System V stack frame look like: It is perhaps worth pointing out for people who aren't really into language technology that there is no such thing as a "generic" System V stack frame. Such details are necessarily implementation- specific. The classic reference for this is Bell Labs CSTR No. 102, "The C Language Calling Sequence" by S. C. Johnson and D. M. Ritchie.
chris@mimsy.UUCP (Chris Torek) (12/05/86)
In article <961@cuuxb.UUCP> wbp@cuuxb.UUCP (Walt Pesch) writes: >Oh, well, you asked! Time to get down into the mud... For System V, >the following dirty trick should work: Getting down in the mud is right; this kind of thing is hardly portable. But `for System V' is not true: The operation is *machine* specific, not *operating system* specific (though there are machines on which the operating system might affect the method). Here is some 4.2/4.3BSD Vax Unix code to do the trick. #include <stdio.h> #include <sys/types.h> #include <machine/frame.h> main() { f(); g(); exit(0); } f() { g(); } g() { register struct frame *fr; /* r11 */ asm(" movl fp,r11"); /* set fr=frame */ printf("g: will return to address %x\n", fr->fr_savpc); } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) UUCP: seismo!mimsy!chris ARPA/CSNet: chris@mimsy.umd.edu
greg@utcsri.UUCP (Gregory Smith) (12/06/86)
In article <961@cuuxb.UUCP> wbp@cuuxb.UUCP (Walt Pesch) writes: >In article <810@hropus.UUCP> jgy@hropus.UUCP writes: >>Can anyone help me with the following problem: I'm looking for a few >>lines of C or assembly code which can be used at the top of a function >>to get the address of the function which called it. I can then map >>this address to the calling functions name using "nm". > >Oh, well, you asked! Time to get down into the mud... For System V, >the following dirty trick should work: > >When defining the actual function, which is normally passed "n" >variables, define the function to have "n+1" variables. By the nature >of the stack frame, the "n+1"'th variable will contain the program >address for returning. Not on anything I've seen. The n+1'th parameter will be part of the caller's auto or temp space. What you need is the 'zeroth' parameter: foo(a,b) any a,b; { char **klugepointer =( (char **)&a) -1; This sets klugepointer to an address one 'char *' lower than the address of the first parameter - this will point to the return address on many machines. More directly: char *retadress = ( (char**) &a )[-1]; This return address will be somewhere within the calling routine. You can use that to find the caller's name. If you can look at the next stack frame down, you can find the address to return from the caller. This will allow you to locate the subroutine call which activated the caller. The caller's start address will be contained in this instruction ( or can be calculated from it ). This is assuming that the caller was normally called, of course. There may be >1 type of call instruction. If these are of different lengths, you cannot determine the beginning of the instruction given the address of the next instruction (i.e. the return address). You will need a 3B2 machine-language reference and some sample assembler output from cc to complete this fearsome, grisly mission if you choose to accept it. Of course, don't expect it to port to a different compiler, let alone a different machine. -- ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg Have vAX, will hack...
ggs@ulysses.UUCP (Griff Smith) (12/06/86)
> In article <810@hropus.UUCP> jgy@hropus.UUCP writes: > >Can anyone help me with the following problem: I'm looking for a few > >lines of C or assembly code which can be used at the top of a function > >to get the address of the function which called it. > > Oh, well, you asked! Time to get down into the mud... For System V, > the following dirty trick should work: > ... > A generic System V stack frame looks like: > > <n words of passing parameters> > program address (address after call) > saved ap (start of previous frame) > saved fp (start of previous frame's automatics and temporaries) > <n words for saving registers> > <automatic and temporary variables> > | > | Stack Growth > V > > I don't know if the same trick will work with BSD or any of the other > <a-hem> variants. And life is too short to RTFS the BSD internals, so > I'll leave it to someone else to comment on how to do "it" on other > forms of Unix. > > Walt Pesch > {ihnp4,akgua,et al}!cuuxb!wbp > cuuxb!wbp@lll-crg Er, ah, I understand the company policy that UNIX(R) = System V (don't agree with it, but understand it), but saying UNIX = System V running on a 3B2 is carrying company loyalty a bit too far. System V (or BSD, for that matter) on a VAX, or a CCI POWER 6/32 (plus many others) grows the stack the other way, so you can't access the return address as an extra arg. You can't easily find the return address when given only the argument list; you need the value of the frame pointer. If you really must have the return address, write a short assembly language function that finds the caller of ITS caller by following the frame pointer. Make sure you use a different version of the function for each machine you want to run it on. Better yet, use a debugging tool that knows what it's doing and quit fooling with machine- specific hacks. -- Griff Smith AT&T (Bell Laboratories), Murray Hill Phone: (201) 582-7736 UUCP: {allegra|ihnp4}!ulysses!ggs Internet: ggs@ulysses.uucp
tim@hoptoad.uucp (Tim Maroney) (12/06/86)
There is a portable and clean way to implement a routine finding out the address of its caller in a few lines of code. It involves no assembly language or machine assumptions. Simply pass the address of the calling routine as an argument to the routine that needs the address. foo() { nmuser(foo); } nmuser(f) int (*f)(); { /* whatever you are doing using nm */ } This can be fooled, but an assembly-language caller can easily fool the other scheme as well by putting a spurious return address on the stack. -- Tim Maroney, Electronic Village Idiot {ihnp4,sun,well,ptsfa,lll-crg,frog}!hoptoad!tim (uucp) hoptoad!tim@lll-crg (arpa)
mac@esl.UUCP (Mike McNamara) (12/06/86)
In article <5428@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >It is perhaps worth pointing out for people who aren't really into >language technology that there is no such thing as a "generic" >System V stack frame. Such details are necessarily implementation- >specific. The classic reference for this is Bell Labs CSTR No. 102, >"The C Language Calling Sequence" by S. C. Johnson and D. M. Ritchie. Actually, the _important_ reference is, as Chris Torek pointed out, /usr/include/machine/frame.h, or equivilent. This tells you what your machine does. = = = = -- Michael Mc Namara ESL Incorporated ARPA: mac%esl@lll-lcc.ARPA
wbp@cuuxb.UUCP (Walt Pesch) (12/08/86)
This is what I get for looking at too many 3B crash dumps - it gets to you after a while. Y'all are right, the stack frame is not only dependant on the OS but also very much machine specific. For AT&T SV releases on the 3B line, the Stack Frame does look like what I showed, and it does grow downwards. For the AT&T System V on the Vax, it still looks the same but grows upwards (97% certainty). For anything else, my advice would be to get into crash and dump the stack for a couple of procs and figure it out yourself. If you're lucky, the stack dump will also contain a pretty picture showing yoy exactly what to look for. Walt Pesch {ihnp4,akgua,et al}!cuuxb!wbp cuuxb!wbp@lll-crg
wbp@cuuxb.UUCP (Walt Pesch) (12/08/86)
This is what I get for looking at too many 3B crash dumps - it gets to you after a while. Y'all are right, the stack frame is not only dependant on the OS but also very much machine specific. For AT&T SV releases on the 3B line, the Stack Frame does look like what I showed, and it does grow downwards in memory (i.e. the stack pointer is incremented in a push operation). For the AT&T System V on the Vax, it still looks the same but grows upwards in memory (i.e. the stack pointer is decremented in a puch operation). For anything else, my advice would be to get into crash and dump the stack for a couple of procs and figure it out yourself. If you're lucky, the stack dump will also contain a pretty picture showing yoy exactly what to look for. Walt Pesch {ihnp4,akgua,et al}!cuuxb!wbp cuuxb!wbp@lll-crg
billc@blia.BLI.COM (Bill Coffin) (12/10/86)
People have been talking about the caller's-address problem as if it were machine-dependent or operating-system dependent. Not so. It is a compiler-dependent problem. I guarantee you that a compiler generating different frame-handling code will break any scheme that gets the functions' return address. Further, any compiler that can emulate a stack architecture and do reasonable frame handling will enable solution of the problem; we have solved this problem on VM/CMS -- a non-stack architecture. Getting the caller's address is dependent entirely on the code generated by the compiler. <vanilla disclaimer>
dave@lsuc.UUCP (12/16/86)
I just came across this code I wrote 5 years ago on a PDP-11/45 running v6: / returns the address of the caller's return pointer .globl _pcret _pcret: mov 2(r5),r0 / pc of caller of caller rts pc Looking back at the application, I see now that doing it this way was silly as well as non-portable. I wanted a function to do different things depending on which function called it. Much better just to pass that information as an argument. However, if anyone out there has a PDP-11 running v6, this might work. Call it pcret.s and invoke it as pcret(), of course. David Sherman Toronto -- { ihnp4!utzoo seismo!mnetor utai watmath decvax!utcsri } !lsuc!dave