Fixes for bug 1081, bug 1104 (fork test bugs)
[dyninst.git] / dyninstAPI_RT / src / RTaix.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  * RTaix.c: mutatee-side library function specific to AIX
34 ************************************************************************/
35
36 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
37 #include "RTthread.h"
38 #include <dlfcn.h> /* dlopen constants */
39 #include <stdio.h>
40 #include <pthread.h>
41 #include <unistd.h>
42 #include <signal.h>
43
44 /************************************************************************
45  * void DYNINSTos_init(void)
46  *
47  * os initialization function
48 ************************************************************************/
49
50 void DYNINSTstaticHeap_1048576_textHeap_libSpace(void);
51
52 void DYNINSTbreakPoint()
53 {
54     /* We set a global flag here so that we can tell
55        if we're ever in a call to this when we get a 
56        SIGBUS */
57    /*
58    int thread_index = DYNINSTthreadIndex();
59    */
60     DYNINST_break_point_event = 1;
61     while (DYNINST_break_point_event)  {
62         kill(getpid(), DYNINST_BREAKPOINT_SIGNUM);
63     }
64     /* Mutator resets to 0... */
65 }
66
67
68 void DYNINSTsafeBreakPoint()
69 {
70     DYNINST_break_point_event = 2; /* Not the same as above */
71
72     // We cannot send SIGSTOPs to ourselves - it triggers kernel
73     // bugs on exit -> see bug 1081
74
75     // We can now use SIGTRAPs in this situation because we
76     // can now trust that the child will be traced on exit from
77     // fork
78     kill(getpid(), SIGTRAP);
79 }
80
81 void DYNINSTos_init(int calledByFork, int calledByAttach)
82 {
83    /* Text heap initialization. Call this to force the library to
84       be included by the linker */
85 #ifdef USES_LIB_TEXT_HEAP
86    /* Dummy call to get the library space actually included
87       (not pruned by an optimizing linker) */
88    DYNINSTstaticHeap_1048576_textHeap_libSpace();
89 #endif
90 }
91
92 #define NOT_SETUP_ERR 0x2468ace0
93
94 int DYNINSTloadLibrary(char *libname)
95 {
96    void *res;
97    char *err_str;
98    gLoadLibraryErrorString[0]='\0';
99    
100    if (NULL == (res = dlopen(libname, RTLD_NOW | RTLD_GLOBAL))) {
101       /* An error has occurred */
102       //perror( "DYNINSTloadLibrary -- dlopen" );
103     
104       if (NULL != (err_str = dlerror()))
105          strncpy(gLoadLibraryErrorString, err_str, ERROR_STRING_LENGTH);
106       else 
107          sprintf(gLoadLibraryErrorString,"unknown error with dlopen");
108       
109       /*fprintf(stderr, "%s[%d]: %s\n", __FILE__, __LINE__,
110                 gLoadLibraryErrorString);*/
111       return 0;  
112    } else
113       return 1;
114 }
115
116 void DYNINST_ThreadPInfo(void* tls, void** stkbase, dyntid_t* tid, 
117                          long *pc, int* lwp, void** rs) 
118 {
119    /* Use the __pthrdsinfo struct defined in /usr/include/pthread.h */
120    struct __pthrdsinfo *ptr = (struct __pthrdsinfo *) tls;
121    /* Want: 
122       Stack base
123       TID
124       initial PC (entry to provided "start" function)
125       LWP
126       RS (thread context)
127    */
128    *stkbase = (void *) ptr->__pi_stackaddr;
129    *tid = ptr->__pi_ptid; /* pthread_t as opposed to tid_t */
130    *pc = ptr->__pi_func;
131    *lwp = ptr->__pi_tid;
132    *rs = (void *) (&ptr->__pi_context);
133 }
134
135 int DYNINSTthreadInfo(BPatch_newThreadEventRecord *ev)
136 {
137    struct __pthrdsinfo pthread_desc;
138    int pthread_desc_size = sizeof(struct __pthrdsinfo);
139    int registers[1024];
140    int regsize = 1024*sizeof(int);
141
142    dyntid_t tidp;
143    int lwpid;
144    long startpc;
145    void *stkbase, *rs_p;
146
147    int result;
148
149    pthread_t pthread_id;
150    pthread_id = (pthread_t) dyn_pthread_self();
151
152    result = dyn_pthread_getthrds_np(&pthread_id, PTHRDSINFO_QUERY_ALL,
153                                     &pthread_desc, pthread_desc_size,
154                                     registers, &regsize);
155    if (result)
156    {
157       if (result != NOT_SETUP_ERR)
158          perror("RTthread-aix:DYNINST_ThreadInfo");
159       else
160          fprintf(stderr, "[%s:%u] - TInfo not yet setup\n", __FILE__, __LINE__);
161       return 0;
162    }
163
164    DYNINST_ThreadPInfo((void *)&pthread_desc, &stkbase, &tidp, &startpc, 
165                        &lwpid, &rs_p);
166
167    ev->stack_addr = stkbase;
168    ev->start_pc = (void *) startpc;
169
170    /*
171    fprintf(stderr, "DYNINST_ThreadInfo, stkbase=%x, tid=%d, " 
172            "startpc=%x, lwp=%d, resumestate=%x\n",
173            (unsigned) *stkbase, *tidp, *startpc, *lwpid, (unsigned)*rs_p);
174    */
175           
176    return 1;
177 }
178
179 int dyn_pid_self()
180 {
181    return getpid();
182 }
183
184 int dyn_lwp_self()
185 {
186    return thread_self();
187 }
188
189 typedef struct {
190    void *func;
191    unsigned toc;
192    void *dummy;
193 } call_record_t;
194 typedef dyntid_t (*DYNINST_pself_t)(void);
195 typedef int (*DYNINST_pgetthrds_np_t)(pthread_t *, int, struct __pthrdsinfo *, 
196                                       int, void *, int *);
197
198 call_record_t DYNINST_pthread_self_record;
199 DYNINST_pself_t DYNINST_pthread_self = 
200     (DYNINST_pself_t) &DYNINST_pthread_self_record;
201 dyntid_t dyn_pthread_self()
202 {
203    if (!DYNINST_pthread_self_record.func)
204    {
205       return (void *) DYNINST_SINGLETHREADED;
206    }
207    return (*DYNINST_pthread_self)();
208 }
209
210 call_record_t DYNINST_pthread_getthrds_np_record;
211 DYNINST_pgetthrds_np_t DYNINST_pthread_getthrds_np =
212    (DYNINST_pgetthrds_np_t) &DYNINST_pthread_getthrds_np_record;
213 int dyn_pthread_getthrds_np(pthread_t *thread, int mode, 
214                             struct __pthrdsinfo *buf, int bufsize,
215                             void *regbuf, int *regbufsize)
216 {
217    if (!DYNINST_pthread_getthrds_np_record.func)
218    {
219       return NOT_SETUP_ERR;
220    }
221    return (*DYNINST_pthread_getthrds_np)(thread, mode, buf, bufsize, 
222                                          regbuf, regbufsize);
223 }
224
225 /* 
226    We reserve index 0 for the initial thread. This value varies by
227    platform but is always constant for that platform. Wrap that
228    platform-ness here. 
229 */
230 int DYNINST_am_initial_thread(dyntid_t tid) {
231     return (tid == (dyntid_t) 1);
232 }