rebased to master after sw 3rd party completed
[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 #if defined(_MSC_VER)
118 #define TLS_VAR __declspec(thread)
119 #else
120 #define TLS_VAR __thread
121 #endif
122
123 TLS_VAR int DYNINST_tls_tramp_guard = 1;
124
125 DLLEXPORT int DYNINST_lock_tramp_guard()
126 {
127   if(!DYNINST_tls_tramp_guard) return 0;
128   DYNINST_tls_tramp_guard = 0;
129   return 1;
130 }
131 DLLEXPORT void DYNINST_unlock_tramp_guard()
132 {
133   DYNINST_tls_tramp_guard = 1;
134 }
135
136 #if defined(os_linux)
137 void DYNINSTlinuxBreakPoint();
138 #endif
139
140 DECLARE_DYNINST_LOCK(DYNINST_trace_lock);
141
142 /**
143  * Init the FPU.  We've seen bugs with Linux (e.g., Redhat 6.2 stock kernel on
144  * PIIIs) where processes started by Paradyn started with FPU uninitialized.
145  * DYNINSTdummydouble is global so the compiler won't optimize away FP code
146  * in initFPU
147  **/
148 double DYNINSTdummydouble = 4321.71;
149 static void initFPU()
150 {
151    double x = 17.1234;
152    DYNINSTdummydouble *= x;
153 }
154
155 /**
156  * This function is called in both static and dynamic rewriting, on
157  * all platforms that support binary rewriting, but before DYNINSTinit
158  **/
159 void DYNINSTBaseInit()
160 {
161 #if defined(cap_mutatee_traps)
162    DYNINSTinitializeTrapHandler();
163 #endif
164    DYNINST_unlock_tramp_guard();
165    DYNINSThasInitialized = 1;
166
167    RTuntranslatedEntryCounter = 0;
168 }
169
170 /**
171  * The Dyninst API arranges for this function to be called at the entry to
172  * main() via libdyninstAPI_RT_init (defined in RTposix.c and RTwinnt.c).
173  * libdyninstAPI_RT_init is called by one of the following methods:
174  *    GCC: link with gcc -shared, and use __attribute__((constructor));
175  *    Linux: ld with -init libdyninstAPI_RT_init
176  *           gcc with -Wl,-init -Wl,...
177  *    Windows: called from DllMain, which exists in lieu of libdyninstAPI_RT_init
178  *
179  * This is only called in the Dynamic instrumentation case.  Static
180  * libraries don't call this.
181  **/
182 void DYNINSTinit()
183 {
184 //#warning "This function is not implemented for AARCH64 yet!"
185 #if !defined(arch_aarch64)
186    rtdebug_printf("%s[%d]:  DYNINSTinit:  welcome to DYNINSTinit()\n", __FILE__, __LINE__);
187    initFPU();
188    mark_heaps_exec();
189
190    tc_lock_init(&DYNINST_trace_lock);
191    DYNINSThasInitialized = 1;
192    rtdebug_printf("%s[%d]:  welcome to DYNINSTinit\n", __FILE__, __LINE__);
193
194    /* sanity check */
195    assert(sizeof(int64_t) == 8);
196    assert(sizeof(int32_t) == 4);
197
198    /* defensive stuff */
199    memset(DYNINST_target_cache,
200           0,
201           sizeof(void*) * TARGET_CACHE_WIDTH * TARGET_CACHE_WAYS);
202    memset(cacheLRUflags, 1, sizeof(char)*TARGET_CACHE_WIDTH);
203    // stOut = fopen("rtdump.txt","w");
204
205    rtdebug_printf("%s[%d]:  leaving DYNINSTinit\n", __FILE__, __LINE__);
206    fakeTickCount=0;
207    /* Memory emulation */
208 #else
209         assert(0);
210 #endif
211 }
212
213 /**
214  * Does what it's called. Used by the paradyn daemon as a default in certain
215  * cases (MT in particular)
216  **/
217 int DYNINSTreturnZero()
218 {
219    return 0;
220 }
221
222 /* Used to by dyninst breakpoint snippet */
223 void DYNINST_snippetBreakpoint() {
224 //#warning "This function is not implemented for AARCH64 yet!"
225 #if !defined(arch_aarch64)
226    tc_lock_lock(&DYNINST_trace_lock);
227
228    /* Set the state so the mutator knows what's up */
229    DYNINST_synch_event_id = DSE_snippetBreakpoint;
230    DYNINST_synch_event_arg1 = NULL;
231    /* Stop ourselves */
232    DYNINSTbreakPoint();
233    /* Once the stop completes, clean up */
234    DYNINST_synch_event_id = DSE_undefined;
235
236    tc_lock_unlock(&DYNINST_trace_lock);
237 #else
238         assert(0);
239 #endif
240 }
241
242 /* Used to instrument (and report) the entry of fork */
243 DLLEXPORT void DYNINST_instForkEntry() {
244 //#warning "This function is not implemented for AARCH64 yet!"
245 #if !defined(arch_aarch64)
246    tc_lock_lock(&DYNINST_trace_lock);
247
248    /* Set the state so the mutator knows what's up */
249    DYNINST_synch_event_id = DSE_forkEntry;
250    DYNINST_synch_event_arg1 = NULL;
251    /* Stop ourselves */
252    DYNINSTbreakPoint();
253    /* Once the stop completes, clean up */
254    DYNINST_synch_event_id = DSE_undefined;
255    DYNINST_synch_event_arg1 = NULL;
256
257    tc_lock_unlock(&DYNINST_trace_lock);
258 #else
259         assert(0);
260 #endif
261 }
262
263
264 /* Used to instrument (and report) the exit of fork */
265 /* We use the safe breakpoint on the child side of fork
266    as we may not be attached at that point. The parent
267    side uses the normal version. */
268 DLLEXPORT void DYNINST_instForkExit(void *arg1) {
269 //#warning "This function is not implemented for AARCH64 yet!"
270 #if !defined(arch_aarch64)
271    tc_lock_lock(&DYNINST_trace_lock);
272
273    /* Set the state so the mutator knows what's up */
274    DYNINST_synch_event_id = DSE_forkExit;
275    DYNINST_synch_event_arg1 = arg1;
276    /* Stop ourselves */
277    if ((long int)arg1 == 0) {
278        /* Child... */
279        DYNINSTsafeBreakPoint();
280    }
281    else {
282        DYNINSTbreakPoint();
283    }
284    /* Once the stop completes, clean up */
285    DYNINST_synch_event_id = DSE_undefined;
286    DYNINST_synch_event_arg1 = NULL;
287
288    tc_lock_unlock(&DYNINST_trace_lock);
289 #else
290         assert(0);
291 #endif
292 }
293
294
295 /* Used to instrument (and report) the entry of exec */
296 DLLEXPORT void DYNINST_instExecEntry(void *arg1) {
297 //#warning "This function is not implemented for AARCH64 yet!"
298 #if !defined(arch_aarch64)
299    tc_lock_lock(&DYNINST_trace_lock);
300
301    /* Set the state so the mutator knows what's up */
302    DYNINST_synch_event_id = DSE_execEntry;
303    DYNINST_synch_event_arg1 = arg1;
304    /* Stop ourselves */
305 #if defined(os_linux)
306    DYNINSTlinuxBreakPoint();
307 #else
308    DYNINSTbreakPoint();
309 #endif
310    /* Once the stop completes, clean up */
311    DYNINST_synch_event_id = DSE_undefined;
312    DYNINST_synch_event_arg1 = NULL;
313
314    tc_lock_unlock(&DYNINST_trace_lock);
315 #endif
316 }
317
318
319 /* Used to instrument (and report) the exit of exec */
320 DLLEXPORT void DYNINST_instExecExit(void *arg1) {
321    tc_lock_lock(&DYNINST_trace_lock);
322
323    /* Set the state so the mutator knows what's up */
324    DYNINST_synch_event_id = DSE_execExit;
325    DYNINST_synch_event_arg1 = arg1;
326    /* Stop ourselves */
327    DYNINSTbreakPoint();
328    /* Once the stop completes, clean up */
329    DYNINST_synch_event_id = DSE_undefined;
330    DYNINST_synch_event_arg1 = NULL;
331
332    tc_lock_unlock(&DYNINST_trace_lock);
333 }
334
335
336 /* Used to instrument (and report) the entry of exit */
337 DLLEXPORT void DYNINST_instExitEntry(void *arg1) {
338    tc_lock_lock(&DYNINST_trace_lock);
339
340    /* Set the state so the mutator knows what's up */
341    DYNINST_synch_event_id = DSE_exitEntry;
342    DYNINST_synch_event_arg1 = arg1;
343    /* Stop ourselves */
344    DYNINSTbreakPoint();
345    /* Once the stop completes, clean up */
346    DYNINST_synch_event_id = DSE_undefined;
347    DYNINST_synch_event_arg1 = NULL;
348
349    tc_lock_unlock(&DYNINST_trace_lock);
350 }
351
352 /* Used to instrument (and report) the entry of exit */
353 DLLEXPORT void DYNINST_instLoadLibrary(void *arg1) {
354    tc_lock_lock(&DYNINST_trace_lock);
355
356    /* Set the state so the mutator knows what's up */
357    DYNINST_synch_event_id = DSE_loadLibrary;
358    DYNINST_synch_event_arg1 = arg1;
359    /* Stop ourselves */
360    DYNINSTbreakPoint();
361    /* Once the stop completes, clean up */
362    DYNINST_synch_event_id = DSE_undefined;
363    DYNINST_synch_event_arg1 = NULL;
364
365    tc_lock_unlock(&DYNINST_trace_lock);
366 }
367
368 /* Used to instrument (and report) the entry of exit */
369 DLLEXPORT void DYNINST_instLwpExit(void) {
370    tc_lock_lock(&DYNINST_trace_lock);
371
372    /* Set the state so the mutator knows what's up */
373    DYNINST_synch_event_id = DSE_lwpExit;
374    DYNINST_synch_event_arg1 = NULL;
375    /* Stop ourselves */
376    DYNINSTbreakPoint();
377    /* Once the stop completes, clean up */
378    DYNINST_synch_event_id = DSE_undefined;
379    DYNINST_synch_event_arg1 = NULL;
380
381    tc_lock_unlock(&DYNINST_trace_lock);
382 }
383
384
385 // implementation of an N=2 way associative cache to keep access time low
386 // width = 32
387 // the cache contains valid addresses
388 // add to the cache when an instrumented instruction misses in the cache
389 // update flags for the cache when an instrumented instruction hits in the cache
390 // instrumentation will take the form of a call to cache check
391 RT_Boolean cacheLookup(void *calculation)
392 {
393     int index = ((unsigned long) calculation) % TARGET_CACHE_WIDTH;
394     if (DYNINST_target_cache[index][0] == calculation) {
395         cacheLRUflags[index] = 0;
396         return RT_TRUE;
397     } else if (DYNINST_target_cache[index][1] == calculation) {
398         cacheLRUflags[index] = 1;
399         return RT_TRUE;
400     } else { //miss
401         if (cacheLRUflags[index] == 0) {
402             DYNINST_target_cache[index][1] = calculation;
403             cacheLRUflags[index] = 1;
404         } else {
405             DYNINST_target_cache[index][0] = calculation;
406             cacheLRUflags[index] = 0;
407         }
408         return RT_FALSE;
409     }
410 }
411
412 /**
413  * Receives two snippets as arguments and stops the mutatee
414  * while the mutator reads the arguments, saved to
415  * DYNINST_synch_event... global variables.
416  *
417  * if flag useCache==1, does a cache lookup and stops only
418  * if there is a cache miss
419  *
420  * The flags are:
421  * bit 0: useCache
422  * bit 1: true if interpAsTarget
423  * bit 2: true if interpAsReturnAddr
424  **/
425 //#define STACKDUMP
426 void DYNINST_stopThread (void * pointAddr, void *callBackID,
427                          void *flags, void *calculation)
428 {
429         static int reentrant = 0;
430
431     RT_Boolean isInCache = RT_FALSE;
432
433
434         if (reentrant == 1) {
435                 return;
436         }
437         reentrant = 1;
438     tc_lock_lock(&DYNINST_trace_lock);
439     rtdebug_printf("RT_st: pt[%lx] flags[%lx] calc[%lx] ",
440                    (long)pointAddr, (long)flags, (long)calculation);
441
442 #if 0 && defined STACKDUMP
443     //if (0 && ((unsigned long)calculation == 0x9746a3 ||
444     //          (unsigned long)calculation == 0x77dd761b))
445     //{
446         fprintf(stOut,"RT_st: %lx(%lx)\n", (long)pointAddr,&calculation);
447         fprintf(stOut,"at instr w/ targ=%lx\n",(long)calculation);
448         for (bidx=0; bidx < 0x100; bidx+=4) {
449             fprintf(stOut,"0x%x:  ", (int)stackBase+bidx);
450             fprintf(stOut,"%02hhx", stackBase[bidx]);
451             fprintf(stOut,"%02hhx", stackBase[bidx+1]);
452             fprintf(stOut,"%02hhx", stackBase[bidx+2]);
453             fprintf(stOut,"%02hhx", stackBase[bidx+3]);
454             fprintf(stOut,"\n");
455         }
456     //}
457     // fsg: read from 40a4aa, how did it become 40a380?
458 #endif
459
460     if ((((long)flags) & 0x04) ) {
461         rtdebug_printf("ret-addr stopThread yields %lx", (long)calculation);
462         //fprintf(stderr,"[$0x%lx]\n", (long)calculation);
463     }
464
465     if (0 != (((long)flags) & 0x03)) {
466         // do the lookup if the useCache bit is set, or if it represents
467         // the address of real code, so that we add the address to the cache
468         // even if we will stop the thread if there's a cache hit
469         isInCache = cacheLookup(calculation);
470     }
471
472     // if the cache flag bit is not set, or if we get a cache miss,
473     // stop the thread so that we can call back to the mutatee
474     if (0 == (((long)flags) & 0x01) ||
475         ! isInCache )
476     {
477         /* Set vars for Dyninst to read */
478         DYNINST_synch_event_id = DSE_stopThread;
479         DYNINST_synch_event_arg1 = pointAddr;
480         DYNINST_synch_event_arg2 = callBackID;
481         DYNINST_synch_event_arg3 = calculation;
482
483         // encode interp as target or as return addr by making
484         // callback ID negative
485         if (0 != (((long)flags) & 0x06))
486         {
487             DYNINST_synch_event_arg2 =
488                 (void*) (-1 * (long)DYNINST_synch_event_arg2);
489         }
490
491         rtdebug_printf("stopping! isInCache=%d\n", isInCache);
492
493         /* Stop ourselves */
494         DYNINSTbreakPoint();
495
496         /* Once the stop completes, clean up */
497         DYNINST_synch_event_id = DSE_undefined;
498         DYNINST_synch_event_arg1 = NULL;
499         DYNINST_synch_event_arg2 = NULL;
500         DYNINST_synch_event_arg3 = NULL;
501     }
502     fflush(stOut);
503     tc_lock_unlock(&DYNINST_trace_lock);
504         reentrant = 0;
505     return;
506 }
507
508 // zeroes out the useCache flag if the call is interprocedural
509 void DYNINST_stopInterProc(void * pointAddr, void *callBackID,
510                            void *flags, void *calculation,
511                            void *objStart, void *objEnd)
512 {
513 #if defined STACKDUMP
514     fprintf(stOut,"RT_sip: calc=%lx objStart=%lx objEnd=%lx\n",
515             calculation, objStart, objEnd);
516     fflush(stOut);
517 #endif
518     if (calculation < objStart || calculation >= objEnd) {
519        flags = (void*) ((long) (((int)((long)flags)) & 0xfffffffe));
520     }
521     DYNINST_stopThread(pointAddr, callBackID, flags, calculation);
522 }
523
524 // boundsArray is a sequence of (blockStart,blockEnd) pairs
525 DLLEXPORT RT_Boolean DYNINST_boundsCheck(void **boundsArray_, void *arrayLen_,
526                                          void *writeTarget_)
527 {
528     RT_Boolean callStopThread = RT_FALSE;
529     const unsigned long writeTarget = (unsigned long)writeTarget_;
530     const long arrayLen = (long)arrayLen_;
531     unsigned long *boundsArray = (unsigned long*)boundsArray_;
532     // set idx to halfway into the array, ensuring we use a blockStart address
533     int idx = (int)arrayLen / 4 * 2;
534     int lowIdx = 0;
535     int highIdx = (int)arrayLen;
536     //fprintf(stderr,"D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n", (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
537     //rtdebug_printf("D_bc@%p: boundsArray=%p target=%lx idx=%d arrayLen=%d [%d]\n", (void*)DYNINST_boundsCheck, boundsArray_, writeTarget_, idx, arrayLen, __LINE__);
538     if ((unsigned long)boundsArray < 0x10000000) {
539         printf("D_bc: boundsArray_ = %lx, returning false\n",(unsigned long) boundsArray);
540         return RT_FALSE;
541     }
542     while (lowIdx < highIdx)
543     {
544         if (idx > arrayLen || idx < 0)
545             rtdebug_printf("ERROR: out of bounds idx=%d, arrayLen = %d [%d]\n", idx, arrayLen, __LINE__);
546         rtdebug_printf("D_bc: low=%d high=%d arr[%d]=%lx [%d]\n", lowIdx, highIdx, idx, boundsArray[idx], __LINE__);
547         if (writeTarget < boundsArray[idx]) {
548             rtdebug_printf("D_bc: [%d]\n", __LINE__);
549             highIdx = idx;
550             idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
551         }
552         else if (boundsArray[idx+1] <= writeTarget) {
553             rtdebug_printf("D_bc: [%d]\n", __LINE__);
554             lowIdx = idx+2;
555             idx = (highIdx - lowIdx) / 4 * 2 + lowIdx;
556         }
557         else {
558             rtdebug_printf("D_bc: callST=true [%d]\n", __LINE__);
559             callStopThread = RT_TRUE;
560             break;
561         }
562     }
563     rtdebug_printf("D_bc: boundsArray=%p ret=%d [%d]\n", boundsArray, callStopThread, __LINE__);
564     return callStopThread;
565 }
566
567
568 /**
569  * Used to report addresses of functions called at dynamic call sites
570  **/
571 DLLEXPORT int DYNINSTasyncDynFuncCall (void * call_target, void *call_addr) {
572     if (DYNINSTstaticMode) return 0;
573
574     tc_lock_lock(&DYNINST_trace_lock);
575
576     /* Set the state so the mutator knows what's up */
577     DYNINST_synch_event_id = DSE_dynFuncCall;
578     DYNINST_synch_event_arg1 = call_target;
579     DYNINST_synch_event_arg2 = call_addr;
580     /* Stop ourselves */
581     DYNINSTbreakPoint();
582     /* Once the stop completes, clean up */
583     DYNINST_synch_event_id = DSE_undefined;
584     DYNINST_synch_event_arg1 = NULL;
585     DYNINST_synch_event_arg2 = NULL;
586
587     tc_lock_unlock(&DYNINST_trace_lock);
588
589     return 0;
590 }
591
592 int DYNINSTuserMessage(void *msg, unsigned int msg_size) {
593     unsigned long msg_size_long = (unsigned long)msg_size;
594     if (DYNINSTstaticMode)
595         {
596                 return 0;
597         }
598
599     tc_lock_lock(&DYNINST_trace_lock);
600
601
602     /* Set the state so the mutator knows what's up */
603     DYNINST_synch_event_id = DSE_userMessage;
604     DYNINST_synch_event_arg1 = msg;
605     DYNINST_synch_event_arg2 = (void *)msg_size_long;
606     /* Stop ourselves */
607     DYNINSTbreakPoint();
608     /* Once the stop completes, clean up */
609     DYNINST_synch_event_id = DSE_undefined;
610     DYNINST_synch_event_arg1 = NULL;
611     DYNINST_synch_event_arg2 = NULL;
612
613     tc_lock_unlock(&DYNINST_trace_lock);
614
615     return 0;
616 }
617
618 int tc_lock_init(tc_lock_t *t)
619 {
620   t->mutex = 0;
621   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
622   return 0;
623 }
624
625 int tc_lock_unlock(tc_lock_t *t)
626 {
627   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
628   t->mutex = 0;
629   return 0;
630 }
631
632 int tc_lock_destroy(tc_lock_t *t)
633 {
634   t->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
635   t->mutex = 0;
636   return 0;
637 }
638
639 void dyninst_init_lock(dyninst_lock_t *lock)
640 {
641    lock->tid = (dyntid_t) DYNINST_INITIAL_LOCK_PID;
642    lock->mutex = 0;
643 }
644
645 void dyninst_free_lock(dyninst_lock_t *lock)
646 {
647     (void)lock; /* unused parameter */
648 }
649
650 int dyninst_lock(dyninst_lock_t *lock)
651 {
652    return tc_lock_lock(lock);
653 }
654
655 void dyninst_unlock(dyninst_lock_t *lock)
656 {
657    tc_lock_unlock(lock);
658 }
659
660 int rtdebug_printf(char *format, ...)
661 {
662   int ret;
663   va_list va;
664   if (!DYNINSTdebugRTlib) return 0;
665   if (NULL == format) return DYNINST_PRINTF_ERRVAL;
666
667   fprintf(stderr, "[RTLIB]");
668   va_start(va, format);
669   ret = vfprintf(stderr, format, va);
670   va_end(va);
671
672   return ret;
673 }
674
675 #ifndef CASE_RETURN_STR
676 #define CASE_RETURN_STR(x) case x: return #x
677 #endif
678
679 char *asyncEventType2str(rtBPatch_asyncEventType t)
680 {
681   switch (t) {
682   CASE_RETURN_STR(rtBPatch_nullEvent);
683   CASE_RETURN_STR(rtBPatch_newConnectionEvent);
684   CASE_RETURN_STR(rtBPatch_internalShutDownEvent);
685   CASE_RETURN_STR(rtBPatch_threadCreateEvent);
686   CASE_RETURN_STR(rtBPatch_threadDestroyEvent);
687   CASE_RETURN_STR(rtBPatch_dynamicCallEvent);
688   CASE_RETURN_STR(rtBPatch_userEvent);
689   default: return "bad_async_event_type";
690   }
691 }
692
693 DLLEXPORT volatile unsigned long dyninstTrapTableUsed;
694 DLLEXPORT volatile unsigned long dyninstTrapTableVersion;
695 DLLEXPORT volatile trapMapping_t *dyninstTrapTable;
696 DLLEXPORT volatile unsigned long dyninstTrapTableIsSorted;
697
698 void* dyninstTrapTranslate(void *source,
699                            volatile unsigned long *table_used,
700                            volatile unsigned long *table_version,
701                            volatile trapMapping_t **trap_table,
702                            volatile unsigned long *is_sorted)
703 {
704    volatile unsigned local_version;
705    unsigned i;
706    void *target;
707
708    do {
709       local_version = *table_version;
710       target = NULL;
711
712       if (*is_sorted)
713       {
714          unsigned min = 0;
715          unsigned mid = 0;
716          unsigned max = *table_used;
717          unsigned prev = max+1;
718
719          for (;;) {
720             mid = (min + max) / 2;
721             if (mid == prev) {
722                 fprintf(stderr,"ERROR: dyninstTrapTranslate couldn't find "
723                         "entry for %p: min=%x mid=%x max=%x prev=%x\n",
724                         source,min,mid,max,prev);
725                break;
726             }
727             prev = mid;
728
729             if ((*trap_table)[mid].source < source)
730                min = mid;
731             else if ((*trap_table)[mid].source > source)
732                max = mid;
733             else {
734                target = (*trap_table)[mid].target;
735                break;
736             }
737          }
738       }
739       else { /*!dyninstTrapTableIsSorted*/
740          for (i = 0; i<*table_used; i++) {
741             if ((*trap_table)[i].source == source) {
742                target = (*trap_table)[i].target;
743                break;
744             }
745          }
746       }
747    } while (local_version != *table_version);
748
749    return target;
750 }
751