fixes for gcc 4
[dyninst.git] / dyninstAPI / src / syscall-solproc.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 // $Id: syscall-solproc.C,v 1.21 2008/09/15 18:37:49 jaw Exp $
43
44 #if defined(os_aix)
45 #include <sys/procfs.h>
46 #else
47 #include <procfs.h>
48 #endif
49 #include "common/h/headers.h"
50 #include "dyninstAPI/src/inst.h"
51 #include "dyninstAPI/src/syscallNotification.h"
52 #include "dyninstAPI/src/sol_proc.h"
53 #include "dyninstAPI/src/process.h"
54 #include "dyninstAPI/src/miniTramp.h"
55 #include "dyninstAPI/src/EventHandler.h"
56 #include "dyninstAPI/src/symtab.h"
57
58 #include "dyninstAPI/src/ast.h"
59
60 #define FORK_FUNC "fork"
61 #define FORK_LIB  "libc.a"
62
63 #define LWP_EXIT_FUNC "_thr_exit_common"
64
65 syscallNotification::syscallNotification(syscallNotification *parentSN,
66                                          process *child) :
67     preForkInst(parentSN->preForkInst),
68     postForkInst(parentSN->postForkInst),
69     preExecInst(parentSN->preExecInst),
70     postExecInst(parentSN->postExecInst),
71     preExitInst(parentSN->preExitInst),
72     preLwpExitInst(parentSN->preLwpExitInst),
73     proc(child) {
74
75     // We set PR_FORK in the parent, so everything was copied.
76     
77     if (parentSN->postForkInst &&
78         (parentSN->postForkInst != SYSCALL_INSTALLED))
79         postForkInst = new instMapping(parentSN->postForkInst, child);
80
81     // I thought we needed this for a while, but we don't. Leave it here 
82     // anyway
83     if (parentSN->preLwpExitInst &&
84         (parentSN->preLwpExitInst != SYSCALL_INSTALLED))
85         preLwpExitInst = new instMapping(parentSN->preLwpExitInst, child);
86
87 }
88
89 /////////// Prefork instrumentation 
90
91 bool syscallNotification::installPreFork() {
92     // Get existing flags, add pre-fork, and set
93     SYSSET_DECLAREPID(proc_pid, proc->getPid());
94     
95     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
96     
97     if (!proc->get_entry_syscalls(entryset)) return false;
98
99     if (SYSSET_MAP(SYS_fork, proc_pid) != -1) {
100         praddsysset(entryset, SYSSET_MAP(SYS_fork, proc_pid));
101     }
102     if (SYSSET_MAP(SYS_fork1, proc_pid) != -1) {
103         praddsysset(entryset, SYSSET_MAP(SYS_fork1, proc_pid));
104     }
105     if (SYSSET_MAP(SYS_vfork, proc_pid) != -1) {
106         praddsysset(entryset, SYSSET_MAP(SYS_vfork, proc_pid));
107     }
108     if (!proc->set_entry_syscalls(entryset)) return false;;
109     SYSSET_FREE(entryset);
110     // Make sure our removal code gets run
111     preForkInst = SYSCALL_INSTALLED;
112     return true;
113 }
114
115 /////////// Postfork instrumentation
116
117 bool syscallNotification::installPostFork() 
118 {
119 #if defined(os_aix)
120     /* Block-comment
121        
122     On AIX, for reasons which are unclear, we cannot count on the OS
123     to copy the address space of the parent to the child on fork. In
124     particular, library text and the a.out text are _not_
125     copied. Areas allocated with mmap (data areas, effectively) are.
126
127     Also, if we tell the process to stop (via /proc) on the exit of
128     fork, we see one of two cases: either the child does not stop (AIX
129     5.1), or the child stops in an unmodifiable state (AIX
130     5.2). Neither is acceptable.
131
132     Our solution is to use instrumentation at the exit of
133     fork(). However, this is complicated by the non-copy behavior of
134     AIX. Our solution is relocation; we ensure that the fork() that is
135     executed is located in a data area. As a result, it is copied to
136     the child, and the child picks up executing there.
137     */
138
139
140     AstNodePtr returnVal = AstNode::operandNode(AstNode::ReturnVal, (void *)0);
141     std::string ffunc(FORK_FUNC);
142     std::string ftarget("Dyninst_instForkExit");
143     std::string flib(FORK_LIB);
144     postForkInst = new instMapping(ffunc, ftarget,
145                                    FUNC_EXIT|FUNC_ARG,
146                                    returnVal,
147                                    flib);
148 #if 0
149     postForkInst = new instMapping(FORK_FUNC, "DYNINST_instForkExit",
150                                    FUNC_EXIT|FUNC_ARG,
151                                    returnVal,
152                                    FORK_LIB);
153 #endif
154     postForkInst->dontUseTrampGuard();
155     
156     pdvector<instMapping *> instReqs;
157     instReqs.push_back(postForkInst);
158     
159     proc->installInstrRequests(instReqs);
160     
161     // Check to see if we put anything in the proggie
162     if (postForkInst->miniTramps.size() == 0) {
163        fprintf(stderr, "%s[%d]:  WARNING:  failed to generate inst for post-fork\n", 
164              FILE__, __LINE__);
165         return false;
166     }
167     return true;
168 #else
169     // Get existing flags, add post-fork, and set
170     SYSSET_DECLAREPID(proc_pid,proc->getPid()); 
171     
172     sysset_t *exitset = SYSSET_ALLOC(proc_pid);
173     
174     if (!proc->get_exit_syscalls(exitset)) return false;;
175
176     if (SYSSET_MAP(SYS_fork, proc_pid) != -1) {
177         praddsysset(exitset, SYSSET_MAP(SYS_fork, proc_pid));
178     }
179     if (SYSSET_MAP(SYS_fork1, proc_pid) != -1) {
180         praddsysset(exitset, SYSSET_MAP(SYS_fork1, proc_pid));
181     }
182     if (SYSSET_MAP(SYS_vfork, proc_pid) != -1) {
183         praddsysset(exitset, SYSSET_MAP(SYS_vfork, proc_pid));
184     }
185     if (!proc->set_exit_syscalls(exitset)) return false;;
186     SYSSET_FREE(exitset);
187     // Make sure our removal code gets run
188     postForkInst = SYSCALL_INSTALLED;
189     return true;
190 #endif
191 }    
192
193 /////////// Pre-exec instrumentation
194
195 bool syscallNotification::installPreExec() {
196     // Get existing flags, add pre-exec, and set
197     SYSSET_DECLAREPID(proc_pid,proc->getPid());
198     
199     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
200     
201     if (!proc->get_entry_syscalls(entryset)) return false;;
202
203     if (SYSSET_MAP(SYS_exec, proc_pid) != -1) {
204         praddsysset(entryset, SYSSET_MAP(SYS_exec, proc_pid));
205     }
206     if (SYSSET_MAP(SYS_execve, proc_pid) != -1) {
207         praddsysset(entryset, SYSSET_MAP(SYS_execve, proc_pid));
208     }
209     if (!proc->set_entry_syscalls(entryset)) return false;;
210     SYSSET_FREE(entryset);
211     // Make sure our removal code gets run
212     preExecInst = SYSCALL_INSTALLED;
213     return true;
214 }    
215
216 //////////// Post-exec instrumentation
217
218 bool syscallNotification::installPostExec() {
219     // Get existing flags, add post-exec, and set
220     SYSSET_DECLAREPID(proc_pid,proc->getPid());
221     
222     sysset_t *exitset = SYSSET_ALLOC(proc_pid);
223     
224     if (!proc->get_exit_syscalls(exitset)) return false;;
225
226     if (SYSSET_MAP(SYS_exec, proc_pid) != -1) {
227         praddsysset(exitset, SYSSET_MAP(SYS_exec, proc_pid));
228     }
229     if (SYSSET_MAP(SYS_execve, proc_pid) != -1) {
230         praddsysset(exitset, SYSSET_MAP(SYS_execve, proc_pid));
231     }
232     if (!proc->set_exit_syscalls(exitset)) return false;;
233     SYSSET_FREE(exitset);
234     // Make sure our removal code gets run
235     postExecInst = SYSCALL_INSTALLED;
236     return true;
237 }    
238
239 /////////// Pre-exit instrumentation
240
241 bool syscallNotification::installPreExit() {
242     // Get existing flags, add pre-exit, and set
243     SYSSET_DECLAREPID(proc_pid, proc->getPid());
244     
245     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
246     
247     if (!proc->get_entry_syscalls(entryset)) return false;;
248
249     if (SYSSET_MAP(SYS_exit, proc_pid) != -1) {
250         praddsysset(entryset, SYSSET_MAP(SYS_exit, proc_pid));
251     }
252     if (!proc->set_entry_syscalls(entryset)) return false;;
253     // Make sure our removal code gets run
254     preExitInst = SYSCALL_INSTALLED;
255     SYSSET_FREE(entryset);
256     return true;
257 }    
258
259
260 /////////// Pre-lwp-exit instrumentation
261
262 bool syscallNotification::installPreLwpExit() {
263     // Get existing flags, add pre-lwp-exit, and set
264     SYSSET_DECLAREPID(proc_pid, proc->getPid());
265     
266     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
267     
268     if (!proc->get_entry_syscalls(entryset)) return false;;
269
270     if (SYSSET_MAP(SYS_lwp_exit, proc_pid) != -1) {
271         praddsysset(entryset, SYSSET_MAP(SYS_lwp_exit, proc_pid));
272     }
273     if (!proc->set_entry_syscalls(entryset)) return false;;
274     // Make sure our removal code gets run
275     preLwpExitInst = SYSCALL_INSTALLED;
276     SYSSET_FREE(entryset);
277
278     return true;
279
280 #if 0
281     preLwpExitInst = new instMapping(LWP_EXIT_FUNC, "DYNINST_instLwpExit",
282                                    FUNC_ENTRY);
283     preLwpExitInst->dontUseTrampGuard();
284     
285     pdvector<instMapping *> instReqs;
286     instReqs.push_back(preLwpExitInst);
287     
288     proc->installInstrRequests(instReqs);
289     
290     // Check to see if we put anything in the proggie
291     if (preLwpExitInst->miniTramps.size() == 0)
292         return false;
293     return true;
294 #endif
295 }    
296
297
298 //////////////////////////////////////////////////////
299
300 /////// Remove pre-fork instrumentation
301
302 bool syscallNotification::removePreFork() {
303     if (!preForkInst) return false;
304     if (!proc->isAttached() || proc->execing()) {
305         preForkInst = NULL;
306         return true;
307     }
308     
309     // Get existing flags, add pre-fork, and set
310     SYSSET_DECLAREPID(proc_pid,proc->getPid());
311     
312     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
313     
314     if (!proc->get_entry_syscalls(entryset)) return false;;
315
316     if (SYSSET_MAP(SYS_fork, proc_pid) != -1) {
317         prdelsysset(entryset, SYSSET_MAP(SYS_fork, proc_pid));
318     }
319     if (SYSSET_MAP(SYS_fork1, proc_pid) != -1) {
320         prdelsysset(entryset, SYSSET_MAP(SYS_fork1, proc_pid));
321     }
322     if (SYSSET_MAP(SYS_vfork, proc_pid) != -1) {
323         prdelsysset(entryset, SYSSET_MAP(SYS_vfork, proc_pid));
324     }
325     if (!proc->set_entry_syscalls(entryset)) return false;;
326     SYSSET_FREE(entryset);
327     preForkInst = NULL;
328     return true;
329 }
330
331 /////// Remove post-fork instrumentation
332
333 bool syscallNotification::removePostFork() {
334     if (!postForkInst) return false;
335
336     if (postForkInst != SYSCALL_INSTALLED) {
337         if (!proc->isAttached() || proc->execing()) {
338             delete postForkInst;
339             postForkInst = NULL;
340             return true;
341         }
342         
343         miniTramp *handle;
344         for (unsigned i = 0; i < postForkInst->miniTramps.size(); i++) {
345             handle = postForkInst->miniTramps[i];
346             
347             bool removed = handle->uninstrument();
348             // At some point we should handle a negative return... but I
349             // have no idea how.
350             
351             assert(removed);
352             // The miniTramp is deleted when the miniTramp is freed, so
353             // we don't have to.
354         } 
355         delete postForkInst;
356         postForkInst = NULL;
357         return true;
358     }
359     
360     // else...
361
362     if (!proc->isAttached() || proc->execing()) {
363         postForkInst = NULL;
364         return true;
365     }
366
367     // Get existing flags, add post-fork, and set
368     SYSSET_DECLAREPID(proc_pid,proc->getPid());
369     
370     sysset_t *exitset = SYSSET_ALLOC(proc_pid);
371     
372     if (!proc->get_exit_syscalls(exitset)) return false;;
373
374     if (SYSSET_MAP(SYS_fork, proc_pid) != -1) {
375         prdelsysset(exitset, SYSSET_MAP(SYS_fork, proc_pid));
376     }
377     if (SYSSET_MAP(SYS_fork1, proc_pid) != -1) {
378         prdelsysset(exitset, SYSSET_MAP(SYS_fork1, proc_pid));
379     }
380     if (SYSSET_MAP(SYS_vfork, proc_pid) != -1) {
381         prdelsysset(exitset, SYSSET_MAP(SYS_vfork, proc_pid));
382     }
383     if (!proc->set_exit_syscalls(exitset)) return false;;
384     SYSSET_FREE(exitset);
385     postForkInst = NULL;
386     return true;
387 }
388
389 /////// Remove pre-exec instrumentation
390
391 bool syscallNotification::removePreExec() {
392     if (!preExecInst) {
393         bperr("Tracing never installed\n");
394         return false;
395     }
396     
397     if (!proc->isAttached() || proc->execing()) {
398         preExecInst = NULL;
399         return true;
400     }
401
402     // Get existing flags, add pre-exec, and set
403     SYSSET_DECLAREPID(proc_pid,proc->getPid());
404     
405     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
406     
407     if (!proc->get_entry_syscalls(entryset)) return false;;
408
409     if (SYSSET_MAP(SYS_exec, proc_pid) != -1) {
410         prdelsysset(entryset, SYSSET_MAP(SYS_exec, proc_pid));
411     }
412     if (SYSSET_MAP(SYS_execve, proc_pid) != -1) {
413         prdelsysset(entryset, SYSSET_MAP(SYS_execve, proc_pid));
414     }
415     if (!proc->set_entry_syscalls(entryset)) return false;;
416     SYSSET_FREE(entryset);
417     preExecInst = NULL;
418     return true;
419
420 }    
421
422 /////// Remove post-exec instrumentation
423
424 bool syscallNotification::removePostExec() {
425     if (!postExecInst) return false;
426     // <whistles>
427     if (!proc->isAttached() || proc->execing()) {
428         postExecInst = NULL;
429         return true;
430     }
431
432     // Get existing flags, add post-exec, and set
433     SYSSET_DECLAREPID(proc_pid, proc->getPid());
434     
435     sysset_t *exitset = SYSSET_ALLOC(proc_pid);
436     
437     if (!proc->get_exit_syscalls(exitset)) return false;;
438
439     if (SYSSET_MAP(SYS_exec, proc_pid) != -1) {
440         prdelsysset(exitset, SYSSET_MAP(SYS_exec, proc_pid));
441     }
442     if (SYSSET_MAP(SYS_execve, proc_pid) != -1) {
443         prdelsysset(exitset, SYSSET_MAP(SYS_execve, proc_pid));
444     }
445     if (!proc->set_exit_syscalls(exitset)) return false;;
446     SYSSET_FREE(exitset);
447     postExecInst = NULL;
448     return true;
449 }
450
451 /////// Remove pre-exit instrumentation
452
453 bool syscallNotification::removePreExit() {
454     if (!preExitInst) return false;
455     if (!proc->isAttached() || proc->execing()) {
456         preExitInst = NULL;
457         return true;
458     }
459
460     // Get existing flags, add pre-exit, and set
461     SYSSET_DECLAREPID(proc_pid, proc->getPid());
462     
463     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
464     
465     if (!proc->get_entry_syscalls(entryset)) return false;;
466
467     if (SYSSET_MAP(SYS_exit, proc_pid) != -1) {
468         prdelsysset(entryset, SYSSET_MAP(SYS_exit, proc_pid));
469     }
470     if (!proc->set_entry_syscalls(entryset)) return false;;
471     SYSSET_FREE(entryset);
472     preExitInst = NULL;
473     
474     return true;
475 }
476
477 /////// Remove pre-exit instrumentation
478
479 bool syscallNotification::removePreLwpExit() {
480     if (!preLwpExitInst) return false;
481
482     if (preLwpExitInst != SYSCALL_INSTALLED) {
483         if (!proc->isAttached() || proc->execing()) {
484             delete preLwpExitInst;
485             preLwpExitInst = NULL;
486             return true;
487         }
488         
489         miniTramp *handle;
490         for (unsigned i = 0; i < preLwpExitInst->miniTramps.size(); i++) {
491             handle = preLwpExitInst->miniTramps[i];
492             
493             bool removed = handle->uninstrument();
494             // At some point we should handle a negative return... but I
495             // have no idea how.
496             
497             assert(removed);
498             // The miniTramp is deleted when the miniTramp is freed, so
499             // we don't have to.
500         } 
501         delete preLwpExitInst;
502         preLwpExitInst = NULL;
503         return true;
504     }
505
506     if (!proc->isAttached()) {
507         preLwpExitInst = NULL;
508         return true;
509     }
510
511     // Get existing flags, add pre-exit, and set
512     SYSSET_DECLAREPID(proc_pid, proc->getPid());
513     
514     sysset_t *entryset = SYSSET_ALLOC(proc_pid);
515     
516     if (!proc->get_entry_syscalls(entryset)) return false;;
517
518     if (SYSSET_MAP(SYS_lwp_exit, proc_pid) != -1) {
519         prdelsysset(entryset, SYSSET_MAP(SYS_lwp_exit, proc_pid));
520     }
521     if (!proc->set_entry_syscalls(entryset)) return false;;
522     SYSSET_FREE(entryset);
523     preLwpExitInst = NULL;
524     
525     return true;
526 }
527
528