BPatch functions that block are now locked (on a finer grain than the rest of the...
[dyninst.git] / dyninstAPI_RT / src / RTcommon.c
1 /*
2  * Copyright (c) 1996-2004 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 /* $Id: RTcommon.c,v 1.41 2005/02/25 07:04:47 jaw Exp $ */
43
44 #if defined(i386_unknown_nt4_0)
45 #include <process.h>
46 #define getpid _getpid
47 #else
48 #if !defined(mips_unknown_ce2_11) /*ccw 15 may 2000 : 29 mar 2001*/
49 #include <unistd.h>
50 #endif
51
52 #endif
53 #if !defined(mips_unknown_ce2_11) /*ccw 15 may 2000 : 29 mar 2001*/
54 #include <assert.h>
55 #endif
56
57 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
58
59 /* Stop in some sort of Dyninst-approved fashion */
60 extern void DYNINSTbreakPoint();
61
62 /* Platform-specific initialization */
63 extern void DYNINSTos_init(int calledByFork, int calledByAttach);
64
65 unsigned int DYNINSTversion = 1;
66 unsigned int DYNINSTobsCostLow;
67 unsigned int DYNINSThasInitialized = 0; /* 0 : has not initialized
68                                            2 : initialized by Dyninst
69                                            3 : initialized by Paradyn */
70
71 struct DYNINST_bootstrapStruct DYNINST_bootstrap_info ={0,0,0} ; /*ccw 10 oct 2000 : 29 mar 2001*/
72
73 /* Instrumentation heaps */
74 #if defined( ia64_unknown_linux2_4 )
75
76 /* Yoinked from dyninstAPI/src/arch-ia64.h; the IA-64 requires that
77    instruction be 16-byte aligned, so we have to align the heaps if
78    we want to use them for inferior RPCs. */
79 typedef struct { uint64_t low; uint64_t high; } ia64_bundle_t;
80 ia64_bundle_t DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof( ia64_bundle_t )] __attribute__((aligned));
81 ia64_bundle_t DYNINSTstaticHeap_32K_lowmemHeap_1[32*1024/sizeof( ia64_bundle_t )] __attribute__((aligned));
82 ia64_bundle_t DYNINSTstaticHeap_4M_anyHeap_1[4*1024*1024/sizeof( ia64_bundle_t )] __attribute__((aligned));
83 #else 
84
85 double DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof(double)];
86 double DYNINSTstaticHeap_32K_lowmemHeap_1[32*1024/sizeof(double)];
87 double DYNINSTstaticHeap_4M_anyHeap_1[4*1024*1024/sizeof(double)];
88
89 #endif
90
91 /* Trampoline guard */
92 int DYNINSTtrampGuard=1;
93
94 /* Written to by daemon just before launching an inferior RPC */
95 rpcInfo curRPC = { 0, 0, 0 };
96 unsigned pcAtLastIRPC;  /* just used to check for errors */
97 /* 1 = a trap was ignored and needs to be regenerated
98    0 = there is not a trap that hasn't been processed */
99 int trapNotHandled = 0;
100
101 #ifdef DEBUG_PRINT_RT
102 int DYNINSTdebugPrintRT = 1;
103 #else
104 int DYNINSTdebugPrintRT = 0;
105 #endif
106
107 /* One some platforms we can tell when a fork or exec
108    is occurring through system-provided events. On
109    others we do it ourselves.
110    0: No event
111    1: Called at entry to fork
112    2: Called at exit of fork
113    3: Called at entry to exec
114    4: Called at "exit" of exec
115    5: Called at entry to exit
116 */
117 int DYNINST_instSyscallState = 0;
118 /* And storage for the syscall's arguments (if needed) */
119 void *DYNINST_instSyscallArg1;
120
121 int DYNINST_mutatorPid = -1;
122
123 extern const char V_libdyninstAPI_RT[];
124
125 double DYNINSTdummydouble = 4321.71; /* Global so the compiler won't
126                                         optimize away FP code in initFPU */
127 static void initFPU()
128 {
129        /* Init the FPU.  We've seen bugs with Linux (e.g., Redhat 6.2
130           stock kernel on PIIIs) where processes started by Paradyn
131           started with FPU uninitialized. */
132        double x = 17.1234;
133        DYNINSTdummydouble *= x;
134 }
135
136 #if defined(sparc_sun_solaris2_4) \
137  || defined(i386_unknown_linux2_0) \
138  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
139  || defined(rs6000_ibm_aix4_1)
140 int isMutatedExec = 0;
141 #else
142 void RTmutatedBinary_init() {
143     return;
144 }
145 #endif
146
147 /*
148  * The Dyninst API arranges for this function to be called at the entry to
149  * main().
150  */
151 void DYNINSTinit(int cause, int pid)
152 {
153     int calledByFork = 0, calledByAttach = 0;
154
155     initFPU();
156     
157     DYNINST_mutatorPid = pid;
158     
159 #if defined(sparc_sun_solaris2_4) \
160  || defined(i386_unknown_linux2_0) \
161  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
162  || defined(rs6000_ibm_aix4_1)
163         /* this checks to see if this is a restart or a
164                 normal attach  ccw 19 nov 2001*/
165         
166 /* 
167         isElfFile;
168 #else
169         isXCOFFfile;
170 #endif
171 */
172         if(isMutatedExec){
173                 fflush(stdout);
174                 cause = 9;
175         }
176 #endif
177
178     DYNINSThasInitialized = 2;
179
180     if (cause == 2) calledByFork = 1;
181     else if (cause == 3) calledByAttach = 1;
182     
183     /* sanity check */
184 #if !defined(mips_unknown_ce2_11) /*ccw 15 may 2000 : 29 mar 2001*/
185     assert(sizeof(int64_t) == 8);
186     assert(sizeof(int32_t) == 4);
187 #endif
188     
189 #ifndef mips_unknown_ce2_11 /*ccw 23 july 2001*/
190     RTprintf("%s\n", V_libdyninstAPI_RT);
191 #endif
192     
193     DYNINSTos_init(calledByFork, calledByAttach);
194     
195 #if !defined(mips_unknown_ce2_11) /*ccw 16 may 2000 : 29 mar 2001*/
196     DYNINST_bootstrap_info.pid = getpid();
197 #endif
198     DYNINST_bootstrap_info.ppid = pid;
199     
200     DYNINST_bootstrap_info.event = cause;
201 }
202
203 /* These variables are used to pass arguments into DYNINSTinit
204    when it is called as an _init function */
205 int libdyninstAPI_RT_init_localCause=-1;
206 int libdyninstAPI_RT_init_localPid=-1;
207
208 #if defined(i386_unknown_nt4_0)  /*ccw 13 june 2001*/
209 #include <windows.h>
210
211 /* this function is automatically called when windows loads this dll
212  if we are launching a mutatee to instrument, dyninst will place
213  the correct values in libdyninstAPI_RT_DLL_localPid and
214  libdyninstAPI_RT_DLL_localCause and they will be passed to
215  DYNINSTinit to correctly initialize the dll.  this keeps us
216  from having to instrument two steps from the mutator (load and then 
217  the execution of DYNINSTinit()
218 */
219 int DllMainCalledOnce = 0;
220 BOOL WINAPI DllMain(
221   HINSTANCE hinstDLL,  /* handle to DLL module */
222   DWORD fdwReason,     /* reason for calling function */
223   LPVOID lpvReserved   /* reserved */
224 ){
225         if(DllMainCalledOnce == 0){
226                 DllMainCalledOnce++;
227                 if(libdyninstAPI_RT_init_localPid != -1 || libdyninstAPI_RT_init_localCause != -1){
228                         DYNINSTinit(libdyninstAPI_RT_init_localCause,libdyninstAPI_RT_init_localPid);
229                 }
230         }
231         return 1; 
232 }
233  
234
235 #else
236
237 /* _init table of methods:
238    GCC: link with gcc -shared, and use __attribute__((constructor));
239    AIX: ld with -binitfini:libdyninstAPI_RT_init
240    Solaris: ld with -z initarray=libdyninstAPI_RT_init
241    Linux: ld with -init libdyninstAPI_RT_init
242           gcc with -Wl,-init -Wl,...
243           
244 */
245
246 /* Convince GCC to run _init when the library is loaded */
247 #ifdef __GNUC
248 void libdyninstAPI_RT_init(void) __attribute__ ((constructor));
249 #endif
250
251 /* UNIX-style initialization through _init */
252 int initCalledOnce = 0;
253 void libdyninstAPI_RT_init() {
254     if (initCalledOnce) return;
255     initCalledOnce++;
256 /* Has its own call-once protection, and so can be called here */
257     RTmutatedBinary_init();
258     
259     if(libdyninstAPI_RT_init_localCause != -1 ||
260        libdyninstAPI_RT_init_localPid != -1) {
261         DYNINSTinit(libdyninstAPI_RT_init_localCause,
262                     libdyninstAPI_RT_init_localPid);
263     }
264 }
265
266 #endif
267 /* Does what it's called. Used by the paradyn daemon as a 
268    default in certain cases (MT in particular)
269 */
270
271 int DYNINSTreturnZero()
272 {
273   return 0;
274 }
275
276 /* Used to instrument (and report) the entry of fork */
277 void DYNINST_instForkEntry() {
278     /* Set the state so the mutator knows what's up */
279     DYNINST_instSyscallState = 1;
280     DYNINST_instSyscallArg1 = NULL;
281     /* Stop ourselves */
282     DYNINSTbreakPoint();
283     /* Once the stop completes, clean up */
284     DYNINST_instSyscallState = 0;
285     DYNINST_instSyscallArg1 = NULL;
286 }
287
288        
289 /* Used to instrument (and report) the exit of fork */
290 void DYNINST_instForkExit(void *arg1) {
291     /* Set the state so the mutator knows what's up */
292     
293     DYNINST_instSyscallState = 2;
294     DYNINST_instSyscallArg1 = arg1;
295     /* Stop ourselves */
296     DYNINSTbreakPoint();
297     /* Once the stop completes, clean up */
298     DYNINST_instSyscallState = 0;
299     DYNINST_instSyscallArg1 = NULL;
300 }
301
302        
303 /* Used to instrument (and report) the entry of exec */
304 void DYNINST_instExecEntry(void *arg1) {
305     /* Set the state so the mutator knows what's up */
306     DYNINST_instSyscallState = 3;
307     DYNINST_instSyscallArg1 = arg1;
308     /* Stop ourselves */
309     DYNINSTbreakPoint();
310     /* Once the stop completes, clean up */
311     DYNINST_instSyscallState = 0;
312     DYNINST_instSyscallArg1 = NULL;
313 }
314
315        
316 /* Used to instrument (and report) the exit of exec */
317 void DYNINST_instExecExit(void *arg1) {
318     /* Set the state so the mutator knows what's up */
319     DYNINST_instSyscallState = 4;
320     DYNINST_instSyscallArg1 = arg1;
321     /* Stop ourselves */
322     DYNINSTbreakPoint();
323     /* Once the stop completes, clean up */
324     DYNINST_instSyscallState = 0;
325     DYNINST_instSyscallArg1 = NULL;
326 }
327
328        
329 /* Used to instrument (and report) the entry of exit */
330 void DYNINST_instExitEntry(void *arg1) {
331     /* Set the state so the mutator knows what's up */
332     DYNINST_instSyscallState = 5;
333     DYNINST_instSyscallArg1 = arg1;
334     /* Stop ourselves */
335     DYNINSTbreakPoint();
336     /* Once the stop completes, clean up */
337     DYNINST_instSyscallState = 0;
338     DYNINST_instSyscallArg1 = NULL;
339 }
340
341 void DYNINSTunlock_spinlock(dyninst_spinlock *mut)
342 {
343   mut->lock = 0;
344 }
345
346 extern int DYNINSTwriteEvent(void *ev, int sz); // posix or windows
347 extern void LockCommsMutex();
348 extern void UnlockCommsMutex();
349 unsigned long int getThreadID() {return 0;}
350
351 /* DYNINSTasyncDynFuncCall */
352 /* Used to report addresses of functions called at dynamic call sites */
353        
354 int DYNINSTasyncDynFuncCall (void * call_target, void *call_addr)
355 {
356   int err = 0;
357   rtBPatch_asyncEventRecord ev;
358   BPatch_dynamicCallRecord call_ev;
359
360   LockCommsMutex();
361
362   ev.type = rtBPatch_dynamicCallEvent;
363   ev.pid = getpid();
364   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
365
366   if (err) {
367     fprintf(stderr, "%s[%d]:  write error\n",
368             __FILE__, __LINE__);
369     goto done;
370   }
371
372   call_ev.call_site_addr = call_addr;
373   call_ev.call_target = call_target;
374   err = DYNINSTwriteEvent((void *) &call_ev, sizeof(BPatch_dynamicCallRecord));
375
376   if (err) {
377     fprintf(stderr, "%s[%d]:  write error\n",
378             __FILE__, __LINE__);
379     goto done;
380   }
381
382  done:
383   UnlockCommsMutex();
384   return err;
385 }
386
387 int DYNINSTreportThreadEvent(rtBPatch_asyncEventType t, long unsigned int tid)
388 {
389   int err = 0;
390   rtBPatch_asyncEventRecord ev;
391   BPatch_threadEventRecord thread_ev;
392   ev.type = t;
393   ev.pid = getpid();
394   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
395
396   if (err) {
397     fprintf(stderr, "%s[%d]:  write error\n",
398             __FILE__, __LINE__);
399     goto done;
400   }
401
402   thread_ev.start_func_addr = NULL;
403   thread_ev.tid = tid;
404   err = DYNINSTwriteEvent((void *) &thread_ev, sizeof(BPatch_threadEventRecord));
405   if (err) {
406     fprintf(stderr, "%s[%d]:  write error\n",
407             __FILE__, __LINE__);
408     goto done;
409   }
410
411
412  done:
413   return err;
414 }
415
416 int DYNINSTasyncThreadCreate()
417 {
418   long unsigned int tid;
419   int ret = -1;
420   LockCommsMutex();
421   tid = getThreadID();
422   ret = DYNINSTreportThreadEvent(rtBPatch_threadCreateEvent, tid);
423
424   UnlockCommsMutex();
425   return ret;
426 }
427 int DYNINSTasyncThreadDestroy()
428 {
429   long unsigned int tid;
430   int ret = -1;
431   LockCommsMutex();
432   tid = getThreadID();
433   ret = DYNINSTreportThreadEvent(rtBPatch_threadDestroyEvent, tid);
434   UnlockCommsMutex();
435   return ret;
436 }
437 int DYNINSTasyncThreadStart()
438 {
439   long unsigned int tid;
440   int ret = -1;
441   LockCommsMutex();
442   tid = getThreadID();
443   ret = DYNINSTreportThreadEvent(rtBPatch_threadStartEvent, tid);
444   UnlockCommsMutex();
445   return ret;
446 }
447 int DYNINSTasyncThreadStop()
448 {
449   long unsigned int tid;
450   int ret = -1;
451   LockCommsMutex();
452   tid = getThreadID();
453   ret = DYNINSTreportThreadEvent(rtBPatch_threadStopEvent, tid);
454   UnlockCommsMutex();
455   return ret;
456 }