I have done a commit that fixes the "irpc-trap" bug. This bug occurs
[dyninst.git] / dyninstAPI_RT / src / RTlinux.c
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /************************************************************************
43  * $Id: RTlinux.c,v 1.6 2000/03/17 21:56:19 schendel Exp $
44  * RTlinux.c: mutatee-side library function specific to Linux
45  ************************************************************************/
46
47 #include <signal.h>
48 #include <assert.h>
49 #include <stdio.h>
50 #include <dlfcn.h>
51 #include <link.h>
52
53 #include <sys/ptrace.h>
54
55 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
56
57 /************************************************************************
58  * void DYNINSTos_init(void)
59  *
60  * os initialization function
61 ************************************************************************/
62
63 void DYNINSTtrapHandler(int sig, struct sigcontext uap );
64
65 void
66 DYNINSTos_init(int calledByFork, int calledByAttach)
67 {
68     /*
69        Install trap handler.
70        This is currently being used only on the x86 platform.
71     */
72     
73     struct sigaction act;
74     act.sa_handler = (void(*)(int))DYNINSTtrapHandler;
75     act.sa_flags = 0;
76     sigfillset(&act.sa_mask);
77     if (sigaction(SIGTRAP, &act, 0) != 0) {
78         perror("sigaction(SIGTRAP)");
79         assert(0);
80         abort();
81     }
82     
83     ptrace( PTRACE_TRACEME, 0, 0, 0 );
84 }
85
86
87 \f
88
89
90 /****************************************************************************
91    The trap handler. Currently being used only on x86 platform.
92
93    Traps are used when we can't insert a jump at a point. The trap
94    handler looks up the address of the base tramp for the point that
95    uses the trap, and set the pc to this base tramp.
96    The paradynd is responsible for updating the tramp table when it
97    inserts instrumentation.
98 *****************************************************************************/
99
100 trampTableEntry DYNINSTtrampTable[TRAMPTABLESZ];
101 unsigned DYNINSTtotalTraps = 0;
102
103 static unsigned lookup(unsigned key) {
104     unsigned u;
105     unsigned k;
106     for (u = HASH1(key); 1; u = (u + HASH2(key)) % TRAMPTABLESZ) {
107       k = DYNINSTtrampTable[u].key;
108       if (k == 0)
109         return 0;
110       else if (k == key)
111         return DYNINSTtrampTable[u].val;
112     }
113     /* not reached */
114     assert(0);
115     abort();
116 }
117
118 void DYNINSTtrapHandler(int sig, struct sigcontext uap ) {
119     unsigned pc = uap.eip;
120     unsigned nextpc;
121
122     /* If we're in the process of running an inferior RPC, we'll
123        ignore the trap here and have the daemon rerun the trap
124        instruction when the inferior rpc is done.  Because the default
125        behavior is for the daemon to reset the PC to it's previous
126        value and the PC is still at the trap instruction, we don't
127        need to make any additional adjustments to the PC in the
128        daemon.
129
130        This is used only on x86 platforms, so if multithreading is
131        ever extended to x86 platforms, then perhaps this would need to
132        be modified for that.
133
134        I haven't seen the irpc trap bug with linux version.  This is
135        probably because on linux we have the application's traps sent
136        to the daemon and forwarded back to the application.  However,
137        if trap signals are ever changed to be handled locally by the
138        application, we'll be ready for it.  */
139
140     if(curRPC.runningInferiorRPC == 1) {
141       /* If the current PC is somewhere in the RPC then it's a trap that
142          occurred just before the RPC and is just now getting delivered.
143          That is we want to ignore it here and regenerate it later. */
144       if(curRPC.begRPCAddr <= pc && pc <= curRPC.endRPCAddr) {
145       /* If a previous trap didn't get handled on this next irpc (assumes one 
146          trap per irpc) then we have a bug, a trap didn't get regenerated */
147         /* printf("trapHandler, begRPCAddr: %x, pc: %x, endRPCAddr: %x\n",
148            curRPC.begRPCAddr, pc, curRPC.endRPCAddr);
149         */
150         assert(trapNotHandled==0);
151         trapNotHandled = 1; 
152         return;
153       }
154       else  ;   /* a trap occurred as a result of a function call within the */ 
155                 /* irpc, these traps we want to handle */
156     }
157     else { /* not in an irpc */
158       if(trapNotHandled == 1) {
159         /* Ok good, the trap got regenerated.
160            Check to make sure that this trap is the one corresponding to the 
161            one that needs to get regenerated.
162         */
163         assert(pcAtLastIRPC == pc);
164         trapNotHandled = 0;
165         /* we'll then continue to process the trap */
166       }
167     }
168     nextpc = lookup(pc);
169
170     if (!nextpc) {
171       /* kludge: maybe the PC was not automatically adjusted after the trap */
172       /* this happens for a forked process */
173       pc--;
174       nextpc = lookup(pc);
175     }
176
177     if (nextpc) {
178       /* WARNING -- Remove before using in real use, it could KILL anything
179          that instruments libc */
180       /*fprintf( stderr, "DYNINST trap %#.8x -> %#.8x\n", pc, nextpc );*/
181       uap.eip = nextpc;
182     } else {
183       assert(0);
184       abort();
185     }
186     DYNINSTtotalTraps++;
187 }
188
189 int DYNINSTloadLibrary(char *libname)
190 {
191     void *res;
192
193     res = dlopen( libname, RTLD_NOW | RTLD_GLOBAL );
194
195     if( res == NULL ) {
196         perror( "DYNINSTloadLibrary -- dlopen" );
197         return 0;  // An error has occurred
198     } else
199         return 1;
200
201     /*
202      * All of this is necessary because on linux, dlopen is not in libc, but
203      * in a separate library libdl.  Not all programs are linked with libdl,
204      * but libc does contain the underlying functions.  This is gross and
205      * may break with new versions of glibc.  It is based on glibc 2.0.6
206      */
207 /*
208     struct link_map *new;
209     char *errstr;
210     int err;
211     
212     void doit (void) {
213         new = _dl_open( libname ?: "", RTLD_NOW | RTLD_GLOBAL );
214     }
215
216     err = _dl_catch_error( &errstr, doit );
217     
218     if( errstr == NULL )
219         return 1;
220     else {
221         fprintf( stderr, errstr );
222         free( errstr );
223         return 0;
224     }
225 */
226 }