Fix instrumentation regressions for libc-2.29 on ARM (#653)
[dyninst.git] / dyninstAPI_RT / src / RTcommon.c
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 /* $Id: RTcommon.c,v 1.78 2008/04/15 16:43:44 roundy Exp $ */
32
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <assert.h>
38 #include <string.h>
39 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
40 #include "RTcommon.h"
41 #include "RTthread.h"
42
43 unsigned int DYNINSTobsCostLow;
44 DLLEXPORT unsigned int DYNINSThasInitialized = 0;
45 struct DYNINST_bootstrapStruct DYNINST_bootstrap_info;
46 char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
47 int DYNINSTdebugRTlib = 0;
48
49 DLLEXPORT int DYNINSTstaticMode = 1;
50
51 /**
52  * Allocate the Dyninst heaps
53  *
54  * The IA-64 requires that instruction be 16-byte aligned, so we have to
55  * align the heaps if we want to use them for inferior RPCs.
56  **/
57 #define HEAP_TYPE double
58 #define ALIGN_ATTRIB
59
60 #if defined(os_linux) || defined(os_freebsd)
61 #define HEAP_LOCAL extern
62 #else
63 #define HEAP_LOCAL DLLEXPORT
64 #endif
65
66 HEAP_LOCAL HEAP_TYPE DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
67
68 #if !defined(target_smallmem)
69 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_512K_lowmemHeap_1[512*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
70 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_16M_anyHeap_1[16*1024*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
71 /* These are necessary due to silly C-style 'extern'/linking conventions. */
72 const unsigned long sizeOfLowMemHeap1 = sizeof( DYNINSTstaticHeap_512K_lowmemHeap_1 );
73 const unsigned long sizeOfAnyHeap1 = sizeof( DYNINSTstaticHeap_16M_anyHeap_1 );
74 #else
75 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_8K_lowmemHeap_1[8*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
76 HEAP_LOCAL HEAP_TYPE DYNINSTstaticHeap_32K_anyHeap_1[32*1024/sizeof(HEAP_TYPE)] ALIGN_ATTRIB;
77 /* These are necessary due to silly C-style 'extern'/linking conventions. */
78 const unsigned long sizeOfLowMemHeap1 = sizeof( DYNINSTstaticHeap_8K_lowmemHeap_1 );
79 const unsigned long sizeOfAnyHeap1 = sizeof( DYNINSTstaticHeap_32K_anyHeap_1 );
80 #endif
81
82 /**
83  * One some platforms we can tell when a fork or exec is occurring through
84  * system-provided events. On others we do it ourselves.  Enumerated type
85  * defined in header file
86  **/
87 DLLEXPORT DYNINST_synch_event_t DYNINST_synch_event_id = DSE_undefined;
88 DLLEXPORT void *DYNINST_synch_event_arg1;
89 /* Code to read args 2,3 would have to be moved from dyninstAPI's*/
90 /* process::handleStopThread to signalgenerator::decodeRTSignal in*/
91 /* order for other signals to make use of them, as currently only the*/
92 /* stopThread event needs makes use of them.  */
93 DLLEXPORT void *DYNINST_synch_event_arg2 = NULL; /* not read in dyninst's decodeRTSignal*/
94 DLLEXPORT void *DYNINST_synch_event_arg3 = NULL; /* not read in dyninst's decodeRTSignal*/
95 DLLEXPORT int DYNINST_break_point_event = 0;
96
97 /**
98  * These variables are used to pass arguments into DYNINSTinit
99  * when it is called as an _init function
100  **/
101 int libdyninstAPI_RT_init_localCause=-1;
102 int libdyninstAPI_RT_init_localPid=-1;
103 int libdyninstAPI_RT_init_maxthreads=-1;
104 int libdyninstAPI_RT_init_debug_flag=0;
105
106 int DYNINST_mutatorPid;
107 int DYNINSTdebugPrintRT = 0;
108 int isMutatedExec = 0;
109
110 // stopThread cache variables
111 char cacheLRUflags[TARGET_CACHE_WIDTH];
112 DLLEXPORT void *DYNINST_target_cache[TARGET_CACHE_WIDTH][TARGET_CACHE_WAYS];
113 FILE *stOut;
114 int fakeTickCount;
115
116
117 #ifdef _MSC_VER
118 #define TLS_VAR __declspec(thread)
119 #else
120 // Note, the initial-exec model gives us static TLS which can be accessed
121 // directly, unlike dynamic TLS that calls __tls_get_addr().  Such calls risk
122 // recursing back to us if they're also instrumented, ad infinitum.  Static TLS
123 // must be used very sparingly though, because it is a limited resource.
124 // *** This case is very special -- do not use IE in general libraries! ***
125
126 #if defined(DYNINST_RT_STATIC_LIB)
127 #define TLS_VAR __thread __attribute__ ((tls_model("local-exec")))
128 #else
129 #define TLS_VAR __thread __attribute__ ((tls_model("initial-exec")))
130 #endif
131 #endif
132
133 // It's tempting to make this a char, but glibc < 2.17 hits a bug:
134 //   https://sourceware.org/bugzilla/show_bug.cgi?id=14898
135 static TLS_VAR short DYNINST_tls_tramp_guard = 1;
136
137 DLLEXPORT int DYNINST_lock_tramp_guard()
138 {
139   if(!DYNINST_tls_tramp_guard) return 0;
140   DYNINST_tls_tramp_guard = 0;
141   return 1;
142 }
143 DLLEXPORT void DYNINST_unlock_tramp_guard()
144 {
145   DYNINST_tls_tramp_guard = 1;
146 }
147
148 DECLARE_DYNINST_LOCK(DYNINST_trace_lock);
149
150 /**
151  * Init the FPU.  We've seen bugs with Linux (e.g., Redhat 6.2 stock kernel on
152  * PIIIs) where processes started by Paradyn started with FPU uninitialized.
153  * DYNINSTdummydouble is global so the compiler won't optimize away FP code
154  * in initFPU
155  **/
156 double DYNINSTdummydouble = 4321.71;
157 static void initFPU()
158 {
159    double x = 17.1234;
160    DYNINSTdummydouble *= x;
161 }
162
163 /**
164  * This function is called in both static and dynamic rewriting, on
165  * all platforms that support binary rewriting, but before DYNINSTinit
166  **/
167 void DYNINSTBaseInit()
168 {
169 #if defined(cap_mutatee_traps)
170    DYNINSTinitializeTrapHandler();
171 #endif
172    DYNINST_unlock_tramp_guard();
173    DYNINSThasInitialized = 1;
174
175    RTuntranslatedEntryCounter = 0;
176 }
177
178 /**
179  * The Dyninst API arranges for this function to be called at the entry to
180  * main() via libdyninstAPI_RT_init (defined in RTposix.c and RTwinnt.c).
181  * libdyninstAPI_RT_init is called by one of the following methods:
182  *    GCC: link with gcc -shared, and use __attribute__((constructor));
183  *    Linux: ld with -init libdyninstAPI_RT_init
184  *           gcc with -Wl,-init -Wl,...
185  *    Windows: called from DllMain, which exists in lieu of libdyninstAPI_RT_init
186  *
187  * This is only called in the Dynamic instrumentation case.  Static
188  * libraries don't call this.
189  **/
190 void DYNINSTinit()
191 {
192    rtdebug_printf("%s[%d]:  DYNINSTinit:  welcome to DYNINSTinit()\n", __FILE__, __LINE__);
193    initFPU();
194    mark_heaps_exec();
195
196    tc_lock_init(&DYNINST_trace_lock);
197    DYNINSThasInitialized = 1;
198    rtdebug_printf("%s[%d]:  welcome to DYNINSTinit\n", __FILE__, __LINE__);
199
200    /* sanity check */
201    assert(sizeof(int64_t) == 8);
202    assert(sizeof(int32_t) == 4);
203
204    /* defensive stuff */
205    memset(DYNINST_target_cache,
206           0,
207           sizeof(void*) * TARGET_CACHE_WIDTH * TARGET_CACHE_WAYS);
208    memset(cacheLRUflags, 1, sizeof(char)*TARGET_CACHE_WIDTH);
209    // stOut = fopen("rtdump.txt","w");
210
211    rtdebug_printf("%s[%d]:  leaving DYNINSTinit\n", __FILE__, __LINE__);
212    fakeTickCount=0;
213    /* Memory emulation */
214 }
215
216 /**
217  * Does what it's called. Used by the paradyn daemon as a default in certain
218  * cases (MT in particular)
219  **/
220 int DYNINSTreturnZero()
221 {
222    return 0;
223 }
224
225 /* Used to by dyninst breakpoint snippet */
226 void DYNINST_snippetBreakpoint() {
227    tc_lock_lock(&DYNINST_trace_lock);
228
229    /* Set the state so the mutator knows what's up */
230    DYNINST_synch_event_id = DSE_snippetBreakpoint;
231    DYNINST_synch_event_arg1 = NULL;
232    /* Stop ourselves */
233    DYNINSTbreakPoint();
234    /* Once the stop completes, clean up */
235    DYNINST_synch_event_id = DSE_undefined;
236
237    tc_lock_unlock(&DYNINST_trace_lock);
238 }
239
240 /* Used to instrument (and report) the entry of fork */
241 DLLEXPORT void DYNINST_instForkEntry() {
242    tc_lock_lock(&DYNINST_trace_lock);
243
244    /* Set the state so the mutator knows what's up */
245    DYNINST_synch_event_id = DSE_forkEntry;
246    DYNINST_synch_event_arg1 = NULL;
247    /* Stop ourselves */
248    DYNINSTbreakPoint();
249    /* Once the stop completes, clean up */
250    DYNINST_synch_event_id = DSE_undefined;
251    DYNINST_synch_event_arg1 = NULL;
252
253    tc_lock_unlock(&DYNINST_trace_lock);
254 }
255
256
257 /* Used to instrument (and report) the exit of fork */
258 /* We use the safe breakpoint on the child side of fork
259    as we may not be attached at that point. The parent
260    side uses the normal version. */
261 DLLEXPORT void DYNINST_instForkExit(void *arg1) {
262 //#warning "This function is not implemented for AARCH64 yet!"
263 #if !defined(arch_aarch64)
264    tc_lock_lock(&DYNINST_trace_lock);
265
266    /* Set the state so the mutator knows what's up */
267    DYNINST_synch_event_id = DSE_forkExit;
268    DYNINST_synch_event_arg1 = arg1;
269    /* Stop ourselves */
270    if ((long int)arg1 == 0) {
271        /* Child... */
272        DYNINSTsafeBreakPoint();
273    }
274    else {
275        DYNINSTbreakPoint();
276    }
277    /* Once the stop completes, clean up */
278    DYNINST_synch_event_id = DSE_undefined;
279    DYNINST_synch_event_arg1 = NULL;
280
281    tc_lock_unlock(&DYNINST_trace_lock);
282 #else
283         assert(0);
284 #endif
285 }
286
287
288 /* Used to instrument (and report) the entry of exec */
289 DLLEXPORT void DYNINST_instExecEntry(void *arg1) {
290 //#warning "This function is not implemented for AARCH64 yet!"
291 #if !defined(arch_aarch64)
292    tc_lock_lock(&DYNINST_trace_lock);
293
294    /* Set the state so the mutator knows what's up */
295    DYNINST_synch_event_id = DSE_execEntry;
296    DYNINST_synch_event_arg1 = arg1;
297    /* Stop ourselves */
298    DYNINSTbreakPoint();
299    /* Once the stop completes, clean up */
300    DYNINST_synch_event_id = DSE_undefined;
301    DYNINST_synch_event_arg1 = NULL;
302
303    tc_lock_unlock(&DYNINST_trace_lock);
304 #endif
305 }
306
307
308 /* Used to instrument (and report) the exit of exec */
309 DLLEXPORT void DYNINST_instExecExit(void *arg1) {
310    tc_lock_lock(&DYNINST_trace_lock);
311
312    /* Set the state so the mutator knows what's up */
313    DYNINST_synch_event_id = DSE_execExit;
314    DYNINST_synch_event_arg1 = arg1;
315    /* Stop ourselves */
316    DYNINSTbreakPoint();
317    /* Once the stop completes, clean up */
318    DYNINST_synch_event_id = DSE_undefined;
319    DYNINST_synch_event_arg1 = NULL;
320
321    tc_lock_unlock(&DYNINST_trace_lock);
322 }
323
324
325 /* Used to instrument (and report) the entry of exit */
326 DLLEXPORT void DYNINST_instExitEntry(void *arg1) {
327    tc_lock_lock(&DYNINST_trace_lock);
328
329    /* Set the state so the mutator knows what's up */
330    DYNINST_synch_event_id = DSE_exitEntry;
331    DYNINST_synch_event_arg1 = arg1;
332    /* Stop ourselves */
333    DYNINSTbreakPoint();
334    /* Once the stop completes, clean up */
335    DYNINST_synch_event_id = DSE_undefined;
336    DYNINST_synch_event_arg1 = NULL;
337
338    tc_lock_unlock(&DYNINST_trace_lock);
339 }
340
341 /* Used to instrument (and report) the entry of exit */
342 DLLEXPORT void DYNINST_instLoadLibrary(void *arg1) {
343    tc_lock_lock(&DYNINST_trace_lock);
344
345    /* Set the state so the mutator knows what's up */
346    DYNINST_synch_event_id = DSE_loadLibrary;
347    DYNINST_synch_event_arg1 = arg1;
348    /* Stop ourselves */
349    DYNINSTbreakPoint();
350    /* Once the stop completes, clean up */
351    DYNINST_synch_event_id = DSE_undefined;
352    DYNINST_synch_event_arg1 = NULL;
353
354    tc_lock_unlock(&DYNINST_trace_lock);
355 }
356
357 /* Used to instrument (and report) the entry of exit */
358 DLLEXPORT void DYNINST_instLwpExit(void) {
359    tc_lock_lock(&DYNINST_trace_lock);
360
361    /* Set the state so the mutator knows what's up */
362    DYNINST_synch_event_id = DSE_lwpExit;
363    DYNINST_synch_event_arg1 = NULL;
364    /* Stop ourselves */
365    DYNINSTbreakPoint();
366    /* Once the stop completes, clean up */
367    DYNINST_synch_event_id = DSE_undefined;
368    DYNINST_synch_event_arg1 = NULL;
369
370    tc_lock_unlock(&DYNINST_trace_lock);
371 }
372
373
374 // implementation of an N=2 way associative cache to keep access time low
375 // width = 32
376 // the cache contains valid addresses
377 // add to the cache when an instrumented instruction misses in the cache
378 // update flags for the cache when an instrumented instruction hits in the cache
379 // instrumentation will take the form of a call to cache check
380 RT_Boolean cacheLookup(void *calculation)
381 {
382     int index = ((unsigned long) calculation) % TARGET_CACHE_WIDTH;
383     if (DYNINST_target_cache[index][0] == calculation) {
384         cacheLRUflags[index] = 0;
385         return RT_TRUE;
386     } else if (DYNINST_target_cache[index][1] == calculation) {
387         cacheLRUflags[index] = 1;
388         return RT_TRUE;
389     } else { //miss
390         if (cacheLRUflags[index] == 0) {
391             DYNINST_target_cache[index][1] = calculation;
392             cacheLRUflags[index] = 1;
393         } else {
394             DYNINST_target_cache[index][0] = calculation;
395             cacheLRUflags[index] = 0;
396         }
397         return RT_FALSE;
398     }
399 }
400
401 /**
402  * Receives two snippets as arguments and stops the mutatee
403  * while the mutator reads the arguments, saved to
404  * DYNINST_synch_event... global variables.
405  *
406  * if flag useCache==1, does a cache lookup and stops only
407  * if there is a cache miss
408  *
409  * The flags are:
410  * bit 0: useCache
411  * bit 1: true if interpAsTarget
412  * bit 2: true if interpAsReturnAddr
413  **/
414 //#define STACKDUMP
415 void DYNINST_stopThread (void * pointAddr, void *callBackID,
416                          void *flags, void *calculation)
417 {
418         static int reentrant = 0;
419
420     RT_Boolean isInCache = RT_FALSE;
421
422
423         if (reentrant == 1) {
424                 return;
425         }
426         reentrant = 1;
427     tc_lock_lock(&DYNINST_trace_lock);
428     rtdebug_printf("RT_st: pt[%lx] flags[%lx] calc[%lx] ",
429                    (long)pointAddr, (long)flags, (long)calculation);
430
431 #if 0 && defined STACKDUMP
432     //if (0 && ((unsigned long)calculation == 0x9746a3 ||
433     //          (unsigned long)calculation == 0x77dd761b))
434     //{
435         fprintf(stOut,"RT_st: %lx(%lx)\n", (long)pointAddr,&calculation);
436         fprintf(stOut,"at instr w/ targ=%lx\n",(long)calculation);
437         for (bidx=0; bidx < 0x100; bidx+=4) {
438             fprintf(stOut,"0x%x:  ", (int)stackBase+bidx);
439             fprintf(stOut,"%02hhx", stackBase[bidx]);
440             fprintf(stOut,"%02hhx", stackBase[bidx+1]);
441             fprintf(stOut,"%02hhx", stackBase[bidx+2]);
442             fprintf(stOut,"%02hhx", stackBase[bidx+3]);
443             fprintf(stOut,"\n");
444         }
445     //}
446     // fsg: read from 40a4aa, how did it become 40a380?
447 #endif
448
449     if ((((long)flags) & 0x04) ) {
450         rtdebug_printf("ret-addr stopThread yields %lx", (long)calculation);
451         //fprintf(stderr,"[$0x%lx]\n", (long)calculation);
452     }
453
454     if (0 != (((long)flags) & 0x03)) {
455         // do the lookup if the useCache bit is set, or if it represents
456         // the address of real code, so that we add the address to the cache
457         // even if we will stop the thread if there's a cache hit
458         isInCache = cacheLookup(calculation);
459     }
460
461     // if the cache flag bit is not set, or if we get a cache miss,
462     // stop the thread so that we can call back to the mutatee
463     if (0 == (((long)flags) & 0x01) ||
464         ! isInCache )
465     {
466         /* Set vars for Dyninst to read */
467         DYNINST_synch_event_id = DSE_stopThread;
468         DYNINST_synch_event_arg1 = pointAddr;
469         DYNINST_synch_event_arg2 = callBackID;
470         DYNINST_synch_event_arg3 = calculation;
471
472         // encode interp as target or as return addr by making
473         // callback ID negative
474         if (0 != (((long)flags) & 0x06))
475         {
476             DYNINST_synch_event_arg2 =
477                 (void*) (-1 * (long)DYNINST_synch_event_arg2);
478         }
479
480         rtdebug_printf("stopping! isInCache=%d\n", isInCache);
481
482         /* Stop ourselves */
483         DYNINSTbreakPoint();
484
485         /* Once the stop completes, clean up */
486         DYNINST_synch_event_id = DSE_undefined;
487         DYNINST_synch_event_arg1 = NULL;
488         DYNINST_synch_event_arg2 = NULL;
489         DYNINST_synch_event_arg3 = NULL;
490     }
491     fflush(stOut);
492     tc_lock_unlock(&DYNINST_trace_lock);
493         reentrant = 0;
494     return;
495 }
496
497 // zeroes out the useCache flag if the call is interprocedural
498 void DYNINST_stopInterProc(void * pointAddr, void *callBackID,
499                            void *flags, void *calculation,
500                            void *objStart, void *objEnd)
501 {
502 #if defined STACKDUMP
503     fprintf(stOut,"RT_sip: calc=%lx objStart=%lx objEnd=%lx\n",
504             calculation, objStart, objEnd);
505     fflush(stOut);
506 #endif
507     if (calculation < objStart || calculation >= objEnd) {
508        flags = (void*) ((long) (((int)((long)flags)) & 0xfffffffe));
509     }
510     DYNINST_stopThread(pointAddr, callBackID, flags, calculation);
511 }
512
513 // boundsArray is a sequence of (blockStart,blockEnd) pairs
514 DLLEXPORT RT_Boolean DYNINST_boundsCheck(void **boundsArray_, void *arrayLen_,
515                                          void *writeTarget_)
516 {
517     RT_Boolean callStopThread = RT_FALSE;
518     const unsigned long writeTarget = (unsigned long)writeTarget_;
519     const long arrayLen = (long)arrayLen_;
520     unsigned long *boundsArray = (unsigned long*)boundsArray_;
521     // set idx to halfway into the array, ensuring we use a blockStart address
522     int idx = (int)arrayLen / 4 * 2;
523     int lowIdx = 0;
524     int highIdx = (int)arrayLen;
525     //fprintf(stderr,"D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n", (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
526     //rtdebug_printf("D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n", (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
527     if ((unsigned long)boundsArray < 0x10000000) {
528         printf("D_bc: boundsArray_ = %lx, returning false\n",(unsigned long) boundsArray);
529         return RT_FALSE;
530     }
531     while (lowIdx < highIdx)
532     {
533         if (idx > arrayLen || idx < 0)
534             rtdebug_printf("ERROR: out of bounds idx=%d, arrayLen = %d [%d]\n", idx, arrayLen, __LINE__);
535         rtdebug_printf("D_bc: low=%d high=%d arr[%d]=%lx [%d]\n", lowIdx, highIdx, idx, boundsArray[idx], __LINE__);
536         if (writeTarget < boundsArray[idx]) {
537             rtdebug_printf("D_bc: [%d]\n", __LINE__);
538             highIdx = idx;
539             idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
540         }
541         else if (boundsArray[idx+1] <= writeTarget) {
542             rtdebug_printf("D_bc: [%d]\n", __LINE__);
543             lowIdx = idx+2;
544             idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
545         }
546         else {
547             rtdebug_printf("D_bc: callST=true [%d]\n", __LINE__);
548             callStopThread = RT_TRUE;
549             break;
550         }
551     }
552     rtdebug_printf("D_bc: boundsArray=%p ret=%d [%d]\n", boundsArray, callStopThread, __LINE__);
553     return callStopThread;
554 }
555
556
557 /**
558  * Used to report addresses of functions called at dynamic call sites
559  **/
560 DLLEXPORT int DYNINSTasyncDynFuncCall (void * call_target, void *call_addr) {
561     if (DYNINSTstaticMode) return 0;
562
563     tc_lock_lock(&DYNINST_trace_lock);
564
565     /* Set the state so the mutator knows what's up */
566     DYNINST_synch_event_id = DSE_dynFuncCall;
567     DYNINST_synch_event_arg1 = call_target;
568     DYNINST_synch_event_arg2 = call_addr;
569     /* Stop ourselves */
570     DYNINSTbreakPoint();
571     /* Once the stop completes, clean up */
572     DYNINST_synch_event_id = DSE_undefined;
573     DYNINST_synch_event_arg1 = NULL;
574     DYNINST_synch_event_arg2 = NULL;
575
576     tc_lock_unlock(&DYNINST_trace_lock);
577
578     return 0;
579 }
580
581 int DYNINSTuserMessage(void *msg, unsigned int msg_size) {
582     unsigned long msg_size_long = (unsigned long)msg_size;
583     if (DYNINSTstaticMode)
584         {
585                 return 0;
586         }
587
588     tc_lock_lock(&DYNINST_trace_lock);
589
590
591     /* Set the state so the mutator knows what's up */
592     DYNINST_synch_event_id = DSE_userMessage;
593     DYNINST_synch_event_arg1 = msg;
594     DYNINST_synch_event_arg2 = (void *)msg_size_long;
595     /* Stop ourselves */
596     DYNINSTbreakPoint();
597     /* Once the stop completes, clean up */
598     DYNINST_synch_event_id = DSE_undefined;
599     DYNINST_synch_event_arg1 = NULL;
600     DYNINST_synch_event_arg2 = NULL;
601
602     tc_lock_unlock(&DYNINST_trace_lock);
603
604     return 0;
605 }
606
607 int tc_lock_init(tc_lock_t *t)
608 {
609   t->mutex = 0;
610   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
611   return 0;
612 }
613
614 int tc_lock_unlock(tc_lock_t *t)
615 {
616   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
617   t->mutex = 0;
618   return 0;
619 }
620
621 int tc_lock_destroy(tc_lock_t *t)
622 {
623   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
624   t->mutex = 0;
625   return 0;
626 }
627
628 void dyninst_init_lock(dyninst_lock_t *lock)
629 {
630    lock->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
631    lock->mutex = 0;
632 }
633
634 void dyninst_free_lock(dyninst_lock_t *lock)
635 {
636     (void)lock; /* unused parameter */
637 }
638
639 int dyninst_lock(dyninst_lock_t *lock)
640 {
641    return tc_lock_lock(lock);
642 }
643
644 void dyninst_unlock(dyninst_lock_t *lock)
645 {
646    tc_lock_unlock(lock);
647 }
648
649 int rtdebug_printf(char *format, ...)
650 {
651   int ret;
652   va_list va;
653   if (!DYNINSTdebugRTlib) return 0;
654   if (NULL == format) return DYNINST_PRINTF_ERRVAL;
655
656   fprintf(stderr, "[RTLIB]");
657   va_start(va, format);
658   ret = vfprintf(stderr, format, va);
659   va_end(va);
660
661   return ret;
662 }
663
664 #ifndef CASE_RETURN_STR
665 #define CASE_RETURN_STR(x) case x: return #x
666 #endif
667
668 char *asyncEventType2str(rtBPatch_asyncEventType t)
669 {
670   switch (t) {
671   CASE_RETURN_STR(rtBPatch_nullEvent);
672   CASE_RETURN_STR(rtBPatch_newConnectionEvent);
673   CASE_RETURN_STR(rtBPatch_internalShutDownEvent);
674   CASE_RETURN_STR(rtBPatch_threadCreateEvent);
675   CASE_RETURN_STR(rtBPatch_threadDestroyEvent);
676   CASE_RETURN_STR(rtBPatch_dynamicCallEvent);
677   CASE_RETURN_STR(rtBPatch_userEvent);
678   default: return "bad_async_event_type";
679   }
680 }
681
682 DLLEXPORT volatile unsigned long dyninstTrapTableUsed;
683 DLLEXPORT volatile unsigned long dyninstTrapTableVersion;
684 DLLEXPORT volatile trapMapping_t *dyninstTrapTable;
685 DLLEXPORT volatile unsigned long dyninstTrapTableIsSorted;
686
687 void* dyninstTrapTranslate(void *source,
688                            volatile unsigned long *table_used,
689                            volatile unsigned long *table_version,
690                            volatile trapMapping_t **trap_table,
691                            volatile unsigned long *is_sorted)
692 {
693    volatile unsigned local_version;
694    unsigned i;
695    void *target;
696
697    do {
698       local_version = *table_version;
699       target = NULL;
700
701       if (*is_sorted)
702       {
703          unsigned min = 0;
704          unsigned mid = 0;
705          unsigned max = *table_used;
706          unsigned prev = max+1;
707
708          for (;;) {
709             mid = (min + max) / 2;
710             if (mid == prev) {
711                 fprintf(stderr,"ERROR: dyninstTrapTranslate couldn't find "
712                         "entry for %p: min=%x mid=%x max=%x prev=%x\n",
713                         source,min,mid,max,prev);
714                break;
715             }
716             prev = mid;
717
718             if ((*trap_table)[mid].source < source)
719                min = mid;
720             else if ((*trap_table)[mid].source > source)
721                max = mid;
722             else {
723                target = (*trap_table)[mid].target;
724                break;
725             }
726          }
727       }
728       else { /*!dyninstTrapTableIsSorted*/
729          for (i = 0; i<*table_used; i++) {
730             if ((*trap_table)[i].source == source) {
731                target = (*trap_table)[i].target;
732                break;
733             }
734          }
735       }
736    } while (local_version != *table_version);
737
738    return target;
739 }
740
741 DLLEXPORT void DYNINSTtrapFunction(){
742    __asm__ __volatile__(
743            "nop\n"
744            :::);
745 }
746
747