Corrected comment syntax
[dyninst.git] / dyninstAPI_RT / src / RTsolaris.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: RTsolaris.c,v 1.32 2006/12/14 20:39:18 legendre Exp $
44  * RTsolaris.c: mutatee-side library function specific to Solaris
45  ************************************************************************/
46
47 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
48
49 #include <signal.h>
50 #include <sys/ucontext.h>
51 #include <assert.h>
52 #include <stdio.h>
53 #include <dlfcn.h>
54
55 #include <sys/procfs.h> /* /proc PIOCUSAGE */
56 #include <fcntl.h> /* O_RDONLY */
57 #include <unistd.h> /* getpid() */
58 #include <string.h>
59 #include <stdlib.h>
60
61
62 #ifdef i386_unknown_solaris2_5
63 void DYNINSTtrapHandler(int sig, siginfo_t *info, ucontext_t *uap);
64
65 extern struct sigaction DYNINSTactTrap;
66 extern struct sigaction DYNINSTactTrapApp;
67 #endif
68
69 /************************************************************************
70  * void DYNINSTos_init(void)
71  *
72  * OS initialization function
73 ************************************************************************/
74
75 void DYNINSTbreakPoint()
76 {
77     /* We set a global flag here so that we can tell
78        if we're ever in a call to this when we get a 
79        SIGBUS */
80    /*
81    int thread_index = DYNINSTthreadIndex();
82    */
83     DYNINST_break_point_event = 1;
84     while (DYNINST_break_point_event)  {
85         kill(getpid(), DYNINST_BREAKPOINT_SIGNUM);
86     }
87     /* Mutator resets to 0... */
88 }
89
90
91 void DYNINSTsafeBreakPoint()
92 {
93     DYNINST_break_point_event = 2; /* Not the same as above */
94     while (DYNINST_break_point_event)
95         kill(getpid(), SIGSTOP);
96 }
97
98 extern void DYNINSTheap_setbounds();  /* RTheap-solaris.c */
99
100 void
101 DYNINSTos_init(int calledByFork, int calledByAttach)
102 {
103     RTprintf("DYNINSTos_init(%d,%d)\n", calledByFork, calledByAttach);
104     DYNINSTheap_setbounds();
105     /* uncomment this if you want instrumentation written out in core files */
106     /* setmemwrite(); */
107 }
108
109 int DYNINSTloadLibrary(char *libname)
110 {
111   void *res;
112   char *err_str;
113   gLoadLibraryErrorString[0]='\0';
114   
115   if (NULL == (res = dlopen(libname, RTLD_NOW | RTLD_GLOBAL))) {
116     /* An error has occurred */
117     //perror( "DYNINSTloadLibrary -- dlopen" );
118     
119     if (NULL != (err_str = dlerror()))
120       strncpy(gLoadLibraryErrorString, err_str, ERROR_STRING_LENGTH);
121     else 
122       sprintf(gLoadLibraryErrorString,"unknown error with dlopen");
123     
124     fprintf(stderr, "%s[%d]: %s\n",__FILE__,__LINE__,gLoadLibraryErrorString);
125     return 0;  
126   } else
127     return 1;
128 }
129
130
131 /*
132 We can get Solaris to put instrumented code in the core file of dumped
133 mutatees by setting setting WRITE protection on all pages in the
134 process (SHARED text pages cannot have WRITE protect set).
135
136 To use, compile and link this code with the runtime library, and call
137 setmemwrite from DYNINSTinit.
138 */
139
140 /* Set every page in this process to be writable to
141    cause pages with instrumented code to be saved in core dumps. */
142 #include <sys/types.h>
143 #include <sys/mman.h>
144 #include <sys/procfs.h>
145 #define maxpmap 512
146 static
147 int setmemwrite()
148 {
149     int pfd, numpmap, i;
150     prmap_t pmap[maxpmap];
151
152     char buf[32];
153     sprintf(buf, "/proc/%05d", getpid());
154     pfd = open(buf, O_RDONLY);
155     if (0 > pfd) {
156          perror("open (in setmemwrite)");
157          fprintf(stderr, "Can't open /proc on myself\n");
158          exit(1);
159     }
160     if (0 > ioctl(pfd, PIOCNMAP, &numpmap)) {
161          perror("PIOCNMAP (in setmemwrite)");
162          exit(1);
163     }
164     if (numpmap + 1 > maxpmap) {
165          fprintf(stderr, "Too many memory mappings\n");
166          exit(1);
167     }
168     if (0 > ioctl(pfd, PIOCMAP, pmap)) {
169          perror("PIOCMAP (in setmemwrite)");
170          exit(1);
171     }
172     for (i = 0; i < numpmap; i++) {
173          prmap_t *p = &pmap[i];
174          /* Enable WRITE if this region does not have it already and
175             we won't get in trouble for setting it (i.e., it is not
176             SHARED). */
177          if (~p->pr_mflags & MA_WRITE
178              && ~p->pr_mflags & MA_SHARED)
179               if (0 > mprotect(p->pr_vaddr, p->pr_size,
180                                PROT_WRITE
181                                | PROT_READ
182                                | (p->pr_mflags & MA_EXEC ? PROT_EXEC : 0))) {
183                    perror("mprotect (in setmemwrite)");
184                    fprintf(stderr, "mprotect (it %d) args: %#010x, %x, %x\n",
185                            i,
186                            p->pr_vaddr, p->pr_size, 
187                            PROT_WRITE
188                            | PROT_READ
189                            | (p->pr_mflags & MA_EXEC ? PROT_EXEC : 0));
190                    exit(1);
191               }
192     }
193     close(pfd);
194     return 0;
195 }
196
197
198 /*********************************************************
199  *** MULTITHREAD
200  *********************************************************/
201
202 #include <thread.h>
203 #include <sys/lwp.h>
204
205 dyntid_t (*DYNINST_pthread_self)(void);
206 dyntid_t dyn_pthread_self()
207 {
208    dyntid_t me;
209    if (!DYNINST_pthread_self) {
210        return (dyntid_t) DYNINST_SINGLETHREADED;
211    }
212    me = (*DYNINST_pthread_self)();
213    return (dyntid_t) me;
214 }
215
216 int dyn_pid_self()
217 {
218    return getpid();
219 }
220
221 int dyn_lwp_self()
222 {
223    return _lwp_self();
224 }
225
226 /* New approach - from Linux. Store offsets rather than
227    structures. Mo' easia. */
228
229 typedef struct pthread_offset_t
230 {
231   unsigned thr_pos;
232   unsigned lwp_pos;
233   unsigned start_func_pos;
234   unsigned stck_start_pos;
235 } pthread_offset_t;
236
237
238 /* Increase when we get more types... like Solaris 2.10 */
239 #define POS_ENTRIES 2
240
241 static pthread_offset_t positions[POS_ENTRIES] = {
242   { 18, 19, 17, 2 }, /* shemesh.cs.wisc.edu, Sol 2.8 */
243   { 16, 17, 50, 11} /* adams.cs.umd.edu, Sol 2.9. thr_pos and lwp_pos
244                         may be reversed, as the values were identical
245                         in tests. */
246 };
247
248 void DYNINST_ThreadPInfo(void* tls, void** stkbase, long *pc)
249 {
250   static int w = -1;
251   dyntid_t tid;
252   int lwp;
253   int i;
254   int *tls_int = (int *)tls;
255
256   *stkbase = 0;
257   *pc = 0;
258
259   /*if (w) return w;*/
260   tid = dyn_pthread_self();
261   if (tid == (dyntid_t) -1)
262       return;
263   lwp = dyn_lwp_self();
264
265   /* Find the right type... */
266   if (w == -1) {
267     for (i = 0; i < POS_ENTRIES; i++) {
268       if ((tls_int[positions[i].thr_pos] == (int) tid) &&
269           (tls_int[positions[i].lwp_pos] == lwp)) {
270         w = i;
271
272         break;
273       }
274     }
275   }
276   if (w == -1) {
277     /* Couldn't find... */
278     return;
279   }
280
281   *stkbase = (void *) tls_int[positions[w].stck_start_pos];
282   *pc = tls_int[positions[w].start_func_pos];
283
284   return;
285 }
286
287
288 /* Defined in RTthread-sparc-asm.s, access %g7 */
289 void *DYNINST_curthread(void) ;
290
291 int DYNINSTthreadInfo(BPatch_newThreadEventRecord *ev) {
292     dyntid_t tidp;
293     int lwpid;
294     long startpc;
295     void *stkbase, *rs_p;
296     void *curthread = DYNINST_curthread();
297     if ( curthread != NULL ) {
298         DYNINST_ThreadPInfo(curthread, &stkbase, &startpc);
299         ev->stack_addr = stkbase;
300         ev->start_pc = (void *)startpc;
301         return 1;
302     }
303     return 0;
304 }
305
306 /* 
307    We reserve index 0 for the initial thread. This value varies by
308    platform but is always constant for that platform. Wrap that
309    platform-ness here. 
310 */
311 int DYNINST_am_initial_thread(dyntid_t tid) {
312     return (tid == (dyntid_t) 1);
313 }
314