Sets the brk pointer for save-the-world binaries to what it was when each
[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.50 2006/01/13 00:00:48 jodom Exp $ */
43
44 #include <assert.h>\r
45 #include <stdlib.h>
46 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
47 #include "RTcommon.h"
48 #include "RTthread.h"
49
50 unsigned int DYNINSTobsCostLow;
51 unsigned int DYNINSThasInitialized;
52 unsigned DYNINST_max_num_threads;
53 struct DYNINST_bootstrapStruct DYNINST_bootstrap_info;
54 char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
55 void *gBRKptr;
56
57 /**
58  * Allocate the Dyninst heaps
59  * 
60  * The IA-64 requires that instruction be 16-byte aligned, so we have to 
61  * align the heaps if we want to use them for inferior RPCs. 
62  **/
63 #if defined(arch_ia64)
64 typedef struct { uint64_t low; uint64_t high; } ia64_bundle_t;
65 #define HEAP_TYPE ia64_bundle_t
66 #define ALIGN_ATTRIB __attribute((aligned))
67 #else
68 #define HEAP_TYPE double
69 #define ALIGN_ATTRIB 
70 #endif
71
72 HEAP_TYPE DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
73 HEAP_TYPE DYNINSTstaticHeap_32K_lowmemHeap_1[32*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
74 HEAP_TYPE DYNINSTstaticHeap_4M_anyHeap_1[4*1024*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
75
76
77 /**
78  * One some platforms we can tell when a fork or exec is occurring through 
79  * system-provided events. On others we do it ourselves.  Enumerated type 
80  * defined in header file
81  **/
82 DYNINST_synch_event_t DYNINST_synch_event_id = DSE_undefined;
83 void *DYNINST_synch_event_arg1;
84
85 /**
86  * These variables are used to pass arguments into DYNINSTinit
87  * when it is called as an _init function 
88  **/
89 int libdyninstAPI_RT_init_localCause=-1;
90 int libdyninstAPI_RT_init_localPid=-1;
91 int libdyninstAPI_RT_init_maxthreads=-1;
92
93 int DYNINST_mutatorPid;
94 int DYNINSTdebugPrintRT;
95 int isMutatedExec = 0;
96
97 unsigned *DYNINST_tramp_guards;
98
99 tc_lock_t DYNINST_trace_lock;
100
101 /**
102  * Init the FPU.  We've seen bugs with Linux (e.g., Redhat 6.2 stock kernel on 
103  * PIIIs) where processes started by Paradyn started with FPU uninitialized. 
104  * DYNINSTdummydouble is global so the compiler won't optimize away FP code
105  * in initFPU
106  **/
107 double DYNINSTdummydouble = 4321.71;                                    
108 static void initFPU()
109 {
110    double x = 17.1234;
111    DYNINSTdummydouble *= x;
112 }
113
114 static void initTrampGuards(unsigned maxthreads)
115 {
116    unsigned i;
117    //We allocate maxthreads+1 because maxthreads is sometimes used as an
118    //error value to mean we don't know what thread this is.  Sometimes used
119    //during the early setup phases.
120    DYNINST_tramp_guards = (unsigned *) malloc((maxthreads+1)*sizeof(unsigned));
121    for (i=0; i<maxthreads; i++)
122    {
123       DYNINST_tramp_guards[i] = 1;
124    }
125 }
126
127 /**
128  * The Dyninst API arranges for this function to be called at the entry to
129  * main() via libdyninstAPI_RT_init (defined in RTposix.c and RTwinnt.c).
130  * libdyninstAPI_RT_init is called by one of the following methods:
131  *    GCC: link with gcc -shared, and use __attribute__((constructor));
132  *    AIX: ld with -binitfini:libdyninstAPI_RT_init
133  *    Solaris: ld with -z initarray=libdyninstAPI_RT_init
134  *    Linux: ld with -init libdyninstAPI_RT_init
135  *           gcc with -Wl,-init -Wl,...
136  **/
137 void DYNINSTinit(int cause, int pid, int maxthreads)
138 {
139    int calledByFork = 0, calledByAttach = 0;
140    initFPU();
141
142    tc_lock_init(&DYNINST_trace_lock);
143    DYNINST_mutatorPid = pid;
144    
145    if (isMutatedExec) {
146       fflush(stdout);
147       cause = 9;
148    }
149
150    calledByFork = (cause == 2);
151    calledByAttach = (cause == 3);
152    DYNINSThasInitialized = 1;
153    DYNINST_max_num_threads = maxthreads;
154
155    /* sanity check */
156    assert(sizeof(int64_t) == 8);
157    assert(sizeof(int32_t) == 4);
158    
159    RTprintf("%s\n", V_libdyninstAPI_RT);
160    initTrampGuards(DYNINST_max_num_threads);
161
162 #if defined(cap_async_events)
163    DYNINSTasyncConnect(DYNINST_mutatorPid);
164 #endif
165    DYNINSTos_init(calledByFork, calledByAttach);
166    DYNINST_initialize_index_list();
167       
168
169    DYNINST_bootstrap_info.pid = dyn_pid_self();
170    DYNINST_bootstrap_info.ppid = pid;    
171    DYNINST_bootstrap_info.event = cause;
172 }
173
174  
175 /**
176  * Does what it's called. Used by the paradyn daemon as a default in certain 
177  * cases (MT in particular)
178  **/
179 int DYNINSTreturnZero()
180 {
181    return 0;
182 }
183
184 /* Used to instrument (and report) the entry of fork */
185 void DYNINST_instForkEntry() {
186    /* Set the state so the mutator knows what's up */
187    DYNINST_synch_event_id = DSE_forkEntry;
188    DYNINST_synch_event_arg1 = NULL;
189    /* Stop ourselves */
190    DYNINSTbreakPoint();
191    /* Once the stop completes, clean up */
192    DYNINST_synch_event_id = DSE_undefined;
193    DYNINST_synch_event_arg1 = NULL;
194 }
195
196        
197 /* Used to instrument (and report) the exit of fork */
198 void DYNINST_instForkExit(void *arg1) {
199    /* Set the state so the mutator knows what's up */    
200    DYNINST_synch_event_id = DSE_forkExit;
201    DYNINST_synch_event_arg1 = arg1;
202    /* Stop ourselves */
203    DYNINSTbreakPoint();
204    /* Once the stop completes, clean up */
205    DYNINST_synch_event_id = DSE_undefined;
206    DYNINST_synch_event_arg1 = NULL;
207 }
208
209        
210 /* Used to instrument (and report) the entry of exec */
211 void DYNINST_instExecEntry(void *arg1) {
212    /* Set the state so the mutator knows what's up */
213    DYNINST_synch_event_id = DSE_execEntry;
214    DYNINST_synch_event_arg1 = arg1;
215    /* Stop ourselves */
216    DYNINSTbreakPoint();
217    /* Once the stop completes, clean up */
218    DYNINST_synch_event_id = DSE_undefined;
219    DYNINST_synch_event_arg1 = NULL;
220 }
221
222        
223 /* Used to instrument (and report) the exit of exec */
224 void DYNINST_instExecExit(void *arg1) {
225    /* Set the state so the mutator knows what's up */
226    DYNINST_synch_event_id = DSE_execExit;
227    DYNINST_synch_event_arg1 = arg1;
228    /* Stop ourselves */
229    DYNINSTbreakPoint();
230    /* Once the stop completes, clean up */
231    DYNINST_synch_event_id = DSE_undefined;
232    DYNINST_synch_event_arg1 = NULL;
233 }
234
235        
236 /* Used to instrument (and report) the entry of exit */
237 void DYNINST_instExitEntry(void *arg1) {
238    /* Set the state so the mutator knows what's up */
239    DYNINST_synch_event_id = DSE_exitEntry;
240    DYNINST_synch_event_arg1 = arg1;
241    /* Stop ourselves */
242    DYNINSTbreakPoint();
243    /* Once the stop completes, clean up */
244    DYNINST_synch_event_id = DSE_undefined;
245    DYNINST_synch_event_arg1 = NULL;
246 }
247
248 /* Used to instrument (and report) the entry of exit */
249 void DYNINST_instLoadLibrary(void *arg1) {
250    /* Set the state so the mutator knows what's up */
251    DYNINST_synch_event_id = DSE_loadLibrary;
252    DYNINST_synch_event_arg1 = arg1;
253    /* Stop ourselves */
254    DYNINSTbreakPoint();
255    /* Once the stop completes, clean up */
256    DYNINST_synch_event_id = DSE_undefined;
257    DYNINST_synch_event_arg1 = NULL;
258 }
259
260 /**
261  * Used to report addresses of functions called at dynamic call sites 
262  **/     
263 int DYNINSTasyncDynFuncCall (void * call_target, void *call_addr)
264 {
265   int err = 0;
266   int result;
267   rtBPatch_asyncEventRecord ev;
268   BPatch_dynamicCallRecord call_ev;
269
270   result = tc_lock_lock(&DYNINST_trace_lock);
271   if (result == DYNINST_DEAD_LOCK)
272   {
273      fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock\n",
274              __FILE__, __LINE__);
275      return -1;
276   }
277  
278   ev.type = rtBPatch_dynamicCallEvent;
279   ev.pid = dyn_pid_self();
280   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
281
282   if (err) {
283     fprintf(stderr, "%s[%d]:  write error\n",
284             __FILE__, __LINE__);
285     goto done;
286   }
287
288   call_ev.call_site_addr = call_addr;
289   call_ev.call_target = call_target;
290   err = DYNINSTwriteEvent((void *) &call_ev, sizeof(BPatch_dynamicCallRecord));
291
292   if (err) {
293     fprintf(stderr, "%s[%d]:  write error\n",
294             __FILE__, __LINE__);
295     goto done;
296   }
297
298  done:
299   tc_lock_unlock(&DYNINST_trace_lock);
300   return err;
301 }
302
303 int DYNINSTuserMessage(void *msg, unsigned int msg_size)
304 {
305   int err = 0, result;
306   rtBPatch_asyncEventRecord ev;
307
308   result = tc_lock_lock(&DYNINST_trace_lock);
309   if (result == DYNINST_DEAD_LOCK)
310   {
311      fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock\n",
312              __FILE__, __LINE__);
313      return -1;
314   }
315
316   ev.type = rtBPatch_userEvent;
317   ev.pid = dyn_pid_self();
318   ev.size = msg_size;
319   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
320
321   if (err) {
322     fprintf(stderr, "%s[%d]:  write error\n",
323             __FILE__, __LINE__);
324     goto done;
325   }
326
327   err = DYNINSTwriteEvent(msg, msg_size);
328
329   if (err) {
330     fprintf(stderr, "%s[%d]:  write error\n",
331             __FILE__, __LINE__);
332     goto done;
333   }
334
335  done:
336   tc_lock_unlock(&DYNINST_trace_lock);
337   return err;
338 }
339
340 int tc_lock_init(tc_lock_t *t)
341 {
342   t->mutex = 0;
343   t->tid = (dyntid_t) -1;
344   return 0;
345 }
346
347 int tc_lock_unlock(tc_lock_t *t)
348 {
349   t->mutex = 0;
350   t->tid = (dyntid_t) -1;
351   return 0;
352 }
353     
354 int tc_lock_destroy(tc_lock_t *t)
355 {
356   t->mutex = 0;
357   t->tid = (dyntid_t) -1;
358   return 0;
359 }
360
361 void dyninst_init_lock(dyninst_lock_t *lock)
362 {
363    lock->mutex = 0;
364    lock->tid = (dyntid_t) -1;
365 }
366
367 void dyninst_free_lock(dyninst_lock_t *lock)
368 {
369 }
370
371 int dyninst_lock(dyninst_lock_t *lock)
372 {
373    return tc_lock_lock(lock);
374 }
375
376 void dyninst_unlock(dyninst_lock_t *lock)
377 {
378    tc_lock_unlock(lock);
379 }
380
381 unsigned dyninst_maxNumOfThreads()
382 {
383 #if !defined(cap_threads)
384    return 1;
385 #else
386    if (!DYNINSThasInitialized)
387       return 0;
388    if (!DYNINST_multithread_capable)
389       return 1;
390    return DYNINST_max_num_threads;
391 #endif
392 }