rebased to master after sw 3rd party completed
[dyninst.git] / dyninstAPI_RT / src / RTfreebsd.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 /************************************************************************
32  * $Id: RTlinux.c,v 1.54 2008/04/11 23:30:44 legendre Exp $
33  * RTlinux.c: mutatee-side library function specific to Linux
34  ************************************************************************/
35
36 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
37 #include "dyninstAPI_RT/src/RTthread.h"
38 #include "dyninstAPI_RT/src/RTcommon.h"
39 #include <assert.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <unistd.h>
43
44 #include <dlfcn.h>
45 #include <sys/types.h>
46 #include <sys/syscall.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <signal.h>
50 #include <sys/mman.h>
51 #include <link.h>
52
53 /* FreeBSD libc has stubs so a static version shouldn't need libpthreads */
54 #include <pthread.h>
55
56 extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
57 extern double DYNINSTstaticHeap_16M_anyHeap_1[];
58 extern unsigned long sizeOfLowMemHeap1;
59 extern unsigned long sizeOfAnyHeap1;
60
61 static struct trap_mapping_header *getStaticTrapMap(unsigned long addr);
62
63 /** RT lib initialization **/
64
65 void mark_heaps_exec() {
66     RTprintf( "*** Initializing dyninstAPI runtime.\n" );
67
68     /* Grab the page size, to align the heap pointer. */
69     long int pageSize = sysconf( _SC_PAGESIZE );
70     if( pageSize == 0 || pageSize == - 1 ) {
71         fprintf( stderr, "*** Failed to obtain page size, guessing 16K.\n" );
72         perror( "mark_heaps_exec" );
73         pageSize = 1024 * 16;
74     } /* end pageSize initialization */
75
76     /* Align the heap pointer. */
77     unsigned long int alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1;
78     alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
79     unsigned long int adjustedSize = (unsigned long int) DYNINSTstaticHeap_16M_anyHeap_1 - alignedHeapPointer + sizeOfAnyHeap1;
80
81     /* Make the heap's page executable. */
82     int result = mprotect( (void *) alignedHeapPointer, (size_t) adjustedSize, PROT_READ | PROT_WRITE | PROT_EXEC );
83     if( result != 0 ) {
84         fprintf( stderr, "%s[%d]: Couldn't make DYNINSTstaticHeap_16M_anyHeap_1 executable!\n", __FILE__, __LINE__);
85         perror( "mark_heaps_exec" );
86     }
87     RTprintf( "*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer, alignedHeapPointer + adjustedSize );
88
89     /* Mark _both_ heaps executable. */
90     alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1;
91     alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
92     adjustedSize = (unsigned long int) DYNINSTstaticHeap_512K_lowmemHeap_1 - alignedHeapPointer + sizeOfLowMemHeap1;
93
94     /* Make the heap's page executable. */
95     result = mprotect( (void *) alignedHeapPointer, (size_t) adjustedSize, PROT_READ | PROT_WRITE | PROT_EXEC );
96     if( result != 0 ) {
97         fprintf( stderr, "%s[%d]: Couldn't make DYNINSTstaticHeap_512K_lowmemHeap_1 executable!\n", __FILE__, __LINE__ );
98         perror( "mark_heaps_exec" );
99     }
100     RTprintf( "*** Marked memory from 0x%lx to 0x%lx executable.\n", alignedHeapPointer, alignedHeapPointer + adjustedSize );
101 } /* end mark_heaps_exec() */
102
103
104 #if defined(cap_binary_rewriter) && !defined(DYNINST_RT_STATIC_LIB)
105 /* For a static binary, all global constructors are combined in an undefined
106  * order. Also, DYNINSTBaseInit must be run after all global constructors have
107  * been run. Since the order of global constructors is undefined, DYNINSTBaseInit
108  * cannot be run as a constructor in static binaries. Instead, it is run from a
109  * special constructor handler that processes all the global constructors in
110  * the binary. Leaving this code in would create a global constructor for the
111  * function runDYNINSTBaseInit(). See DYNINSTglobal_ctors_handler.
112  */ 
113 extern void DYNINSTBaseInit();
114 void runDYNINSTBaseInit() __attribute__((constructor));
115 void runDYNINSTBaseInit()
116 {
117    DYNINSTBaseInit();
118 }
119 #endif
120
121 /** Dynamic instrumentation support **/
122
123 static
124 int tkill(pid_t pid, long lwp, int sig) {
125     static int has_tkill = 1;
126     int result = 0;
127
128     if( has_tkill ) {
129         result = syscall(SYS_thr_kill2, pid, lwp, sig);
130         if( 0 != result && ENOSYS == errno ) {
131             has_tkill = 0;
132         }
133     }
134
135     if( !has_tkill ) {
136         result = kill(pid, sig);
137     }
138
139     return (result == 0);
140 }
141
142 void DYNINSTbreakPoint()
143 {
144     if(DYNINSTstaticMode) return;
145
146     DYNINST_break_point_event = 1;
147     while( DYNINST_break_point_event ) {
148         tkill(getpid(), dyn_lwp_self(), DYNINST_BREAKPOINT_SIGNUM);
149     }
150     /* Mutator resets to 0 */
151 }
152
153 static int failed_breakpoint = 0;
154 void uncaught_breakpoint(int sig)
155 {
156    failed_breakpoint = 1;
157 }
158
159 void DYNINSTsafeBreakPoint()
160 {
161     if(DYNINSTstaticMode) return;
162
163     DYNINST_break_point_event = 1;
164     while( DYNINST_break_point_event ) {
165         tkill(getpid(), dyn_lwp_self(), SIGSTOP);
166     }
167     /* Mutator resets to 0 */
168
169 #if 0
170     if( DYNINSTstaticMode ) return;
171     DYNINST_break_point_event = 2;
172     sigset_t emptyset;
173     sigemptyset(&emptyset);
174
175     // There is a bug with attaching to a stopped process on FreeBSD This
176     // achieves the same result as long as Dyninst attaches to the process when
177     // it is in sigsuspend
178     while( DYNINST_break_point_event ) {
179         sigsuspend(&emptyset);
180     }
181 #endif
182 }
183
184 #if !defined(DYNINST_RT_STATIC_LIB)
185 static int get_dlopen_error() {
186     const char *err_str;
187     err_str = dlerror();
188     if( err_str ) {
189         strncpy(gLoadLibraryErrorString, err_str, (size_t) ERROR_STRING_LENGTH);
190         return 1;
191     }
192
193     sprintf(gLoadLibraryErrorString, "unknown error withe dlopen");
194     return 0;
195 }
196
197 int DYNINSTloadLibrary(char *libname)
198 {
199     void *res;
200     gLoadLibraryErrorString[0] = '\0';
201     res = dlopen(libname, RTLD_NOW | RTLD_GLOBAL);
202     if( res ) return 1;
203
204     get_dlopen_error();
205     return 0;
206 }
207 #endif
208
209 /** threading support **/
210
211 int dyn_lwp_self()
212 {
213     static int gettid_not_valid = 0;
214     int result;
215     
216     if( gettid_not_valid )
217         return getpid();
218
219     long lwp_id;
220     result = syscall(SYS_thr_self, &lwp_id);
221     if( result && errno == ENOSYS ) {
222         gettid_not_valid = 1;
223         return getpid();
224     }
225
226     return lwp_id;
227 }
228
229 int dyn_pid_self()
230 {
231    return getpid();
232 }
233
234 dyntid_t (*DYNINST_pthread_self)(void);
235
236 dyntid_t dyn_pthread_self()
237 {
238    dyntid_t me;
239    if (DYNINSTstaticMode) {
240       return (dyntid_t) pthread_self();
241    }
242    if (!DYNINST_pthread_self) {
243       return (dyntid_t) DYNINST_SINGLETHREADED;
244    }
245    me = (*DYNINST_pthread_self)();
246    return (dyntid_t) me;
247 }
248
249 int DYNINST_am_initial_thread( dyntid_t tid ) {
250     /*
251      * LWPs and PIDs are in different namespaces on FreeBSD.
252      *
253      * I don't really know a good way to determine this without
254      * doing an expensive sysctl.
255      *
256      * Luckily, this function isn't used anymore
257      */
258     assert(!"This function is unimplemented on FreeBSD");
259     return 0;
260 }
261
262 /** trap based instrumentation **/
263
264 #if defined(cap_mutatee_traps)
265
266 #include <ucontext.h>
267
268 #if defined(arch_x86) || defined(MUTATEE_32)
269 #define UC_PC(x) x->uc_mcontext.mc_eip
270 #elif defined(arch_x86_64)
271 #define UC_PC(x) x->uc_mcontext.mc_rip
272 #endif // UC_PC
273
274 extern unsigned long dyninstTrapTableUsed;
275 extern unsigned long dyninstTrapTableVersion;
276 extern trapMapping_t *dyninstTrapTable;
277 extern unsigned long dyninstTrapTableIsSorted;
278
279 /**
280  * This comment is now obsolete, left for historic purposes
281  *
282  * Called by the SIGTRAP handler, dyninstTrapHandler.  This function is 
283  * closly intwined with dyninstTrapHandler, don't modify one without 
284  * understanding the other.
285  *
286  * This function sets up the calling context that was passed to the
287  * SIGTRAP handler so that control will be redirected to our instrumentation
288  * when we do the setcontext call.
289  * 
290  * There are a couple things that make this more difficult than it should be:
291  *   1. The OS provided calling context is similar to the GLIBC calling context,
292  *      but not compatible.  We'll create a new GLIBC compatible context and
293  *      copy the possibly stomped registers from the OS context into it.  The
294  *      incompatiblities seem to deal with FP and other special purpose registers.
295  *   2. setcontext doesn't restore the flags register.  Thus dyninstTrapHandler
296  *      will save the flags register first thing and pass us its value in the
297  *      flags parameter.  We'll then push the instrumentation entry and flags
298  *      onto the context's stack.  Instead of transfering control straight to the
299  *      instrumentation, we'll actually go back to dyninstTrapHandler, which will
300  *      do a popf/ret to restore flags and go to instrumentation.  The 'retPoint'
301  *      parameter is the address in dyninstTrapHandler the popf/ret can be found.
302  **/
303 void dyninstTrapHandler(int sig, siginfo_t *sg, ucontext_t *context)
304 {
305    void *orig_ip;
306    void *trap_to;
307
308    orig_ip = UC_PC(context);
309    assert(orig_ip);
310
311    // Find the new IP we're going to and substitute. Leave everything else untouched
312    if (DYNINSTstaticMode) {
313       unsigned long zero = 0;
314       unsigned long one = 1;
315       struct trap_mapping_header *hdr = getStaticTrapMap((unsigned long) orig_ip);
316       if (!hdr) return;
317
318       assert(hdr);
319       trapMapping_t *mapping = &(hdr->traps[0]);
320       trap_to = dyninstTrapTranslate(orig_ip, 
321                                      (unsigned long *) &hdr->num_entries, 
322                                      &zero, 
323                                      (volatile trapMapping_t **) &mapping,
324                                      &one);
325    }
326    else {
327       trap_to = dyninstTrapTranslate(orig_ip, 
328                                      &dyninstTrapTableUsed,
329                                      &dyninstTrapTableVersion,
330                                      (volatile trapMapping_t **) &dyninstTrapTable,
331                                      &dyninstTrapTableIsSorted);
332                                      
333    }
334    UC_PC(context) = (long) trap_to;
335 }
336
337 #if defined(cap_binary_rewriter)
338
339 #define NUM_LIBRARIES 512 //Important, max number of rewritten libraries
340
341 #define WORD_SIZE (8 * sizeof(unsigned))
342 #define NUM_LIBRARIES_BITMASK_SIZE (1 + NUM_LIBRARIES / WORD_SIZE)
343 struct trap_mapping_header *all_headers[NUM_LIBRARIES];
344
345 static unsigned all_headers_current[NUM_LIBRARIES_BITMASK_SIZE];
346 static unsigned all_headers_last[NUM_LIBRARIES_BITMASK_SIZE];
347
348 #if !defined(arch_x86_64) || defined(MUTATEE_32)
349 typedef Elf32_Dyn ElfX_Dyn;
350 typedef Elf32_Ehdr ElfX_Ehdr;
351 #else
352 typedef Elf64_Dyn ElfX_Dyn;
353 typedef Elf64_Ehdr ElfX_Ehdr;
354 #endif
355
356 static int parse_libs();
357 static int parse_link_map(struct link_map *l);
358 static void clear_unloaded_libs();
359
360 static void set_bit(unsigned *bit_mask, int bit, char value);
361 static void clear_bitmask(unsigned *bit_mask);
362 static unsigned get_next_free_bitmask(unsigned *bit_mask, int last_pos);
363 static unsigned get_next_set_bitmask(unsigned *bit_mask, int last_pos);
364
365 static tc_lock_t trap_mapping_lock;
366
367 static struct trap_mapping_header *getStaticTrapMap(unsigned long addr)
368 {
369    struct trap_mapping_header *header;
370    int i;
371    
372    tc_lock_lock(&trap_mapping_lock);
373    parse_libs();
374
375    i = -1;
376    for (;;) {
377       i = get_next_set_bitmask(all_headers_current, i);
378       assert(i >= 0 && i <= NUM_LIBRARIES);
379       if (i == NUM_LIBRARIES) {
380          header = NULL;
381          goto done;
382       }
383       header = all_headers[i];
384       if (addr >= header->low_entry && addr <= header->high_entry) {
385          goto done;
386       }
387    }  
388  done:
389    tc_lock_unlock(&trap_mapping_lock);
390    return header;
391 }
392
393 static struct link_map *getLinkMap() {
394     struct link_map *map = NULL;
395 #if !defined(DYNINST_RT_STATIC_LIB)
396     if( dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map) ) {
397         return NULL;
398     }
399
400     // Rewind the current link map pointer to find the
401     // start of the list
402     struct link_map *last_map;
403     while( map != NULL ) {
404         last_map = map;
405         map = map->l_prev;
406     }
407
408     map = last_map;
409 #endif
410     return map;
411 }
412
413 static int parse_libs()
414 {
415    struct link_map *l_current;
416
417    l_current = getLinkMap();
418    if (!l_current)
419       return -1;
420
421    clear_bitmask(all_headers_current);
422    while (l_current) {
423       parse_link_map(l_current);
424       l_current = l_current->l_next;
425    }
426    clear_unloaded_libs();
427
428    return 0;
429 }
430
431 //parse_link_map return values
432 #define PARSED 0
433 #define NOT_REWRITTEN 1
434 #define ALREADY_PARSED 2
435 #define ERROR_INTERNAL -1
436 #define ERROR_FULL -2
437 static int parse_link_map(struct link_map *l) 
438 {
439    ElfX_Dyn *dynamic_ptr;
440    struct trap_mapping_header *header;
441    unsigned int i, new_pos;
442
443    dynamic_ptr = (ElfX_Dyn *) l->l_ld;
444    if (!dynamic_ptr)
445       return -1;
446
447    assert(sizeof(dynamic_ptr->d_un.d_ptr) == sizeof(void *));
448    for (; dynamic_ptr->d_tag != DT_NULL && dynamic_ptr->d_tag != DT_DYNINST; dynamic_ptr++);
449    if (dynamic_ptr->d_tag == DT_NULL) {
450       return NOT_REWRITTEN;
451    }
452
453    header = (struct trap_mapping_header *) (dynamic_ptr->d_un.d_val + l->l_addr);
454
455    caddr_t libAddr = l->l_addr;
456
457    // Executables have an implicit zero load address but the library load address
458    // may be non-zero
459    if( ((ElfX_Ehdr *)libAddr)->e_type == ET_EXEC ) {
460        libAddr = 0;
461    }else if( ((ElfX_Ehdr *)libAddr)->e_type == ET_DYN ) {
462        // Account for library_adjust mechanism which is used for shared libraries
463        // on FreeBSD
464        libAddr += getpagesize();
465    }
466
467    header = (struct trap_mapping_header *) (dynamic_ptr->d_un.d_val + libAddr);
468    
469    if (header->signature != TRAP_HEADER_SIG)
470       return ERROR_INTERNAL;
471    if (header->pos != -1) {
472       set_bit(all_headers_current, header->pos, 1);
473       assert(all_headers[header->pos] == header);
474       return ALREADY_PARSED;
475    }
476  
477    for (i = 0; i < header->num_entries; i++)
478    {
479       header->traps[i].source = (void *) (((unsigned long) header->traps[i].source) + libAddr);
480       header->traps[i].target = (void *) (((unsigned long) header->traps[i].target) + libAddr);
481       if (!header->low_entry || header->low_entry > (unsigned long) header->traps[i].source)
482          header->low_entry = (unsigned long) header->traps[i].source;
483       if (!header->high_entry || header->high_entry < (unsigned long) header->traps[i].source)
484          header->high_entry = (unsigned long) header->traps[i].source;
485    }
486
487    new_pos = get_next_free_bitmask(all_headers_last, -1);
488    assert(new_pos >= 0 && new_pos < NUM_LIBRARIES);
489    if (new_pos == NUM_LIBRARIES)
490       return ERROR_FULL;
491
492    header->pos = new_pos;
493    all_headers[new_pos] = header;
494    set_bit(all_headers_current, new_pos, 1);
495    set_bit(all_headers_last, new_pos, 1);
496
497    return PARSED;
498 }
499
500 static void clear_unloaded_libs()
501 {
502    unsigned i;
503    for (i = 0; i<NUM_LIBRARIES_BITMASK_SIZE; i++)
504    {
505       all_headers_last[i] = all_headers_current[i];
506    }
507 }
508
509 static void set_bit(unsigned *bit_mask, int bit, char value) {
510    assert(bit < NUM_LIBRARIES);
511    unsigned *word = bit_mask + bit / WORD_SIZE;
512    unsigned shift = bit % WORD_SIZE;
513    if (value) {
514       *word |= (1 << shift);
515    }
516    else {
517       *word &= ~(1 << shift);
518    }
519 }
520
521 static void clear_bitmask(unsigned *bit_mask) {
522    unsigned i;
523    for (i = 0; i < NUM_LIBRARIES_BITMASK_SIZE; i++) {
524       bit_mask[i] = 0;
525    }
526 }
527
528 static unsigned get_next_free_bitmask(unsigned *bit_mask, int last_pos) {
529    unsigned i, j;
530    j = last_pos+1;
531    i = j / WORD_SIZE;
532    for (; j < NUM_LIBRARIES; i++) {
533       if (bit_mask[i] == (unsigned) -1) {
534          j += WORD_SIZE;
535          continue;
536       }
537       for (;;) {
538          if (!((1 << (j % WORD_SIZE) & bit_mask[i]))) {
539             return j;
540          }
541          j++;
542          if (j % WORD_SIZE == 0) {
543             break;
544          }
545       }
546    }
547    return NUM_LIBRARIES;
548 }
549
550 static unsigned get_next_set_bitmask(unsigned *bit_mask, int last_pos) {
551    unsigned i, j;
552    j = last_pos+1;
553    i = j / WORD_SIZE;
554    for (; j < NUM_LIBRARIES; i++) {
555       if (bit_mask[i] == (unsigned) 0) {
556          j += WORD_SIZE;
557          continue;
558       }
559       for (;;) {
560          if ((1 << (j % WORD_SIZE) & bit_mask[i])) {
561             return j;
562          }
563          j++;
564          if (j % WORD_SIZE == 0) {
565             break;
566          }
567       }
568    }
569    return NUM_LIBRARIES;
570 }
571
572 #endif
573
574 #endif /* cap_mutatee_traps */
575
576 /*
577  * Note: this program is for historical purposes only, we use libthread_db
578  * now to get thread information.
579  *
580  * A program to determine the offsets of certain thread structures on FreeBSD
581  *
582  * This program should be compiled with the headers from the libthr library from
583  * /usr/src. This can be installed using sysinstall. The following arguments 
584  * should be added to the compile once these headers are installed.
585  *
586  * -I/usr/src/lib/libthr/arch/amd64/include -I/usr/src/lib/libthr/thread
587  *
588  * Change amd64 to what ever is appropriate.
589
590 #include <pthread.h>
591 #include <stdio.h>
592 #include <sys/syscall.h>
593 #include <sys/types.h>
594 #include <unistd.h>
595
596 #include "thr_private.h"
597
598 pthread_attr_t attr;
599
600 void *foo(void *f) {
601     unsigned long stack_addr;
602     void *(*start_func)(void *);
603     unsigned long tid;
604
605     // Get all the values
606     syscall(SYS_thr_self, &tid);
607
608     start_func = foo;
609
610     asm("mov %%rbp,%0" : "=r" (stack_addr));
611
612     pthread_t threadSelf = pthread_self();
613
614     printf("TID: %u == %u\n", tid, threadSelf->tid);
615     printf("STACK: 0x%lx == 0x%lx\n", stack_addr, threadSelf->attr.stackaddr_attr + threadSelf->attr.stacksize_attr);
616     printf("START: 0x%lx == 0x%lx\n", (unsigned long)start_func, (unsigned long)threadSelf->start_routine);
617
618     unsigned char *ptr = (unsigned char *)threadSelf;
619     unsigned long tidVal = *((unsigned long *)(ptr + offsetof(struct pthread, tid)));
620     unsigned long stackAddrVal = *((unsigned long *)(ptr + offsetof(struct pthread, attr) + offsetof(struct pthread_attr, stackaddr_attr)));
621     unsigned long stackSizeVal = *((unsigned long *)(ptr + offsetof(struct pthread, attr) + offsetof(struct pthread_attr, stacksize_attr)));
622     unsigned long startFuncVal = *((unsigned long *)(ptr + offsetof(struct pthread, start_routine)));
623
624     printf("TID = %u, offset = %u\n", tidVal, offsetof(struct pthread, tid));
625     printf("STACK = 0x%lx, offset = %u\n", stackAddrVal, offsetof(struct pthread, attr) + offsetof(struct pthread_attr, stackaddr_attr));
626     printf("SIZE = 0x%lx, offset = %u\n", stackSizeVal, offsetof(struct pthread, attr) + offsetof(struct pthread_attr, stacksize_attr));
627     printf("START = 0x%lx, offset = %u\n", startFuncVal, offsetof(struct pthread, start_routine));
628
629     return NULL;
630 }
631
632 int main(int argc, char *argv[]) {
633     pthread_t t;
634     void *result;
635     pthread_attr_init(&attr);
636     pthread_create(&t, &attr, foo, NULL);
637     pthread_join(t, &result);
638
639     return 0;
640 }
641 */