Sets the brk pointer for save-the-world binaries to what it was when each
[dyninst.git] / dyninstAPI_RT / src / RTlinux.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 /************************************************************************
43  * $Id: RTlinux.c,v 1.36 2006/01/13 00:00:48 jodom Exp $
44  * RTlinux.c: mutatee-side library function specific to Linux
45  ************************************************************************/
46
47 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
48 #include <assert.h>
49 #include <stdio.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <dlfcn.h>
53 #include <sys/types.h>
54 #include <sys/syscall.h>
55 #include <string.h>
56
57 #if defined(arch_ia64) || defined(arch_x86_64)
58
59 #include <errno.h>
60 #include <sys/mman.h>
61
62 extern double DYNINSTstaticHeap_32K_lowmemHeap_1[];
63 extern double DYNINSTstaticHeap_4M_anyHeap_1[];
64
65 void _start( void ) 
66 {
67    int result;
68         RTprintf("*** Initializing dyninstAPI runtime.\n" );
69
70         /* Grab the page size, to align the heap pointer. */
71         long int pageSize = sysconf( _SC_PAGESIZE );
72         if( pageSize == 0 || pageSize == - 1 ) {
73                 fprintf( stderr, "*** Failed to obtain page size, guessing 16K.\n" );
74                 perror( "_start" );
75                 pageSize = 1024 * 16;
76    } /* end pageSize initialization */
77
78         /* Align the heap pointer. */
79         unsigned long int alignedHeapPointer = 
80       (unsigned long int) DYNINSTstaticHeap_4M_anyHeap_1;
81         unsigned long long int adjustedSize = alignedHeapPointer + (4 * 1024 * 1024);
82         alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
83         adjustedSize -= alignedHeapPointer;
84
85         /* Make the heap's page executable. */
86    result = mprotect((void *) alignedHeapPointer, (size_t) adjustedSize, 
87                      PROT_READ | PROT_WRITE | PROT_EXEC);
88    if (result != 0)
89    {
90                 fprintf(stderr, 
91         "[%s:%d]: Couldn't make DYNINSTstaticHeap_4M_anyHeap_1 executable!\n",
92               __FILE__, __LINE__);
93                 perror( "_start" );
94    }
95         RTprintf("*** Marked memory from 0x%lx to 0x%lx executable.\n", 
96             alignedHeapPointer, 
97             alignedHeapPointer + adjustedSize );
98
99         /* Mark _both_ heaps executable. */
100         alignedHeapPointer = (unsigned long int) DYNINSTstaticHeap_32K_lowmemHeap_1;
101         adjustedSize = alignedHeapPointer + 32 * 1024;
102         alignedHeapPointer = (alignedHeapPointer) & ~(pageSize - 1);
103         adjustedSize -= alignedHeapPointer;
104
105         /* Make the heap's page executable. */
106    result = mprotect((void *) alignedHeapPointer, (size_t) adjustedSize, 
107                      PROT_READ | PROT_WRITE | PROT_EXEC );
108    if (result != 0 ) 
109    {
110                 fprintf(stderr, 
111         "[%s:%d]: Couldn't make DYNINSTstaticHeap_4M_anyHeap_1 executable!\n",
112               __FILE__, __LINE__);
113                 perror( "_start" );
114    }
115         RTprintf("*** Marked memory from 0x%lx to 0x%lx executable.\n", 
116             alignedHeapPointer, alignedHeapPointer + adjustedSize );
117 }
118 #endif
119
120 #if defined(arch_ia64)
121 /* Ensure we an executable block of memory. */
122 void R_BRK_TARGET() {
123         /* Make sure we've got room for two bundles. */
124         asm( "nop 0" ); asm( "nop 0" ); asm( "nop 0" );
125         asm( "nop 0" ); asm( "nop 0" ); asm( "nop 0" );
126         }
127
128 #endif /*arch_ia64*/
129
130 /************************************************************************
131  * void DYNINSTos_init(void)
132  *
133  * OS initialization function
134 ************************************************************************/
135
136 void DYNINSTos_init(int calledByFork, int calledByAttach)
137 {
138     RTprintf("DYNINSTos_init(%d,%d)\n", calledByFork, calledByAttach);
139 }
140
141 typedef struct dlopen_args {
142   const char *libname;
143   int mode;
144   void *result;
145   void *caller;
146 } dlopen_args_t;
147
148 void *(*DYNINST_do_dlopen)(dlopen_args_t *) = NULL;
149
150 static int get_dlopen_error() {
151    char *err_str;
152    err_str = dlerror();
153    if (err_str) {
154       strncpy(gLoadLibraryErrorString, err_str, (size_t) ERROR_STRING_LENGTH);
155       return 1;
156    }
157    else {
158       sprintf(gLoadLibraryErrorString,"unknown error with dlopen");
159       return 0;
160    }
161    return 0;
162 }
163
164 int DYNINSTloadLibrary(char *libname)
165 {
166    void *res;
167    gLoadLibraryErrorString[0]='\0';
168    gBRKptr = sbrk(0);
169    res = dlopen(libname, RTLD_NOW | RTLD_GLOBAL);
170    if (res)
171    {
172       return 1;
173    }
174  
175    get_dlopen_error();
176 #if defined(arch_x86)
177    /* dlopen on recent glibcs has a "security check" so that
178       only registered modules can call it. Unfortunately, progs
179       that don't include libdl break this check, so that we
180       can only call _dl_open (the dlopen worker function) from
181       within glibc. We do this by calling do_dlopen
182       We fool this check by calling an addr written by the
183       mutator */
184    if (strstr(gLoadLibraryErrorString, "invalid caller") != NULL &&
185        DYNINST_do_dlopen != NULL) {
186       dlopen_args_t args;
187       args.libname = libname;
188       args.mode = RTLD_NOW | RTLD_GLOBAL;
189       args.result = 0;
190       args.caller = (void *)DYNINST_do_dlopen;
191       // There's a do_dlopen function in glibc. However, it's _not_
192       // exported; thus, getting the address is a bit of a pain. 
193       
194       (*DYNINST_do_dlopen)(&args);
195       // Duplicate the above
196       if (args.result != NULL)
197       {
198          return 1;
199       }
200       else
201          get_dlopen_error();
202    }
203 #endif
204    return 0;
205 }
206
207 //Define this value so that we can compile on a system that doesn't have
208 // gettid and still run on one that does.
209 #if !defined(SYS_gettid)
210
211 #if defined(arch_x86)
212 #define SYS_gettid 224
213 #elif defined(arch_x86_64)
214 #define SYS_gettid 186
215 #elif defined(arch_ia64)
216 #define SYS_gettid 1105
217 #endif
218
219 #endif
220
221 int dyn_lwp_self()
222 {
223    static int gettid_not_valid = 0;
224    int result;
225
226    if (gettid_not_valid)
227       return getpid();
228
229    result = syscall((long int) SYS_gettid);
230    if (result == -1 && errno == ENOSYS)
231    {
232       gettid_not_valid = 1;
233       return getpid();
234    }
235    return result;  
236 }
237
238 int dyn_pid_self()
239 {
240    return getpid();
241 }
242
243 dyntid_t (*DYNINST_pthread_self)(void);
244 dyntid_t dyn_pthread_self()
245 {
246    dyntid_t me;
247    if (!DYNINST_pthread_self) {
248       return (dyntid_t) -1;
249    }
250    me = (*DYNINST_pthread_self)();
251    return (dyntid_t) me;
252 }
253
254
255 /**
256  * We need to extract certain pieces of information from the usually opaque 
257  * type pthread_t.  Unfortunately, libc doesn't export this information so 
258  * we're reverse engineering it out of pthread_t.  The following structure
259  * tells us at what offsets it look off of the return value of pthread_self
260  * for the lwp, pid, initial start function (the one passed to pthread_create)
261  * and the top of this thread's stack.  We have multiple entries in positions, 
262  * one for each different version of libc we've seen.
263  **/
264 #define READ_FROM_BUF(pos, type) *((type *)(buffer+pos))
265
266 typedef struct pthread_offset_t
267 {
268    unsigned lwp_pos;
269    unsigned pid_pos;
270    unsigned start_func_pos;
271    unsigned stck_start_pos;
272 } pthread_offset_t;
273
274 #if defined(arch_x86)
275 #define POS_ENTRIES 3
276 static pthread_offset_t positions[POS_ENTRIES] = { { 72, 476, 516, 576 },
277                                                    { 72, 76, 516, 84 },
278                                                    { 72, 476, 516, 80 } };
279 #else
280 //x86_64 and ia64 share structrues
281 #define POS_ENTRIES 1
282 static pthread_offset_t positions[POS_ENTRIES] = { { 144, 952, 1008, 160 } };
283 #endif
284
285 int DYNINSTthreadInfo(BPatch_newThreadEventRecord *ev)
286 {
287   static int err_printed = 0;
288   int i;
289   char *buffer;
290
291   ev->stack_addr = 0x0;
292   ev->start_pc = 0x0;
293   buffer = (char *) ev->tid;
294   
295   for (i = 0; i < POS_ENTRIES; i++)
296   {
297      if ((READ_FROM_BUF(positions[i].pid_pos, pid_t) != ev->ppid) ||
298          (READ_FROM_BUF(positions[i].lwp_pos, int) != ev->lwp))
299         continue;
300      ev->stack_addr = READ_FROM_BUF(positions[i].stck_start_pos, void *);
301      ev->start_pc = READ_FROM_BUF(positions[i].start_func_pos, void *);
302      return 1;
303   }
304   
305   if (!err_printed)
306   {
307     //If you get this error, then Dyninst is having trouble figuring out
308     //how to read the information from the positions structure above.
309     //It needs a new entry filled in.  Running the commented out program
310     //that follows this function can help you collect the necessary data.
311     fprintf(stderr, "[%s:%d] Unable to parse the pthread_t structure for this"
312             " version of libpthread.  Making a best guess effort.\n", 
313             __FILE__, __LINE__);
314     err_printed = 1;
315   }
316    
317   return 1;
318 }
319
320
321 /*
322 //Small program for finding the correct values to fill in pos_in_pthreadt
323 // above
324 #include <pthread.h>
325 #include <stdio.h>
326 #include <sys/syscall.h>
327 #include <sys/types.h>
328 #include <unistd.h>
329
330 #define gettid() syscall(SYS_gettid)
331
332 pthread_attr_t attr;
333
334 void *foo(void *f) {
335   pid_t pid, tid;
336   unsigned stack_addr;
337   unsigned best_stack = 0xffffffff;
338   int best_stack_pos = 0;
339   void *start_func;
340   int *p;
341   int i = 0;
342   pid = getpid();
343   tid = gettid();
344   start_func = foo;
345   //x86 only.  
346   asm("movl %%ebp,%0" : "=r" (stack_addr));
347   p = (int *) pthread_self();
348   while (i < 1000)
349   {
350     if (*p == (unsigned) pid)
351       printf("pid @ %d\n", i);
352     if (*p == (unsigned) tid)
353       printf("lwp @ %d\n", i);
354     if (*p > stack_addr && *p < best_stack)
355     {
356       best_stack = *p;
357       best_stack_pos = i;
358     }
359     if (*p == (unsigned) start_func)
360       printf("func @ %d\n", i);
361     i += sizeof(int);
362     p++;
363   }  
364   printf("stack @ %d\n", best_stack_pos);
365   return NULL;
366 }
367
368 int main(int argc, char *argv[])
369 {
370   pthread_t t;
371   void *result;
372   pthread_attr_init(&attr);
373   pthread_create(&t, &attr, foo, NULL);
374   pthread_join(t, &result);
375   return 0;
376 }
377 */