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