Don't stop children of mutatees in exec. This is temporary until fork/exec
[dyninst.git] / dyninstAPI / src / irix.C
1 /*
2  * Copyright (c) 1998 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: irix.C,v 1.11 1999/10/29 22:32:32 zandy Exp $
43
44 #include <sys/types.h>    // procfs
45 #include <sys/signal.h>   // procfs
46 #include <sys/fault.h>    // procfs
47 #include <sys/syscall.h>  // procfs
48 #include <sys/procfs.h>   // procfs
49 #include <unistd.h>       // getpid()
50 #include <sys/ucontext.h> // gregset_t
51 #include "dyninstAPI/src/arch-mips.h"
52 #include "dyninstAPI/src/inst-mips.h"
53 #include "dyninstAPI/src/symtab.h" // pd_Function
54 #include "dyninstAPI/src/instPoint-mips.h"
55 #include "dyninstAPI/src/instP.h"
56 #include "dyninstAPI/src/process.h"
57 #include "dyninstAPI/src/stats.h" // ptrace{Ops,Bytes}
58 #include "util/h/pathName.h" // expand_tilde_pathname, exists_executable
59 #include "util/h/irixKludges.h" // PDYN_XXX
60 #include <limits.h>       // poll()
61 #include <stropts.h>      // poll()
62 #include <poll.h>         // poll()
63 #include <errno.h>        // errno
64 #include <stdio.h>        // perror()
65 #include <sys/sysmp.h>    // sysmp()
66 #include <sys/sysinfo.h>  // sysmp()
67 #include <string.h>       // strncmp()
68 #include <stdlib.h>       // getenv()
69 #include <termio.h>       // TIOCNOTTY
70 #include <sys/timers.h>   // PTIMER macros
71
72
73 extern debug_ostream inferiorrpc_cerr;
74
75 extern char *Bool[];
76 void print_proc_flags(int fd)
77 {
78   prstatus stat;
79   ioctl(fd, PIOCSTATUS, &stat);
80   fprintf(stderr, "flags: ");
81
82   if (stat.pr_flags & PR_STOPPED) fprintf(stderr, "PR_STOPPED ");
83   if (stat.pr_flags & PR_ISTOP) fprintf(stderr, "PR_ISTOP ");
84   if (stat.pr_flags & PR_DSTOP) fprintf(stderr, "PR_DSTOP ");
85   if (stat.pr_flags & PR_STEP) fprintf(stderr, "PR_STEP ");
86   if (stat.pr_flags & PR_ASLEEP) fprintf(stderr, "PR_ASLEEP ");
87   if (stat.pr_flags & PR_PCINVAL) fprintf(stderr, "PR_PCINVAL ");
88   //if (stat.pr_flags & PR_ISSYS) fprintf(stderr, "PR_ISSYS ");
89   if (stat.pr_flags & PR_FORK) fprintf(stderr, "PR_FORK ");
90   if (stat.pr_flags & PR_RLC) fprintf(stderr, "PR_RLC ");
91   if (stat.pr_flags & PR_KLC) fprintf(stderr, "PR_KLC ");
92   if (stat.pr_flags & PR_PTRACE) fprintf(stderr, "PR_PTRACE ");
93
94   if (stat.pr_flags & PR_ISKTHREAD) fprintf(stderr, "PR_ISKTHREAD ");
95   if (stat.pr_flags & PR_JOINTSTOP) fprintf(stderr, "PR_JOINTSTOP ");
96   if (stat.pr_flags & PR_JOINTPOLL) fprintf(stderr, "PR_JOINTPOLL ");
97   if (stat.pr_flags & PR_RETURN) fprintf(stderr, "PR_RETURN ");
98   if (stat.pr_flags & PR_CKF) fprintf(stderr, "PR_CKF ");
99
100   fprintf(stderr, "\n");
101 }
102
103 void print_proc_regs(int fd)
104 {
105   gregset_t regs;
106   if (ioctl (fd, PIOCGREG, &regs) == -1) {
107     perror("ioctl(PIOCGREG)");
108     return;
109   }
110   char buf[32];
111   for (int i = 0; i < 32; i++) {
112     sprintf(buf, "$%s", reg_names[i]);
113     fprintf(stderr, "%5s: %#10x %s", buf, (unsigned)regs[i],
114             (i % 4 == 3) ? ("\n") : (","));
115   }
116   fprintf(stderr, "%5s: %#10x\n", "$pc", (unsigned)regs[CTX_EPC]);
117 }
118
119 void print_proc_pc(int fd)
120 {
121   gregset_t regs;
122   if (ioctl (fd, PIOCGREG, &regs) == -1) {
123     perror("ioctl(PIOCGREG)");
124     return;
125   }
126   fprintf(stderr, "%5s: %#10x\n", "$pc", (unsigned)regs[CTX_EPC]);
127 }
128
129 bool process::readDataSpace_(const void *inTraced, u_int nbytes, void *inSelf)
130 {
131   //fprintf(stderr, ">>> process::readDataSpace_(0x%016lx)\n", inTraced);
132   ptraceOps++; 
133   ptraceBytes += nbytes;
134
135   if(lseek(proc_fd, (off_t)inTraced, SEEK_SET) == -1) {
136     perror("process::readDataSpace_(lseek)");
137     return false;
138   }
139
140   // TODO: check for infinite loop if read returns 0?
141   char *dst = (char *)inSelf;
142   for (int last, left = nbytes; left > 0; left -= last) {
143     if ((last = read(proc_fd, dst + nbytes - left, left)) == -1) {
144       perror("process::readDataSpace_(read)");
145       return false;
146     }
147   }
148   return true;
149 }
150
151 bool process::writeDataSpace_(void *inTraced, u_int nbytes, const void *inSelf)
152 {
153   //fprintf(stderr, ">>> process::writeDataSpace_(0x%08x: %i bytes)\n", inTraced, nbytes);
154   ptraceOps++; 
155   ptraceBytes += nbytes;
156
157   if(lseek(proc_fd, (off_t)inTraced, SEEK_SET) == -1) {
158     perror("process::writeDataSpace_(lseek)");
159     return false;
160   }
161
162   // TODO: check for infinite loop if write returns 0?
163  char *src = (char *)const_cast<void*>(inSelf);
164   for (int last, left = nbytes; left > 0; left -= last) {
165     if ((last = write(proc_fd, src + nbytes - left, left)) == -1) {
166       perror("process::writeDataSpace_(write)");
167       return false;
168     }
169   }
170   return true;
171 }
172
173 bool process::writeTextWord_(caddr_t inTraced, int data)
174 {
175   //fprintf(stderr, ">>> process::writeTextWord_()\n");
176   return writeDataSpace_(inTraced, INSN_SIZE, &data);
177 }
178
179 bool process::writeTextSpace_(void *inTraced, u_int amount, const void *inSelf)
180 {
181   //fprintf(stderr, ">>> process::writeTextSpace_()\n");
182   return writeDataSpace_(inTraced, amount, inSelf);
183 }
184
185 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
186 bool process::readTextSpace_(void *inTraced, u_int amount, const void *inSelf)
187 {
188   //fprintf(stderr, ">>> process::readTextSpace_()\n");
189   return readDataSpace_(inTraced, amount, (void *)inSelf);
190 }
191 #endif
192
193 void *process::getRegisters() 
194 {
195   //fprintf(stderr, ">>> process::getRegisters()\n");
196   assert(status_ == stopped); // process must be stopped (procfs)
197   
198   gregset_t intRegs;
199   if (ioctl(proc_fd, PIOCGREG, &intRegs) == -1) {
200     perror("process::getRegisters(PIOCGREG)");
201     assert(errno != EBUSY); // procfs thinks the process is active
202     return NULL;
203   }
204   fpregset_t fpRegs;
205   if (ioctl(proc_fd, PIOCGFPREG, &fpRegs) == -1) {
206     perror("process::getRegisters(PIOCGFPREG)");
207     assert(errno != EBUSY);  // procfs thinks the process is active
208     assert(errno != EINVAL); // no floating-point hardware
209     return NULL;
210   }
211   
212   char *buf = new char[sizeof(intRegs) + sizeof(fpRegs)];
213   assert(buf);
214   memcpy(buf, &intRegs, sizeof(intRegs));
215   memcpy(buf + sizeof(intRegs), &fpRegs, sizeof(fpRegs));
216   
217   return (void *)buf;
218 }
219
220 bool process::restoreRegisters(void *_buf)
221 {
222   //fprintf(stderr, ">>> process::restoreRegisters()\n");
223   assert(status_ == stopped); // process must be stopped (procfs)
224
225   char *buf = (char *)_buf;
226   gregset_t *intRegs = (gregset_t *)buf;
227   if (ioctl(proc_fd, PIOCSREG, intRegs) == -1) {
228     perror("process::restoreRegisters(PIOCSREG)");
229     assert(errno != EBUSY); // procfs thinks the process is active
230     return false;
231   }  
232   fpregset_t *fpRegs = (fpregset_t *)(buf + sizeof(gregset_t));
233   if (ioctl(proc_fd, PIOCSFPREG, fpRegs) == -1) {
234     perror("process::restoreRegisters(PIOCSFPREG)");
235     assert(errno != EBUSY);  // procfs thinks the process is active
236     assert(errno != EINVAL); // no floating-point hardware
237     return false;
238   }
239
240   return true;
241 }
242
243 // fetch actual PC value via procfs
244 // TODO: make "process::" - csserra
245 Address pcFromProc(int proc_fd)
246 {
247   gregset_t regs;
248   if (ioctl (proc_fd, PIOCGREG, &regs) == -1) {
249     perror("currentPC(PIOCGREG)");
250     assert(errno != EBUSY); // procfs thinks the process is active
251     return 0;
252   }
253   return (Address)regs[PROC_REG_PC];
254 }
255
256 bool process::changePC(Address addr, const void *savedRegs)
257 {
258   //fprintf(stderr, ">>> process::changePC(0x%08x)\n", addr);
259   assert(status_ == stopped); // process must be stopped (procfs)
260
261   /* copy integer registers from register buffer */
262   gregset_t *savedIntRegs = (gregset_t *)const_cast<void*>(savedRegs); 
263   gregset_t intRegs;
264   memcpy(&intRegs, savedIntRegs, sizeof(gregset_t));
265
266   intRegs[PROC_REG_PC] = addr; // set PC
267
268   if (ioctl(proc_fd, PIOCSREG, &intRegs) == -1) {
269     perror("process::changePC(PIOCSREG)");
270     assert(errno != EBUSY); // procfs thinks the process is active
271     return false;
272   }
273
274    return true;
275 }
276
277 bool process::changePC(Address addr)
278 {
279   //fprintf(stderr, ">>> process::changePC()\n");
280   assert(status_ == stopped); // process must be stopped (procfs)
281
282   gregset_t intRegs;
283   if (ioctl(proc_fd, PIOCGREG, &intRegs) == -1) {
284     perror("process::changePC(PIOCGREG)");
285     assert(errno != EBUSY); // procfs thinks the process is active
286     return false;
287   }
288
289   intRegs[PROC_REG_PC] = addr; // set PC
290
291   if (ioctl(proc_fd, PIOCSREG, &intRegs) == -1) {
292     perror("process::changePC(PIOCSREG)");
293     assert(errno != EBUSY); // procfs thinks the process is active
294     return false;
295   }
296
297    return true;
298 }
299
300 bool process::isRunning_() const
301 {
302   //fprintf(stderr, ">>> process::isRunning_()\n");
303   prstatus status;
304   if (ioctl(proc_fd, PIOCSTATUS, &status) == -1) {
305     perror("process::isRunning_()");
306     assert(0);
307   }
308
309   // TODO - check for discrepancy with "status_" member?
310   if (status.pr_flags & PR_STOPPED) return false;
311
312   return true;
313 }
314
315 void OS::osTraceMe(void)
316 {
317   char procName[128];
318   sprintf(procName,"/proc/%05d", (int)getpid());
319   //fprintf(stderr, ">>> OS::osTraceMe(%s)\n", procName);
320   int fd = P_open(procName, O_RDWR, 0);
321   if (fd < 0) {
322     fprintf(stderr, "osTraceMe: open failed: %s\n", sys_errlist[errno]); 
323     fflush(stderr);
324     P__exit(-1); // must use _exit here.
325   }
326
327   // Procfs on Irix sets the "run-on-last-close" flag (PR_RLC) by default.
328   // This flag needs to be unset to avoid the PIOCSEXIT trace (below) from
329   // being lost when the child closes the proc file descriptor to itself.
330   /* reset "run-on-last-close" flag */
331   long flags = PR_RLC;
332   if (ioctl(fd, PIOCRESET, &flags) < 0) {
333     fprintf(stderr, "osTraceMe: PIOCRESET failed: %s\n", sys_errlist[errno]); 
334     fflush(stderr);
335     P__exit(-1); // must use _exit here.
336   };
337
338   /* set a breakpoint at the exit of execv/execve */
339   sysset_t exitSet;
340   premptyset(&exitSet);
341   (void)praddset(&exitSet, SYS_execv);
342   (void)praddset(&exitSet, SYS_execve);
343   if (ioctl(fd, PIOCSEXIT, &exitSet) < 0) {
344     fprintf(stderr, "osTraceMe: PIOCSEXIT failed: %s\n", sys_errlist[errno]); 
345     fflush(stderr);
346     P__exit(-1); // must use _exit here.
347   }
348
349   errno = 0;
350   close(fd);
351 }
352
353 bool process::attach()
354 {
355   // QUESTION: does this attach operation lead to a SIGTRAP being forwarded
356   // to paradynd in all cases?  How about when we are attaching to an
357   // already-running process?  (Seems that in the latter case, no SIGTRAP
358   // is automatically generated) TODO
359
360   // step 1 - /proc open: attach to the inferior process
361   char procName[128];
362   sprintf(procName,"/proc/%05d", (int)pid);
363   int fd = P_open(procName, O_RDWR, 0);
364   if (fd < 0) {
365     // TODO: official error msg for API tests
366     //perror("process::attach(open)");
367     return false;
368   }
369
370   // step 2 - /proc PIOCSTRACE: define which signals should be forwarded to daemon
371   // these are (1) SIGSTOP and (2) either SIGTRAP (sparc/mips) or SIGILL (x86),
372   // to implement inferiorRPC completion detection.
373   sigset_t sigs;
374   premptyset(&sigs);
375   (void)praddset(&sigs, SIGSTOP);
376   (void)praddset(&sigs, SIGTRAP);
377   (void)praddset(&sigs, SIGILL);
378   if (ioctl(fd, PIOCSTRACE, &sigs) < 0) {
379     perror("process::attach(PIOCSTRACE)");
380     close(fd);
381     return false;
382   }
383
384   // step 3 - /proc PIOC{SET,RESET}:
385   // a) turn on the kill-on-last-close flag (kills inferior with SIGKILL when
386   //    the last writable /proc fd closes)
387   // b) turn on inherit-on-fork flag (tracing flags inherited when
388   // child forks), Paradyn only.
389   // c) turn off run-on-last-close flag (on by default)
390   // Also, any child of this process will stop at the exit of an exec
391   // call, Paradyn only.
392   long flags = 0;
393   /* FIXME: When fork/exec callbacks are implemented for Dyninst, set
394      PR_FORK for Dyninst, too.  It is not set now because otherwise
395      the child would inherit trap-on-exit from exec.  With no way for
396      a mutator to handle this stop, the child process would remain
397      stopped indefinitely. */
398 #ifndef BPATCH_LIBRARY
399   flags = PR_KLC | PR_FORK;
400 #endif
401   if (ioctl (fd, PIOCSET, &flags) < 0) {
402     perror("process::attach(PIOCSET)");
403     close(fd);
404     return false;
405   }
406   flags = PR_RLC;
407   if (ioctl (fd, PIOCRESET, &flags) < 0) {
408     perror("process::attach(PIOCRESET)");
409     close(fd);
410     return false;
411   }
412
413   proc_fd = fd;
414
415   // environment variables
416   prpsinfo_t info;
417   if (ioctl(fd, PIOCPSINFO, &info) < 0) {
418     perror("process::attach(PIOCPSINFO)");
419     close(fd);
420     return false;
421   }
422   // argv[0]
423   char *argv0_start = info.pr_psargs;
424   char *argv0_end = strstr(argv0_start, " ");
425   if (argv0_end) (*argv0_end) = 0;
426   argv0 = argv0_start;
427   // unused variables
428   pathenv = "";
429   cwdenv = "";
430
431   return true;
432 }
433
434 #ifdef BPATCH_LIBRARY
435 int process::waitProcs(int *status, bool block)
436 #else
437 int process::waitProcs(int *status)
438 #endif
439 {
440   //fprintf(stderr, ">>> process::waitProcs()\n");
441
442   extern vector<process*> processVec;
443
444   static struct pollfd fds[OPEN_MAX];  // argument for poll
445   static int selected_fds;             // number of selected
446   static int curr;                     // the current element of fds
447
448 #ifdef BPATCH_LIBRARY
449   do {
450 #endif
451     
452     /* Each call to poll may return many selected fds. Since we only
453        report the status of one process per each call to waitProcs, we
454        keep the result of the last poll buffered, and simply process an
455        element from the buffer until all of the selected fds in the
456        last poll have been processed.  
457     */
458     
459     if (selected_fds == 0) {
460       for (unsigned i = 0; i < processVec.size(); i++) {
461         if (processVec[i] && 
462             (processVec[i]->status() == running || processVec[i]->status() == neonatal))
463           fds[i].fd = processVec[i]->proc_fd;
464         else
465           fds[i].fd = -1;
466         fds[i].events = POLLPRI;
467         fds[i].revents = 0;
468       }
469       
470 #ifdef BPATCH_LIBRARY
471       int timeout;
472       if (block) timeout = INFTIM;
473       else timeout = 0;
474       selected_fds = poll(fds, processVec.size(), timeout);
475 #else
476       selected_fds = poll(fds, processVec.size(), 0);
477 #endif
478       if (selected_fds == -1) {
479         perror("process::waitProcs(poll)");
480         selected_fds = 0;
481         return 0;
482       }      
483       curr = 0;
484     }
485     
486     if (selected_fds > 0) {
487       while (fds[curr].revents == 0) curr++;
488       // fds[curr] has an event of interest
489       //fprintf(stderr, ">>> process::waitProcs(fd %i)\n", curr);
490
491       prstatus_t stat;
492       int ret = 0;
493 #ifdef BPATCH_LIBRARY
494       if (fds[curr].revents & POLLHUP) {
495         //fprintf(stderr, ">>> process::waitProcs(fd %i): POLLHUP\n", curr);
496         do {
497           ret = waitpid(processVec[curr]->getPid(), status, 0);
498         } while ((ret < 0) && (errno == EINTR));
499         if (ret < 0) {
500           // This means that the application exited, but was not our child
501           // so it didn't wait around for us to get it's return code.  In
502           // this case, we can't know why it exited or what it's return
503           // code was.
504           ret = processVec[curr]->getPid();
505           *status = 0;
506         }
507         assert(ret == processVec[curr]->getPid());
508       } else
509 #endif
510         if (ioctl(fds[curr].fd, PIOCSTATUS, &stat) != -1 
511             && ((stat.pr_flags & PR_STOPPED) || (stat.pr_flags & PR_ISTOP))) {
512           //print_proc_flags(fds[curr].fd);
513           process *p = processVec[curr];
514           switch (stat.pr_why) {
515           case PR_SIGNALLED: {
516             // debug
517             //fprintf(stderr, ">>> process::waitProcs(fd %i): $pc(0x%08x), sig(%i)\n", 
518             //curr, stat.pr_reg[PROC_REG_PC], stat.pr_what);
519
520             // return the signal number
521             *status = stat.pr_what << 8 | 0177;
522             ret = p->getPid();
523 #if defined(USES_LIBDYNINSTRT_SO)
524             if (!p->dyninstLibAlreadyLoaded() && 
525                 p->wasCreatedViaAttach()) 
526               {
527                 // make sure we are stopped in the eyes of paradynd - naim
528                 bool wasRunning = (p->status() == running);
529                 if (p->status() != stopped) p->Stopped();   
530
531                 // check for dlopen() of libdyninstRT.so.1
532                 if(p->isDynamicallyLinked()) {
533                   bool objectWasMapped = p->handleIfDueToSharedObjectMapping();
534                   if (p->dyninstLibAlreadyLoaded()) {
535                     // libdyninstRT.so.1 was just loaded so cleanup "_start"
536                     assert(objectWasMapped);
537                     p->handleIfDueToDyninstLib();
538                   }
539                 }
540                 if (wasRunning) {
541                   assert(p->continueProc());
542                 }
543               }
544 #endif
545           } break;
546           case PR_SYSEXIT: {
547             //fprintf(stderr, ">>> process::waitProcs(fd %i): PR_SYSEXIT\n", curr);
548             // exit of a system call
549             if (p->RPCs_waiting_for_syscall_to_complete) {
550               // reset PIOCSEXIT mask
551               //inferiorrpc_cerr << "solaris got PR_SYSEXIT!" << endl;
552               assert(p->save_exitset_ptr != NULL);
553               assert(ioctl(p->proc_fd, PIOCSEXIT, p->save_exitset_ptr) != -1);
554               delete [] p->save_exitset_ptr;
555               p->save_exitset_ptr = NULL;
556               // fall through on purpose (so status, ret get set)
557             }
558             else if (stat.pr_reg[PROC_REG_RV] != 0) {
559               // a failed exec; continue the process
560               p->continueProc_();
561               break;
562             }          
563             *status = SIGTRAP << 8 | 0177;
564             ret = p->getPid();
565             break;
566           }
567           case PR_REQUESTED:
568             // TODO: this has been reached
569             fprintf(stderr, ">>> process::waitProcs(fd %i): PR_REQUESTED\n", curr);
570             assert(0);
571           case PR_JOBCONTROL:
572             fprintf(stderr, ">>> process::waitProcs(fd %i): PR_JOBCONTROL\n", curr);
573             assert(0);
574             break;
575           }        
576         }
577       
578       --selected_fds;
579       ++curr;      
580       if (ret > 0) return ret;
581     }
582 #ifdef BPATCH_LIBRARY
583   } while (block);
584   return 0;
585 #else
586   return waitpid(0, status, WNOHANG);
587 #endif
588 }
589
590 bool process::detach_()
591 {
592   //fprintf(stderr, ">>> process::detach_()\n");
593   if (close(proc_fd) == -1) {
594     perror("process::detach_(close)");
595     return false;
596   }
597   return true;
598 }
599
600 bool process::continueProc_()
601 {
602   //fprintf(stderr, ">>> process::continueProc_()\n");
603   ptraceOps++; 
604   ptraceOtherOps++;
605
606   prstatus_t stat;
607   if (ioctl(proc_fd, PIOCSTATUS, &stat) == -1) {
608     perror("process::continueProc_(PIOCSTATUS)");
609     return false;
610   }
611
612   if (!(stat.pr_flags & (PR_STOPPED | PR_ISTOP))) {
613     // not stopped
614     fprintf(stderr, "continueProc_(): process not stopped\n");
615     print_proc_flags(proc_fd);
616     return false;
617   }
618   
619   prrun_t run;
620   run.pr_flags = PRCSIG; // clear current signal
621   if (hasNewPC) {        // new PC value
622     hasNewPC = false;
623     run.pr_vaddr = (caddr_t)currentPC_;
624     run.pr_flags |= PRSVADDR;
625   }
626   if (ioctl(proc_fd, PIOCRUN, &run) == -1) {
627     perror("process::continueProc_(PIOCRUN)");
628     return false;
629   }
630
631   return true;
632 }
633
634 bool process::heapIsOk(const vector<sym_data>&findUs)
635 {
636   if (!(mainFunction = findOneFunction("main")) &&
637       !(mainFunction = findOneFunction("_main"))) {
638     fprintf(stderr, "process::heapIsOk(): failed to find \"main\"\n");
639     return false;
640   }
641
642   for (unsigned i = 0; i < findUs.size(); i++) {
643     const string &name = findUs[i].name;
644     Address addr = lookup_fn(this, name);
645     if (!addr && findUs[i].must_find) {
646       fprintf(stderr, "process::heapIsOk(): failed to find \"%s\"\n", name.string_of());
647       return false;
648     }
649   }
650
651   string heap_name = INFERIOR_HEAP_BASE;
652   Address heap_addr = lookup_fn(this, heap_name);
653   if (!heap_addr) {
654     fprintf(stderr, "process::heapIsOk(): failed to find \"%s\"\n", heap_name.string_of());
655     return false;
656   }
657
658   return true;
659 }
660
661 bool process::executingSystemCall()
662 {
663    bool ret = false;
664    prstatus stat;
665    if (ioctl(proc_fd, PIOCSTATUS, &stat) == -1) {
666      perror("process::executingSystemCall(PIOCSTATUS)");
667      assert(0);
668    }
669    if (stat.pr_syscall > 0) {
670      inferiorrpc_cerr << "pr_syscall=" << stat.pr_syscall << endl;
671      ret = true;
672    }
673    return ret;
674 }
675
676 Address process::read_inferiorRPC_result_register(Register retval_reg)
677 {
678   //fprintf(stderr, ">>> process::read_inferiorRPC_result_register()\n");
679   gregset_t regs;
680   if (ioctl (proc_fd, PIOCGREG, &regs) == -1) {
681     perror("process::_inferiorRPC_result_registerread(PIOCGREG)");
682     return 0;
683   }
684   return regs[retval_reg];
685 }
686
687 static const Address lowest_addr = 0x00400000;
688 void inferiorMallocConstraints(Address near, Address &lo, Address &hi)
689 {
690   lo = region_lo(near);
691   hi = region_hi(near);  
692   // avoid mapping the zero page
693   if (lo < lowest_addr) lo = lowest_addr;
694 }
695
696 void inferiorMallocAlign(unsigned &size)
697 {
698   // quadword-aligned (stack alignment)
699   unsigned align = 16;
700   if (size % align) size = ((size/align)+1)*align;
701 }
702
703 bool process::pause_()
704 {
705   //fprintf(stderr, ">>> process::pause_()\n");
706   ptraceOps++; 
707   ptraceOtherOps++;
708
709   int ret;
710   if ((ret = ioctl(proc_fd, PIOCSTOP, 0)) == -1) {
711     perror("process::pause_(PIOCSTOP)");
712     sprintf(errorLine, "warning: PIOCSTOP failed in \"pause_\", errno=%i\n", errno);
713     logLine(errorLine);
714   }
715
716   return (ret != -1);
717 }
718
719 int getNumberOfCPUs() 
720 {
721   // see sysmp(2) man page
722   int ret = sysmp(MP_NPROCS);
723   //fprintf(stderr, ">>> getNumberOfCPUs(%i)\n", ret);
724   return ret;
725 }
726
727 bool process::set_breakpoint_for_syscall_completion()
728 {
729   /* Can assume: (1) process is paused and (2) in a system call.  We
730      want to set a TRAP for the syscall exit, and do the inferiorRPC
731      at that time.  We'll use /proc PIOCSEXIT.  Returns true iff
732      breakpoint was successfully set. */
733   //fprintf(stderr, ">>> process::set_breakpoint_for_syscall_completion()\n");
734   
735   sysset_t save_exitset;
736   if (ioctl(proc_fd, PIOCGEXIT, &save_exitset) == -1) {
737     return false;
738   }
739   
740   sysset_t new_exitset;
741   prfillset(&new_exitset);
742   if (ioctl(proc_fd, PIOCSEXIT, &new_exitset) == -1) {
743     return false;
744   }
745   
746   assert(save_exitset_ptr == NULL);
747   save_exitset_ptr = new sysset_t;
748   memcpy(save_exitset_ptr, &save_exitset, sizeof(sysset_t));
749   
750   return true;
751 }
752
753 void process::clear_breakpoint_for_syscall_completion() { return; }
754
755 // TODO: this ignores the "sig" argument
756 bool process::continueWithForwardSignal(int /*sig*/)
757 {
758   fprintf(stderr, ">>> process::continueWithForwardSignal()\n");
759   if (ioctl(proc_fd, PIOCRUN, NULL) == -1) {
760     perror("process::continueWithForwardSignal(PIOCRUN)\n");
761     return false;
762   }
763   return true;
764 }
765
766 bool process::dumpCore_(const string coreFile)
767 {
768   //fprintf(stderr, ">>> process::dumpCore_()\n");
769   bool ret;
770 #ifdef BPATCH_LIBRARY
771   ret = dumpImage(coreFile);
772 #else
773   ret = dumpImage();
774 #endif
775   return ret;
776 }
777
778 #ifdef BPATCH_LIBRARY
779 bool process::terminateProc_()
780 {
781   //fprintf(stderr, ">>> process::terminateProc_()\n");
782   long flags = PR_KLC;
783   if (ioctl(proc_fd, PIOCSET, &flags) == -1) {
784     // not an error: proc_fd has probably been close()ed already
785     return false;
786   }  
787   Exited();
788   return true;
789 }
790 #endif
791
792 #ifdef BPATCH_LIBRARY
793 /* API_detach_: detach from the process (clean up /proc state);
794    continue process' execution if "cont" is true. */
795 bool process::API_detach_(const bool cont)
796 {
797   //fprintf(stderr, ">>> process::API_detach_(%s)\n", (cont) ? ("continue") : ("abort"));
798   bool ret = true;
799
800   // remove shared object loading traps
801   if (dyn) dyn->unsetMappingHooks(this);
802
803   // signal handling
804   sigset_t sigs;
805   premptyset(&sigs);
806   if (ioctl(proc_fd, PIOCSTRACE, &sigs) == -1) {
807     //perror("process::API_detach_(PIOCSTRACE)");
808     ret = false;
809   }
810   if (ioctl(proc_fd, PIOCSHOLD, &sigs) == -1) {
811     //perror("process::API_detach_(PIOCSHOLD)");
812     ret = false;
813   }
814   // fault handling
815   fltset_t faults;
816   premptyset(&faults);
817   if (ioctl(proc_fd, PIOCSFAULT, &faults) == -1) {
818     //perror("process::API_detach_(PIOCSFAULT)");
819     ret = false;
820   }
821   // system call handling
822   sysset_t syscalls;
823   premptyset(&syscalls);
824   if (ioctl(proc_fd, PIOCSENTRY, &syscalls) == -1) {
825     //perror("process::API_detach_(PIOCSENTRY)");
826     ret = false;
827   }
828   if (ioctl(proc_fd, PIOCSEXIT, &syscalls) == -1) {
829     //perror("process::API_detach_(PIOCSEXIT)");
830     ret = false;
831   }
832   // operation mode
833   long flags = PR_RLC | PR_KLC;
834   if (ioctl(proc_fd, PIOCRESET, &flags) == -1) {
835     //perror("process::API_detach_(PIOCRESET)");
836     ret = false;
837   }
838   flags = (cont) ? (PR_RLC) : (PR_KLC);
839   if (ioctl(proc_fd, PIOCSET, &flags) == -1) {
840     //perror("process::API_detach_(PIOCSET)");
841     ret = false;
842   }    
843
844   close(proc_fd);
845   return ret;
846 }
847 #endif
848
849 string process::tryToFindExecutable(const string &progpath, int /*pid*/)
850 {
851   //fprintf(stderr, ">>> process::tryToFindExecutable(%s)\n", progpath.string_of());
852   string ret = "";
853   
854   // attempt #1: expand_tilde_pathname()
855   ret = expand_tilde_pathname(progpath);
856   //fprintf(stderr, "  expand_tilde => \"%s\"\n", ret.string_of());
857   if (exists_executable(ret)) return ret;
858   
859   // TODO: any other way to find executable?
860   // no procfs info available (argv, cwd, env) so we're stuck
861   return "";
862 }
863
864
865
866 // HERE BE DRAGONS
867
868
869
870 // TODO: this is a lousy implementation
871 #ifdef BPATCH_LIBRARY
872 bool process::dumpImage(string outFile) {
873 #else
874 bool process::dumpImage() {
875   char buf[512];
876   sprintf(buf, "image.%d", pid);
877   string outFile = buf;
878 #endif
879   //fprintf(stderr, "!!! process::dumpImage(%s)\n", outFile.string_of());
880   
881   // copy and open file
882   image *img = getImage();
883   string imgFile = img->file();
884   char buf1[1024];
885   sprintf(buf1, "cp %s %s", imgFile.string_of(), outFile.string_of());
886   system(buf1);
887   int fd = open(outFile.string_of(), O_RDWR, 0);
888   if (fd < 0) return false;
889
890   // overwrite ".text" section with runtime contents
891
892   bool is_elf64 = img->getObject().is_elf64();
893   Elf *elfp = elf_begin(fd, ELF_C_READ, 0);
894   assert(elfp);
895   int e_shstrndx;
896   if (is_elf64) {
897
898     Elf64_Ehdr *ehdrp = elf64_getehdr(elfp);
899     assert(ehdrp);
900     e_shstrndx = ehdrp->e_shstrndx;
901
902   } else { // 32-bit
903
904     Elf32_Ehdr *ehdrp = elf32_getehdr(elfp);
905     assert(ehdrp);
906     e_shstrndx = ehdrp->e_shstrndx;
907
908   }
909   Elf_Scn *shstrscnp = elf_getscn(elfp, e_shstrndx);
910   assert(shstrscnp);
911   Elf_Data *shstrdatap = elf_getdata(shstrscnp, 0);
912   assert(shstrdatap);
913   char *shnames = (char *)shstrdatap->d_buf;
914
915   Address txtAddr = 0;
916   int txtLen = 0;
917   int txtOff = 0;
918   Elf_Scn *scn = 0;
919   while ((scn = elf_nextscn(elfp, scn)) != 0) {
920     pdElfShdr pd_shdr(scn, is_elf64);
921     char *name = (char *)&shnames[pd_shdr.pd_name];
922     if (strcmp(name, ".text") == 0) {
923       txtOff = pd_shdr.pd_offset;
924       txtLen = pd_shdr.pd_size;
925       txtAddr = pd_shdr.pd_addr;
926       break;
927     }
928   }
929    
930   if (txtLen > 0) {
931     char *buf2 = new char[txtLen];
932     // TODO: readTextSpace_() only defined for BPATCH_MUTATIONS_ACTIVE
933     if (!(readDataSpace_((void *)txtAddr, txtLen, buf2))) {
934       delete [] buf2;
935       return false;
936     }
937     lseek(fd, txtOff, SEEK_SET);
938     write(fd, buf2, txtLen);
939     close(fd);
940     delete [] buf2;
941   }
942   
943   return true;
944 }
945
946 // getActiveFrame(): populate Frame object using toplevel frame
947 void Frame::getActiveFrame(process *p)
948 {
949   gregset_t regs;
950   int proc_fd = p->getProcFileDescriptor();
951   if (ioctl(proc_fd, PIOCGREG, &regs) == -1) {
952     perror("Frame::Frame(PIOCGREG)");
953     return;
954   }
955   
956   pc_ = regs[PROC_REG_PC];
957   sp_ = regs[PROC_REG_SP];
958   fp_ = regs[PROC_REG_FP];
959   
960   // sometimes the actual $fp is zero
961   // (kludge for stack walk code)
962   if (fp_ == 0) fp_ = sp_;
963 }
964  
965 // determine if the basetramp frame is active
966 // NOTE: arguments 2-4 are from findAddressInFuncsAndTramps()
967 // NOTE: if "ip" is non-NULL, one of "bt" and "mt" must also be non-NULL
968 static bool instrFrameActive(Address pc,
969                              instPoint *ip, 
970                              trampTemplate *bt, 
971                              instInstance *mt)
972 {
973   // "ip" is set if $pc in instrumentation code
974   // the basetramp frame is never active in native code
975   if (!ip) return false;
976
977   // "bt" is set if $pc is in basetramp
978   // the basetramp frame is active in parts of the basetramp
979   if (bt) return bt->inSavedRegion(pc);
980
981   // "mt" is set if $pc is in minitramp
982   // the basetramp frame is always active in minitramps
983   else if (mt) return true;
984
985   // one of "bt" and "mt" must be non-NULL
986   assert(0);
987   return false;
988 }
989
990 /* nativeFrameActive(): determine if the (relative) $pc is between the
991    stack frame save and restore insns */
992 /* TODO: To handle functions with multiple exit points (and restores),
993    the $pc should be considered "after" a given insn only if the $pc
994    is within some proximity.  This heuristic is a poor imitation of
995    dataflow analysis. */
996 #define STACK_RESTORE_PROXIMITY (4*INSN_SIZE)
997 static bool nativFrameActive(Address pc_off, pd_Function *callee)
998 {
999   if (callee->frame_size == 0) return false;
1000
1001   if (pc_off > callee->sp_mod) {
1002     int nret = callee->sp_ret.size();
1003     Address last_ret = callee->sp_ret[nret-1];
1004     if (pc_off <= last_ret) return true;
1005   }
1006
1007   return false;
1008 }
1009
1010 // constants derived from "tramp-mips.s" (must remain consistent)
1011 // size of basetramp stack frame
1012 static const int bt_frame_size = 512;
1013 // offset of save insns from basetramp "daddiu sp,sp,-512"
1014 static const int bt_ra_save_off = (64 * INSN_SIZE); 
1015 static const int bt_fp_save_off = (63 * INSN_SIZE); 
1016 // basetramp stack frame slots
1017 static const int bt_ra_slot = -512;
1018 static const int bt_fp_slot = -504;
1019
1020 static bool basetrampRegSaved(Address pc, Register reg,
1021                               instPoint *ip,
1022                               trampTemplate *bt,
1023                               instInstance *mt)
1024 {
1025   if (!ip) return false;
1026   if (mt) return true;
1027   assert(bt);
1028
1029   Address save_off;
1030   switch(reg) {
1031   case REG_RA:
1032     save_off = bt_ra_save_off;
1033     break;
1034   case REG_S8:
1035     save_off = bt_fp_save_off;
1036     break;
1037   default:
1038     assert(0);
1039   }
1040
1041   if (pc >  bt->baseAddr + bt->savePreInsOffset + save_off && 
1042       pc <= bt->baseAddr + bt->restorePreInsOffset) {
1043     return true;
1044   }
1045   if (pc >  bt->baseAddr + bt->savePostInsOffset + save_off && 
1046       pc <= bt->baseAddr + bt->restorePostInsOffset) {
1047     return true;
1048   }
1049
1050   return false;
1051 }
1052
1053 // return the corresponding $pc in native code
1054 // (for a $pc in instrumentation code)
1055 static Address adjustedPC(Address pc, Address fn_addr,
1056                           instPoint *ip,
1057                           trampTemplate *bt,
1058                           instInstance *mt)
1059 {
1060   // if $pc in native code, no adjustment necessary
1061   if (!ip) return pc;
1062   
1063   // runtime address of instrumentation point
1064   Address pt_addr = fn_addr + ip->offset();
1065
1066   if (bt) {
1067     // $pc in basetramp
1068     assert(bt->inBasetramp(pc));
1069     // assumption: basetramp has exactly two displaced insns
1070     assert(bt->skipPostInsOffset == bt->emulateInsOffset + 2*INSN_SIZE);
1071
1072     int bt_off = pc - bt->baseAddr;
1073     if (bt_off <= bt->emulateInsOffset) {
1074       // $pc is at or before first displaced insn
1075       // $pc' = address of instr pt
1076       return pt_addr;
1077     } else if (bt_off == bt->emulateInsOffset + INSN_SIZE) {
1078       // $pc is at second displaced insn (delay slot)
1079       // $pc' = address of instr pt delay slot
1080       return pt_addr + INSN_SIZE;
1081     } else if (bt_off > bt->emulateInsOffset + INSN_SIZE) {
1082       // $pc is after second displaced insn
1083       // $pc' = address of insn after instr pt
1084       return pt_addr + (2*INSN_SIZE);
1085     }
1086   }
1087
1088   else if (mt) {
1089     // $pc in minitramp
1090     if (mt->when == callPreInsn) {
1091       // $pc in pre-insn instr
1092       // $pc' = address of instr pt
1093       return pt_addr;
1094     } else if (mt->when == callPostInsn) {
1095       // $pc in post-insn instr
1096       // $pc' = address of insn after instr pt
1097       return pt_addr + (2*INSN_SIZE);
1098     }
1099   }
1100
1101   // should not be reached: error
1102   assert(0);
1103   return pc;
1104 }
1105
1106 // TODO: need dataflow, ($pc < saveInsn) insufficient
1107 Frame Frame::getCallerFrameNormal(process *p) const
1108 {
1109   // check for active instrumentation
1110   // (i.e. $pc in native/basetramp/minitramp code)
1111   instPoint     *ip = NULL;
1112   trampTemplate *bt = NULL;
1113   instInstance  *mt = NULL;
1114   pd_Function *callee = findAddressInFuncsAndTramps(p, pc_, ip, bt, mt);
1115   // non-NULL "ip" means that $pc is in instrumentation
1116   // non-NULL "bt" means that $pc is in basetramp
1117   // non-NULL "mt" means that $pc is in minitramp
1118   if (ip) assert(bt || mt);
1119
1120   // calculate runtime address of callee fn
1121   if (!callee) {
1122     fprintf(stderr, "!!! <0x%016lx:???> unknown callee\n", pc_);
1123     return Frame(); // zero frame
1124   }
1125   Address base_addr;
1126   p->getBaseAddress(callee->file()->exec(), base_addr);
1127   Address fn_addr = base_addr + callee->getAddress(0);
1128   
1129   /* 
1130   // debug
1131   if (uppermost_) {
1132     char *info = "";
1133     if (ip) info = (bt) ? ("[basetramp]") : ("[minitramp]");
1134     fprintf(stderr, ">>> toplevel frame => \"%s\" %s\n",
1135             callee->prettyName().string_of(), info);
1136   }
1137   */
1138
1139   // adjust $pc for active instrumentation 
1140   Address pc_adj = adjustedPC(pc_, fn_addr, ip, bt, mt);
1141   // $pc' (adjusted $pc) should be inside callee
1142   /*
1143   if (pc_adj < fn_addr || pc_adj >= fn_addr + callee->size()) {
1144     fprintf(stderr, "!!! adjusted $pc\n");
1145     fprintf(stderr, "    0x%016lx $pc\n", pc_);
1146     fprintf(stderr, "    0x%016lx adjusted $pc\n", pc_adj);
1147     fprintf(stderr, "    0x%016lx fn start\n", fn_addr);
1148     fprintf(stderr, "    0x%016lx fn end\n", fn_addr + callee->size());
1149   }
1150   assert(pc_adj >= fn_addr && pc_adj < fn_addr + callee->size());
1151   */
1152
1153   // which frames (native/basetramp) are active?
1154   Address pc_off = pc_adj - fn_addr;
1155   bool nativeFrameActive = nativFrameActive(pc_off, callee);
1156   bool basetrampFrameActive = instrFrameActive(pc_, ip, bt, mt);
1157
1158   // frame pointers for native and basetramp frames
1159   Address fp_bt = sp_;
1160   if (basetrampFrameActive) {
1161     fp_bt += bt_frame_size;
1162   }
1163   Address fp_native = fp_bt;
1164   if (nativeFrameActive) {
1165     fp_native += callee->frame_size;
1166   }
1167   // override calculated $fp if frame pointer conventions used
1168   if (callee->uses_fp) fp_native = fp_;
1169
1170   // which frames is $ra saved in?
1171   pd_Function::regSave_t &ra_save = callee->reg_saves[REG_RA];
1172   bool ra_saved_native = (ra_save.slot != -1 && pc_off > ra_save.insn);
1173   bool ra_saved_bt = basetrampRegSaved(pc_, REG_RA, ip, bt, mt);
1174
1175   // which frames is $fp saved in?
1176   pd_Function::regSave_t &fp_save = callee->reg_saves[REG_S8];
1177   bool fp_saved_native = (fp_save.slot != -1 && pc_off > fp_save.insn);
1178   bool fp_saved_bt = basetrampRegSaved(pc_, REG_S8, ip, bt, mt);
1179
1180   // sanity checks
1181   if (!uppermost_) {
1182     /* if this is a non-toplevel stack frame, the basetramp $pc must
1183        point to just after an emulated call insn */
1184     if (bt) {
1185       assert(bt->skipPostInsOffset == bt->emulateInsOffset + (2*INSN_SIZE));
1186       /*
1187       if (pc_ != bt->baseAddr + bt->skipPostInsOffset) {
1188         fprintf(stderr, "!!! emulated call\n");
1189         fprintf(stderr, "    0x%016lx $pc\n", pc_);
1190         fprintf(stderr, "    0x%016lx emulated\n", bt->baseAddr + bt->skipPostInsOffset);
1191       }
1192       assert(pc_ == bt->baseAddr + bt->skipPostInsOffset);
1193       */
1194     }
1195     // non-toplevel basetramp frames should always be fully saved
1196     if (basetrampFrameActive) {
1197       /*
1198       if (!fp_saved_bt || !ra_saved_bt) {
1199         fprintf(stderr, "!!! $fp or $ra not saved in basetramp frame\n");
1200         fprintf(stderr, "    0x%016lx $pc\n", pc_);
1201         if (bt) { 
1202           fprintf(stderr, "     [in basetramp]\n");
1203           fprintf(stderr, "     0x%016lx basetramp\n", bt->baseAddr);
1204         } else if (mt) { fprintf(stderr, "     [in minitramp]\n"); }
1205       }
1206       assert(fp_saved_bt && ra_saved_bt);
1207       */
1208     }
1209   }
1210
1211   // find caller $pc (callee $ra)
1212   Address ra;
1213   Address ra_addr = 0;
1214   char ra_debug[256];
1215   sprintf(ra_debug, "<unknown>");
1216   if (nativeFrameActive && ra_saved_native) {
1217     // $ra saved in native frame
1218     ra_addr = fp_native + ra_save.slot;
1219     ra = readAddressInMemory(p, ra_addr, ra_save.dword);
1220     sprintf(ra_debug, "[$fp - %i]", -ra_save.slot);
1221   } else if (basetrampFrameActive && ra_saved_bt) {
1222     // $ra saved in basetramp frame
1223     ra_addr = fp_bt + bt_ra_slot;
1224     ra = readAddressInMemory(p, ra_addr, true);
1225     sprintf(ra_debug, "[$fp - %i]", -bt_ra_slot);
1226   } else {
1227     // $ra not saved in any frame
1228     // try to read $ra from registers (toplevel only)
1229     if (uppermost_) {
1230       // $ra in live register
1231       gregset_t regs;
1232       int proc_fd = p->getProcFileDescriptor();
1233       if (ioctl(proc_fd, PIOCGREG, &regs) == -1) {
1234         perror("process::readDataFromFrame(PIOCGREG)");
1235         return Frame(); // zero frame
1236       }
1237       ra = regs[PROC_REG_RA];
1238       sprintf(ra_debug, "regs[ra]");
1239     } else {
1240       /*
1241       // debug
1242       if (callee->prettyName() != "main" &&
1243           callee->prettyName() != "__start")
1244         fprintf(stderr, "!!! <0x%016lx:\"%s\"> $ra not saved\n",
1245                 pc_adj, callee->prettyName().string_of());
1246       */
1247       // $ra cannot be found (error)
1248       return Frame(); // zero frame
1249     }
1250   }
1251
1252   // find caller $fp
1253   Address fp2;
1254   Address fp_addr = 0;
1255   char fp_debug[256];
1256   sprintf(fp_debug, "<unknown>");
1257   if (nativeFrameActive && fp_saved_native) {
1258     // $fp saved in native frame
1259     fp_addr = fp_native + fp_save.slot;
1260     fp2 = readAddressInMemory(p, fp_addr, fp_save.dword);
1261     sprintf(fp_debug, "[$fp - %i]", -fp_save.slot);
1262   } else if (basetrampFrameActive && fp_saved_bt) {
1263     // $ra saved in basetramp frame
1264     fp_addr = fp_bt + bt_fp_slot;
1265     fp2 = readAddressInMemory(p, fp_addr, true);
1266     sprintf(fp_debug, "[$fp - %i]", -bt_fp_slot);
1267   } else {
1268     // $fp not saved in any frame
1269     // pass up callee $fp
1270     fp2 = fp_;
1271     sprintf(fp_debug, "(callee $fp)");
1272   }
1273   // sometimes the retrieved $fp is zero
1274   // (kludge for stack walk code)
1275   if (fp2 == 0) fp2 = fp_;
1276
1277   // determine location of caller $pc (native code, basetramp, minitramp)
1278   instPoint *ip2 = NULL;
1279   trampTemplate *bt2 = NULL;
1280   instInstance *mt2 = NULL;
1281   pd_Function *caller = findAddressInFuncsAndTramps(p, ra, ip2, bt2, mt2);
1282
1283   /* 
1284   // debug
1285   if(!caller) {
1286     fprintf(stderr, "!!! 0x%016lx unknown caller (callee:\"%s\")\n",
1287             ra, callee->prettyName().string_of());    
1288     const image *owner = callee->file()->exec();
1289     Address obj_base = 0;
1290     p->getBaseAddress(owner, obj_base);
1291     Address addr;
1292     // frame pointer conventions
1293     if (callee->uses_fp) {
1294       fprintf(stderr, "    uses frame pointer\n");
1295       addr = obj_base + callee->getAddress(0) + callee->fp_mod;
1296       disDataSpace(p, (void *)addr, 1, "    $fp frame ");
1297       addr = obj_base + callee->getAddress(0) + ra_save.insn;
1298       disDataSpace(p, (void *)addr, 1, "    $ra save  ");
1299     } else {
1300       fprintf(stderr, "    no frame pointer\n");
1301       addr = obj_base + callee->getAddress(0) + callee->sp_mod;
1302       disDataSpace(p, (void *)addr, 1, "    $sp frame ");
1303       addr = obj_base + callee->getAddress(0) + ra_save.insn;
1304       disDataSpace(p, (void *)addr, 1, "    $ra save  ");
1305     }
1306     // callee $pc
1307     if (!ip) { 
1308       fprintf(stderr, "    in native code\n");
1309     } else if (bt) {
1310       fprintf(stderr, "    in basetramp\n");
1311     } else if (mt) {
1312       fprintf(stderr, "    in minitramp\n");    
1313     }
1314     fprintf(stderr, "    0x%016lx $pc\n", pc_);
1315     fprintf(stderr, "    0x%016lx native $pc\n", pc_adj);
1316     fprintf(stderr, "    %18s callee\n", callee->prettyName().string_of());
1317     // stack frames
1318     fprintf(stderr, "    0x%016lx callee $sp\n", sp_);
1319     fprintf(stderr, "    0x%016lx callee $fp\n", fp_);
1320     if (basetrampFrameActive) {
1321       fprintf(stderr, "    basetramp frame active\n");
1322       fprintf(stderr, "    0x%016x basetramp framesize\n", bt_frame_size);
1323       fprintf(stderr, "    0x%016lx basetramp $fp\n", fp_bt);
1324     } else fprintf(stderr, "    basetramp frame not active\n");
1325     if (nativeFrameActive) {
1326       fprintf(stderr, "    native frame active\n");
1327       fprintf(stderr, "    0x%016x native framesize\n", callee->frame_size);
1328       fprintf(stderr, "    0x%016lx native $fp\n", fp_native);
1329     } else fprintf(stderr, "    native frame not active\n");
1330     fprintf(stderr, "    0x%016lx $fp\n", fp_native);
1331     // caller $pc
1332     fprintf(stderr, "    %18s $ra slot\n", ra_debug);
1333     fprintf(stderr, "    0x%016lx $ra location\n", ra_addr);
1334     fprintf(stderr, "    0x%016lx $ra\n", ra);    
1335     // caller $fp
1336     fprintf(stderr, "    %18s $fp slot\n", fp_debug);
1337     fprintf(stderr, "    0x%016lx $fp location\n", fp_addr);
1338     fprintf(stderr, "    0x%016lx caller $fp\n", fp2);    
1339   }
1340   */
1341
1342   // caller frame is invalid if $pc does not resolve to a function
1343   if (!caller) return Frame(); // zero frame
1344
1345   // return value
1346   Frame ret;
1347   ret.pc_ = ra;
1348   ret.sp_ = fp_native;
1349   ret.fp_ = fp2;
1350
1351   /* 
1352   // debug
1353   fprintf(stderr, "    frame $ra(0x%016lx) $sp(0x%016lx) $fp(0x%016lx)", 
1354           ret.pc_, ret.sp_, ret.fp_);
1355   char *info2 = "";
1356   if (ip2) info2 = (bt2) ? ("[basetramp]") : ("[minitramp]");
1357   fprintf(stderr, " => \"%s\" %s\n", caller->prettyName().string_of(), info2);
1358   */
1359
1360   return ret;
1361 }
1362
1363 // TODO: implement
1364 // do leaf functions exist on Irix (other than syscalls)?
1365 bool process::needToAddALeafFrame(Frame f, Address &leaf_pc) {
1366   return false;
1367 }
1368
1369
1370 //
1371 // paradynd-only methods
1372 //
1373
1374
1375 void OS::osDisconnect(void) {
1376   //fprintf(stderr, ">>> osDisconnect()\n");
1377   int fd = open("/dev/tty", O_RDONLY);
1378   ioctl(fd, TIOCNOTTY, NULL); 
1379   P_close(fd);
1380 }
1381
1382 #ifdef SHM_SAMPLING
1383 // returns user+sys time from the u or proc area of the inferior process, which in
1384 // turn is presumably obtained by mmapping it (sunos) or by using a /proc ioctl
1385 // to obtain it (solaris).  It must not stop the inferior process in order
1386 // to obtain the result, nor can it assue that the inferior has been stopped.
1387 // The result MUST be "in sync" with rtinst's DYNINSTgetCPUtime().
1388 // TODO: "#ifdef PURE_BUILD" support
1389 time64 process::getInferiorProcessCPUtime(int /*lwp_id*/)
1390 {
1391   //fprintf(stderr, ">>> getInferiorProcessCPUtime()\n");
1392   time64 ret;
1393
1394   /*
1395   pracinfo_t t;
1396   ioctl(proc_fd, PIOCACINFO, &t);
1397   ret = PDYN_div1000(t.pr_timers.ac_utime + t.pr_timers.ac_stime);
1398   */
1399
1400   timespec_t t[MAX_PROCTIMER];
1401   if (ioctl(proc_fd, PIOCGETPTIMER, t) == -1) {
1402     //perror("getInferiorProcessCPUtime - PIOCGETPTIMER");
1403     return previous;
1404   }
1405   ret = 0;
1406   ret += PDYN_mulMillion(t[AS_USR_RUN].tv_sec); // sec to usec  (user)
1407   ret += PDYN_mulMillion(t[AS_SYS_RUN].tv_sec); // sec to usec  (sys)
1408   ret += PDYN_div1000(t[AS_USR_RUN].tv_nsec);   // nsec to usec (user)
1409   ret += PDYN_div1000(t[AS_SYS_RUN].tv_nsec);   // nsec to usec (sys)
1410
1411   // sanity check: time should not go backwards
1412   if (ret < previous) {
1413     logLine("*** time going backwards in paradynd ***\n");
1414     ret = previous;
1415   }
1416   previous = ret;
1417
1418   return ret;
1419 }
1420 #endif
1421