Fix race condition caused by bad locking in RT library
[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.78 2008/04/15 16:43:44 roundy Exp $ */
43
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <assert.h>
49 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
50 #include "RTcommon.h"
51 #include "RTthread.h"
52
53 #if defined(rs6000_ibm_aix4_1)
54 #include <sys/mman.h>
55 #include <sys/types.h>
56 #endif
57
58 unsigned int DYNINSTobsCostLow;
59 unsigned int DYNINSThasInitialized = 0;
60 unsigned DYNINST_max_num_threads;
61 struct DYNINST_bootstrapStruct DYNINST_bootstrap_info;
62 char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
63 int DYNINSTdebugRTlib;
64
65 dyninst_thread_t *DYNINST_thread_structs;
66 int *DYNINST_thread_hash;
67 unsigned DYNINST_thread_hash_size;
68 int DYNINSTstaticMode = 1;
69
70 /**
71  * Allocate the Dyninst heaps
72  * 
73  * The IA-64 requires that instruction be 16-byte aligned, so we have to 
74  * align the heaps if we want to use them for inferior RPCs. 
75  **/
76 #if defined(arch_ia64)
77 typedef struct { uint64_t low; uint64_t high; } ia64_bundle_t;
78 #define HEAP_TYPE ia64_bundle_t
79 #define ALIGN_ATTRIB __attribute((aligned))
80 #else
81 #define HEAP_TYPE double
82 #define ALIGN_ATTRIB 
83 #endif
84
85 #if defined(os_linux)
86 #define HEAP_LOCAL extern
87 #else
88 #define HEAP_LOCAL
89 #endif
90
91
92 HEAP_LOCAL HEAP_TYPE DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
93 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_512K_lowmemHeap_1[512*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
94 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_16M_anyHeap_1[16*1024*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
95
96 /* These are necessary because of silly C-style 'extern'/linking conventions. */
97 const unsigned long sizeOfLowMemHeap1 = sizeof( DYNINSTstaticHeap_512K_lowmemHeap_1 );
98 const unsigned long sizeOfAnyHeap1 = sizeof( DYNINSTstaticHeap_16M_anyHeap_1 );
99
100 /**
101  * One some platforms we can tell when a fork or exec is occurring through 
102  * system-provided events. On others we do it ourselves.  Enumerated type 
103  * defined in header file
104  **/
105 DYNINST_synch_event_t DYNINST_synch_event_id = DSE_undefined;
106 void *DYNINST_synch_event_arg1;
107 /* Code to read args 2,3 would have to be moved from dyninstAPI's*/
108 /* process::handleStopThread to signalgenerator::decodeRTSignal in*/
109 /* order for other signals to make use of them, as currently only the*/
110 /* stopThread event needs makes use of them.  */
111 void *DYNINST_synch_event_arg2 = NULL; /* not read in dyninst's decodeRTSignal*/
112 void *DYNINST_synch_event_arg3 = NULL; /* not read in dyninst's decodeRTSignal*/
113 int DYNINST_break_point_event = 0;
114
115 /**
116  * These variables are used to pass arguments into DYNINSTinit
117  * when it is called as an _init function 
118  **/
119 int libdyninstAPI_RT_init_localCause=-1;
120 int libdyninstAPI_RT_init_localPid=-1;
121 int libdyninstAPI_RT_init_maxthreads=-1;
122 int libdyninstAPI_RT_init_debug_flag=0;
123
124 int DYNINST_mutatorPid;
125 int DYNINSTdebugPrintRT = 0;
126 int isMutatedExec = 0;
127
128 unsigned *DYNINST_tramp_guards;
129
130 unsigned DYNINST_default_tramp_guards[MAX_THREADS+1];
131
132 #if defined(os_linux)
133 void DYNINSTlinuxBreakPoint();
134 #endif
135
136 DECLARE_DYNINST_LOCK(DYNINST_trace_lock);
137
138 /**
139  * Init the FPU.  We've seen bugs with Linux (e.g., Redhat 6.2 stock kernel on 
140  * PIIIs) where processes started by Paradyn started with FPU uninitialized. 
141  * DYNINSTdummydouble is global so the compiler won't optimize away FP code
142  * in initFPU
143  **/
144 double DYNINSTdummydouble = 4321.71;                                    
145 static void initFPU()
146 {
147    double x = 17.1234;
148    DYNINSTdummydouble *= x;
149 }
150
151 static void initTrampGuards(unsigned maxthreads)
152 {
153
154    unsigned i;
155 #if defined(rs6000_ibm_aix4_1)
156         /*      WHAT IS GOING ON HERE?
157                 For save the world to work, the DYNINST_tramp_guards must be reloaded in the
158                 exact same place when the mutated binary is run.  Normally, DYNINST_tramp_guards
159                 is allocated by malloc (See below).  This does not work for AIX because before
160                 we get to the init section of the RT lib, which reloads DYNINST_tramp_guards, the
161                 address DYNINST_tramp_guards needs to be loaded at has been allocated and is in
162                 use.  To get around this, I am using mmap to allocate DYNINST_tramp_guards on
163                 AIX.  I am allocating to a MAP_VARIABLE location because there is no address that
164                 is always known to be free that we can allocate.  This way, when the init section
165                 of the RT lib is run this address will probably be free (with a little magic in 
166                 loadFile() in RTmutatedBinary_XCOFF.c.
167
168                 Just in case we cannot mmap the space we need here (at this point in execution I
169                 cannot imagine this happening, if you want to do anything useful with Dyninst) I fall
170                 back to malloc and print a warning that save the world will probably not work.
171         */
172         
173 /* http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/genprogc/sys_mem_alloc.htm#HDRA9E4A4C9921SYLV */
174         unsigned int memLoc = sbrk(0);
175         int pageSize = getpagesize();
176         int arraySize = ((maxthreads +1) * sizeof(unsigned));
177         arraySize -= (arraySize  % pageSize);
178         arraySize +=  pageSize;
179
180         /*fprintf(stderr,"TRAMP GUARDS (sbrk 0x%x)\n",sbrk(0));*/
181
182         /*fprintf(stderr, "MMAP: 0x%x,0x%x,,,1,0x0\n",memLoc,arraySize);*/
183         DYNINST_tramp_guards = (unsigned *) mmap(0x0, arraySize, PROT_READ|PROT_WRITE, MAP_VARIABLE|MAP_ANONYMOUS, -1,0x0);
184
185         if (DYNINST_tramp_guards == (unsigned *) -1){
186                 perror("mmap: DYNINST_tramp_guards ");
187                 fprintf(stderr,"Warning: DYNINST_tramp_guards may not be allocated correctly for save the world code!\n");
188                 DYNINST_tramp_guards = (unsigned *) malloc((maxthreads+1)*sizeof(unsigned));
189         }
190
191         /*fprintf(stderr,"TRAMP GUARDS 0x%x (sbrk 0x%x)\n", DYNINST_tramp_guards,sbrk(0));*/
192
193 #else
194    /*We allocate maxthreads+1 because maxthreads is sometimes used as an*/
195    /*error value to mean we don't know what thread this is.  Sometimes used*/
196    /*during the early setup phases.*/
197    if (maxthreads <= MAX_THREADS) {
198       DYNINST_tramp_guards = DYNINST_default_tramp_guards;
199    }
200    else {
201       DYNINST_tramp_guards = (unsigned *) malloc((maxthreads+1)*sizeof(unsigned));
202    }
203 #endif
204    for (i=0; i<maxthreads; i++)
205    {
206       DYNINST_tramp_guards[i] = 1;
207    }
208 }
209
210 /**
211  * This function is called in both static and dynamic rewriting, on
212  * all platforms that support binary rewriting, but before DYNINSTinit
213  **/
214 void DYNINSTBaseInit()
215 {
216    unsigned i;
217    DYNINST_max_num_threads = MAX_THREADS;
218    DYNINST_tramp_guards = DYNINST_default_tramp_guards;
219    for (i=0; i<DYNINST_max_num_threads; i++)
220       DYNINST_tramp_guards[i] = 1;
221 #if defined(cap_mutatee_traps)
222    DYNINSTinitializeTrapHandler();
223 #endif
224    DYNINST_initialize_index_list();
225 }
226
227 /**
228  * The Dyninst API arranges for this function to be called at the entry to
229  * main() via libdyninstAPI_RT_init (defined in RTposix.c and RTwinnt.c).
230  * libdyninstAPI_RT_init is called by one of the following methods:
231  *    GCC: link with gcc -shared, and use __attribute__((constructor));
232  *    AIX: ld with -binitfini:libdyninstAPI_RT_init
233  *    Solaris: ld with -z initarray=libdyninstAPI_RT_init
234  *    Linux: ld with -init libdyninstAPI_RT_init
235  *           gcc with -Wl,-init -Wl,...
236  *
237  * This is only called in the Dynamic instrumentation case.  Static
238  * libraries don't call this.
239  **/
240 void DYNINSTinit(int cause, int pid, int maxthreads, int debug_flag)
241 {
242    int calledByFork = 0, calledByAttach = 0;
243    rtdebug_printf("%s[%d]:  DYNINSTinit:  welcome to DYNINSTinit()\n", __FILE__, __LINE__);
244    initFPU();
245
246    DYNINSTstaticMode = 0;
247    tc_lock_init(&DYNINST_trace_lock);
248    DYNINST_mutatorPid = pid;
249    
250    if (isMutatedExec) {
251       fflush(stdout);
252       cause = 9;
253    }
254
255    calledByFork = (cause == 2);
256    calledByAttach = (cause == 3);
257    DYNINSThasInitialized = 1;
258    DYNINST_max_num_threads = maxthreads;
259    DYNINSTdebugRTlib = debug_flag; /* set by mutator on request */
260    rtdebug_printf("%s[%d]:  welcome to DYNINSTinit\n", __FILE__, __LINE__);
261
262    /* sanity check */
263    assert(sizeof(int64_t) == 8);
264    assert(sizeof(int32_t) == 4);
265    
266    initTrampGuards(DYNINST_max_num_threads);
267
268    DYNINSTos_init(calledByFork, calledByAttach);
269    DYNINST_initialize_index_list();
270
271    DYNINST_bootstrap_info.pid = dyn_pid_self();
272    DYNINST_bootstrap_info.ppid = pid;    
273    DYNINST_bootstrap_info.event = cause;
274    rtdebug_printf("%s[%d]:  leaving DYNINSTinit\n", __FILE__, __LINE__);
275 }
276
277  
278 /**
279  * Does what it's called. Used by the paradyn daemon as a default in certain 
280  * cases (MT in particular)
281  **/
282 int DYNINSTreturnZero()
283 {
284    return 0;
285 }
286
287 /* Used to by dyninst breakpoint snippet */
288 void DYNINST_snippetBreakpoint() {
289    /* Set the state so the mutator knows what's up */
290    DYNINST_synch_event_id = DSE_snippetBreakpoint;
291    DYNINST_synch_event_arg1 = NULL;
292    /* Stop ourselves */
293    DYNINSTbreakPoint();
294    /* Once the stop completes, clean up */
295    DYNINST_synch_event_id = DSE_undefined;
296 }
297
298 /* Used to instrument (and report) the entry of fork */
299 void DYNINST_instForkEntry() {
300    /* Set the state so the mutator knows what's up */
301    DYNINST_synch_event_id = DSE_forkEntry;
302    DYNINST_synch_event_arg1 = NULL;
303    /* Stop ourselves */
304    DYNINSTbreakPoint();
305    /* Once the stop completes, clean up */
306    DYNINST_synch_event_id = DSE_undefined;
307    DYNINST_synch_event_arg1 = NULL;
308 }
309
310        
311 /* Used to instrument (and report) the exit of fork */
312 /* We use the safe breakpoint on the child side of fork
313    as we may not be attached at that point. The parent
314    side uses the normal version. */
315 void DYNINST_instForkExit(void *arg1) {
316    /* Set the state so the mutator knows what's up */    
317    DYNINST_synch_event_id = DSE_forkExit;
318    DYNINST_synch_event_arg1 = arg1;
319    /* Stop ourselves */
320    if ((long int)arg1 == 0) {
321        /* Child... */
322        DYNINSTsafeBreakPoint();
323    }
324    else {
325        DYNINSTbreakPoint();
326    }
327    /* Once the stop completes, clean up */
328    DYNINST_synch_event_id = DSE_undefined;
329    DYNINST_synch_event_arg1 = NULL;
330 }
331
332        
333 /* Used to instrument (and report) the entry of exec */
334 void DYNINST_instExecEntry(void *arg1) {
335    /* Set the state so the mutator knows what's up */
336    DYNINST_synch_event_id = DSE_execEntry;
337    DYNINST_synch_event_arg1 = arg1;
338    /* Stop ourselves */
339 #if defined(os_linux)
340    DYNINSTlinuxBreakPoint();
341 #else
342    DYNINSTbreakPoint();
343 #endif
344    /* Once the stop completes, clean up */
345    DYNINST_synch_event_id = DSE_undefined;
346    DYNINST_synch_event_arg1 = NULL;
347 }
348
349        
350 /* Used to instrument (and report) the exit of exec */
351 void DYNINST_instExecExit(void *arg1) {
352    /* Set the state so the mutator knows what's up */
353    DYNINST_synch_event_id = DSE_execExit;
354    DYNINST_synch_event_arg1 = arg1;
355    /* Stop ourselves */
356    DYNINSTbreakPoint();
357    /* Once the stop completes, clean up */
358    DYNINST_synch_event_id = DSE_undefined;
359    DYNINST_synch_event_arg1 = NULL;
360 }
361
362        
363 /* Used to instrument (and report) the entry of exit */
364 void DYNINST_instExitEntry(void *arg1) {
365    /* Set the state so the mutator knows what's up */
366    DYNINST_synch_event_id = DSE_exitEntry;
367    DYNINST_synch_event_arg1 = arg1;
368    /* Stop ourselves */
369    DYNINSTbreakPoint();
370    /* Once the stop completes, clean up */
371    DYNINST_synch_event_id = DSE_undefined;
372    DYNINST_synch_event_arg1 = NULL;
373 }
374
375 /* Used to instrument (and report) the entry of exit */
376 void DYNINST_instLoadLibrary(void *arg1) {
377    /* Set the state so the mutator knows what's up */
378    DYNINST_synch_event_id = DSE_loadLibrary;
379    DYNINST_synch_event_arg1 = arg1;
380    /* Stop ourselves */
381    DYNINSTbreakPoint();
382    /* Once the stop completes, clean up */
383    DYNINST_synch_event_id = DSE_undefined;
384    DYNINST_synch_event_arg1 = NULL;
385 }
386
387 /* Used to instrument (and report) the entry of exit */
388 void DYNINST_instLwpExit(void) {
389    /* Set the state so the mutator knows what's up */
390    DYNINST_synch_event_id = DSE_lwpExit;
391    DYNINST_synch_event_arg1 = NULL;
392    /* Stop ourselves */
393    DYNINSTbreakPoint();
394    /* Once the stop completes, clean up */
395    DYNINST_synch_event_id = DSE_undefined;
396    DYNINST_synch_event_arg1 = NULL;
397 }
398
399
400 /** 
401  * Receives two snippets as arguments, stops the mutator, and sends
402  * the arguments back to the mutator
403  **/     
404 void DYNINST_stopThread (void * pointAddr, void *callBackID, void *calculation)
405 {
406    /* Set the state so the mutator knows what's up */
407    DYNINST_synch_event_id = DSE_stopThread;
408    DYNINST_synch_event_arg1 = pointAddr;
409    DYNINST_synch_event_arg2 = callBackID;
410    DYNINST_synch_event_arg3 = calculation;
411    /* Stop ourselves */
412    DYNINSTbreakPoint();
413    /* Once the stop completes, clean up */
414    DYNINST_synch_event_id = DSE_undefined;
415    DYNINST_synch_event_arg1 = NULL;
416    DYNINST_synch_event_arg2 = NULL;
417    DYNINST_synch_event_arg3 = NULL;
418 }
419
420
421 /**
422  * Used to report addresses of functions called at dynamic call sites 
423  **/     
424 int DYNINSTasyncDynFuncCall (void * call_target, void *call_addr)
425 {
426   int err = 0;
427   int result;
428   rtBPatch_asyncEventRecord ev;
429   BPatch_dynamicCallRecord call_ev;
430
431   if (DYNINSTstaticMode)
432      return 0;
433
434   rtdebug_printf("%s[%d]:  welcome to DYNINSTasyncDynFuncCall\n", __FILE__, __LINE__);
435   result = tc_lock_lock(&DYNINST_trace_lock);
436   if (result == DYNINST_DEAD_LOCK)
437   {
438      fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock\n",
439              __FILE__, __LINE__);
440      return DYNINST_TRACEPIPE_ERRVAL;
441   }
442  
443   ev.type = rtBPatch_dynamicCallEvent;
444   ev.pid = dyn_pid_self();
445   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
446
447   if (err) {
448     fprintf(stderr, "%s[%d]:  write error\n",
449             __FILE__, __LINE__);
450     goto done;
451   }
452
453   call_ev.call_site_addr = call_addr;
454   call_ev.call_target = call_target;
455   err = DYNINSTwriteEvent((void *) &call_ev, sizeof(BPatch_dynamicCallRecord));
456
457   if (err) {
458     fprintf(stderr, "%s[%d]:  write error\n",
459             __FILE__, __LINE__);
460     goto done;
461   }
462
463  done:
464   tc_lock_unlock(&DYNINST_trace_lock);
465
466   rtdebug_printf("%s[%d]:  leaving DYNINSTasyncDynFuncCall: status = %s\n", 
467                  __FILE__, __LINE__, err ? "error" : "ok");
468   return err;
469 }
470
471 int DYNINSTuserMessage(void *msg, unsigned int msg_size)
472 {
473   int err = 0, result;
474   rtBPatch_asyncEventRecord ev;
475
476   if (DYNINSTstaticMode)
477      return 0;
478
479   rtdebug_printf("%s[%d]:  welcome to DYNINSTuserMessage\n", __FILE__, __LINE__);
480   result = tc_lock_lock(&DYNINST_trace_lock);
481   if (result == DYNINST_DEAD_LOCK)
482   {
483      fprintf(stderr, "[%s:%d] - Error in libdyninstAPI_RT: trace pipe deadlock\n",
484              __FILE__, __LINE__);
485      return DYNINST_TRACEPIPE_ERRVAL;
486   }
487
488   ev.type = rtBPatch_userEvent;
489   ev.pid = dyn_pid_self();
490   ev.size = msg_size;
491   err = DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord));
492
493   if (err) {
494     fprintf(stderr, "%s[%d]:  write error\n",
495             __FILE__, __LINE__);
496     goto done;
497   }
498
499   err = DYNINSTwriteEvent(msg, msg_size);
500
501   if (err) {
502     fprintf(stderr, "%s[%d]:  write error\n",
503             __FILE__, __LINE__);
504     goto done;
505   }
506
507  done:
508   tc_lock_unlock(&DYNINST_trace_lock);
509   rtdebug_printf("%s[%d]:  leaving DYNINSTuserMessage: status = %s\n", 
510                  __FILE__, __LINE__, err ? "error" : "ok");
511   return err;
512 }
513
514 int tc_lock_init(tc_lock_t *t)
515 {
516   t->mutex = 0;
517   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
518   return 0;
519 }
520
521 int tc_lock_unlock(tc_lock_t *t)
522 {
523   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
524   t->mutex = 0;
525   return 0;
526 }
527     
528 int tc_lock_destroy(tc_lock_t *t)
529 {
530   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
531   t->mutex = 0;
532   return 0;
533 }
534
535 void dyninst_init_lock(dyninst_lock_t *lock)
536 {
537    lock->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
538    lock->mutex = 0;
539 }
540
541 void dyninst_free_lock(dyninst_lock_t *lock)
542 {
543 }
544
545 int dyninst_lock(dyninst_lock_t *lock)
546 {
547    return tc_lock_lock(lock);
548 }
549
550 void dyninst_unlock(dyninst_lock_t *lock)
551 {
552    tc_lock_unlock(lock);
553 }
554
555 unsigned dyninst_maxNumOfThreads()
556 {
557 #if !defined(cap_threads)
558    return 1;
559 #else
560    if (!DYNINSThasInitialized)
561       return 0;
562    if (!DYNINST_multithread_capable)
563       return 1;
564    return DYNINST_max_num_threads;
565 #endif
566 }
567
568 #if !(os_solaris==8)
569 int rtdebug_printf(char *format, ...)
570 {
571   int ret;
572   va_list va;
573   if (!DYNINSTdebugRTlib) return 0;
574   if (NULL == format) return DYNINST_PRINTF_ERRVAL;
575
576   fprintf(stderr, "[RTLIB]");
577   va_start(va, format);
578   ret = vfprintf(stderr, format, va);
579   va_end(va);
580
581   return ret;
582 }
583 #endif
584
585 #ifndef CASE_RETURN_STR
586 #define CASE_RETURN_STR(x) case x: return #x
587 #endif
588
589 char *asyncEventType2str(rtBPatch_asyncEventType t)
590 {
591   switch (t) {
592   CASE_RETURN_STR(rtBPatch_nullEvent);
593   CASE_RETURN_STR(rtBPatch_newConnectionEvent);
594   CASE_RETURN_STR(rtBPatch_internalShutDownEvent);
595   CASE_RETURN_STR(rtBPatch_threadCreateEvent);
596   CASE_RETURN_STR(rtBPatch_threadDestroyEvent);
597   CASE_RETURN_STR(rtBPatch_dynamicCallEvent);
598   CASE_RETURN_STR(rtBPatch_userEvent);
599   default: return "bad_async_event_type";
600   }
601
602
603 volatile unsigned long dyninstTrapTableUsed;
604 volatile unsigned long dyninstTrapTableVersion;
605 volatile trapMapping_t *dyninstTrapTable;
606 volatile unsigned long dyninstTrapTableIsSorted;
607
608 void* dyninstTrapTranslate(void *source, 
609                            volatile unsigned long *table_used,
610                            volatile unsigned long *table_version,
611                            volatile trapMapping_t **trap_table,
612                            volatile unsigned long *is_sorted)
613 {
614    volatile unsigned local_version;
615    unsigned i;
616    void *target;
617
618    do {
619       local_version = *table_version;
620       target = NULL;
621
622       if (*is_sorted) 
623       {
624          unsigned min = 0;
625          unsigned mid = 0;
626          unsigned max = *table_used;
627          unsigned prev = max+1;
628          
629          for (;;) {
630             mid = (min + max) / 2;
631             if (mid == prev)
632                break;
633             prev = mid;
634             
635             if ((*trap_table)[mid].source < source)
636                min = mid;
637             else if ((*trap_table)[mid].source > source)
638                max = mid;
639             else {
640                target = (*trap_table)[mid].target;
641                break;
642             }
643          }
644       } 
645       else { /*!dyninstTrapTableIsSorted*/
646          for (i = 0; i<*table_used; i++) {
647             if ((*trap_table)[i].source == source) {
648                target = (*trap_table)[i].target;
649                break;
650             }
651          }
652       }         
653    } while (local_version != *table_version);
654
655    /*   fprintf(stderr, "Mapped %p to %p\n", source, target);*/
656    return target;
657 }
658