Added several calls to API (waitForStatusChange, BPatch_variableExpr
[dyninst.git] / dyninstAPI / src / sunos.C
1 /*
2  * Copyright (c) 1996 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  * $Log: sunos.C,v $
44  * Revision 1.35  1998/03/06 21:33:08  buck
45  * Added several calls to API (waitForStatusChange, BPatch_variableExpr
46  * member functions getBaseAddr and readValue, writeValue with an extra
47  * length parameter).
48  * Fixed several bugs in x86 instrumentation code related to parsing jump
49  * tables.
50  * Made changes to work with gcc-built programs on NT.
51  *
52  * Revision 1.1.1.6  1997/07/17 18:15:25  buck
53  * Import latest changes from Wisconsin.
54  *
55  * Revision 1.34  1997/07/17 16:53:07  buck
56  * Eliminated the need to link dyninst API with -lkvm on SunOS,
57  * and added a check for the failure of the "attach" constructor for
58  * process.
59  *
60  * Revision 1.33  1997/07/16 19:24:08  naim
61  * Minor change to my previous commit - naim
62  *
63  * Revision 1.32  1997/07/16 19:13:48  naim
64  * Fixing fork on sunos - naim
65  *
66  * Revision 1.31  1997/07/09 19:30:32  tamches
67  * isLeafFunc() --> hasNoStackFrame()
68  *
69  * Revision 1.30  1997/07/08 19:15:18  buck
70  * Added support for the x86 Solaris platform and dynamically linked
71  * executables to the dyninst API library.
72  *
73  * Revision 1.29  1997/07/01 16:54:56  tamches
74  * dummy set_breakpoint_for_syscall_completion
75  *
76  * Revision 1.28  1997/06/23 19:16:03  buck
77  * Added features to the dyninst API library, including an optional "else"
78  * in a BPatch_ifExpr; the BPatch_setMutationsActive call to temporarily
79  * disable all snippets; and the replaceFunctionCall and removeFunctionCall
80  * member functions of BPatch_thread to retarget or NOOP out a function
81  * call.
82  *
83  * Revision 1.1.1.3  1997/06/11 17:33:02  buck
84  * Update Maryland repository with latest changes from Wisconsin.
85  *
86  * Revision 1.27  1997/05/16 18:48:26  naim
87  * Fixing problem when inferiorRPC was launched and the application was in
88  * the middle of a system call - naim
89  *
90  * Revision 1.26  1997/04/14 00:22:26  newhall
91  * removed class pdFunction and replaced it with base class function_base and
92  * derived class pd_Function
93  *
94  * Revision 1.25  1997/03/18 19:44:25  buck
95  * first commit of dyninst library.  Also includes:
96  *      moving templates from paradynd to dyninstAPI
97  *      converting showError into a function (in showerror.C)
98  *      many ifdefs for BPATCH_LIBRARY in dyinstAPI/src.
99  *
100  * Revision 1.24  1997/02/26 23:43:03  mjrg
101  * First part on WindowsNT port: changes for compiling with Visual C++;
102  * moved unix specific code to unix.C
103  *
104  * Revision 1.23  1997/02/21 20:13:53  naim
105  * Moving files from paradynd to dyninstAPI + moving references to dataReqNode
106  * out of the ast class. The is the first pre-dyninstAPI commit! - naim
107  *
108  * Revision 1.22  1997/01/30 18:14:12  tamches
109  * skeleton isRunning, tryToFindExecutable, and read_inferiorRPC_result_register
110  *
111  * Revision 1.21  1996/11/23 22:46:41  lzheng
112  * Finished the implementation of inferiorPRC on HPUX platfrom
113  *
114  * Revision 1.20  1996/11/19 16:28:24  newhall
115  * Fix to stack walking on Solaris: find leaf functions in stack (these can occur
116  * on top of stack or in middle of stack if the signal handler is on the stack)
117  * Fix to relocated functions: new instrumentation points are kept on a per
118  * process basis.  Cleaned up some of the code.
119  *
120  * Revision 1.19  1996/11/05 20:35:34  tamches
121  * changed some OS:: methods to process:: methods
122  *
123  * Revision 1.18  1996/10/31 08:55:11  tamches
124  * the shm-sampling commit; routines to do inferiorRPC; removed some warnings.
125  *
126  * Revision 1.17  1996/08/20 19:18:02  lzheng
127  * Implementation of moving multiple instructions sequence and
128  * splitting the instrumentation into two phases
129  *
130  * Revision 1.16  1996/08/16 21:19:54  tamches
131  * updated copyright for release 1.1
132  *
133  * Revision 1.15  1996/05/08 23:55:09  mjrg
134  * added support for handling fork and exec by an application
135  * use /proc instead of ptrace on solaris
136  * removed warnings
137  *
138  * Revision 1.14  1996/04/03 14:27:58  naim
139  * Implementation of deallocation of instrumentation for solaris and sunos - naim
140  *
141  * Revision 1.13  1996/03/12  20:48:40  mjrg
142  * Improved handling of process termination
143  * New version of aggregateSample to support adding and removing components
144  * dynamically
145  * Added error messages
146  *
147  * Revision 1.12  1996/02/12 16:46:19  naim
148  * Updating the way we compute number_of_cpus. On solaris we will return the
149  * number of cpus; on sunos, hp, aix 1 and on the CM-5 the number of processes,
150  * which should be equal to the number of cpus - naim
151  *
152  * Revision 1.11  1996/02/09  23:53:48  naim
153  * Adding new internal metric number_of_nodes - naim
154  *
155  * Revision 1.10  1995/11/22  00:02:23  mjrg
156  * Updates for paradyndPVM on solaris
157  * Fixed problem with wrong daemon getting connection to paradyn
158  * Removed -f and -t arguments to paradyn
159  * Added cleanUpAndExit to clean up and exit from pvm before we exit paradynd
160  * Fixed bug in my previous commit
161  *
162  */
163
164
165 #include "dyninstAPI/src/process.h"
166
167 extern "C" {
168 extern int ioctl(int, int, ...);
169 extern int getrusage(int, struct rusage*);
170 #include <a.out.h>
171 #include <sys/exec.h>
172 #include <stab.h>
173 extern struct rusage *mapUarea();
174
175 #include <machine/reg.h> // for ptrace_getregs call
176 };
177
178 #include <sys/ioctl.h>
179 #include <fcntl.h>
180 #include <machine/reg.h>
181 #include <sys/user.h> // for u-area stuff
182
183 #include "dyninstAPI/src/symtab.h"
184 #include "util/h/headers.h"
185 #include "dyninstAPI/src/os.h"
186 #include "dyninstAPI/src/stats.h"
187 #include "util/h/Types.h"
188 #include "paradynd/src/showerror.h"
189 #include "dyninstAPI/src/util.h" // getCurrWallTime
190 #include "util/h/pathName.h"
191
192 #ifdef SHM_SAMPLING
193 #include <kvm.h>
194 #include <sys/user.h>
195 #endif
196
197 // #include <sys/termios.h>
198
199 extern bool isValidAddress(process *proc, Address where);
200
201 extern struct rusage *mapUarea();
202
203 /* ********************************************************************** */
204
205 class ptraceKludge {
206 private:
207   static bool haltProcess(process *p);
208   static void continueProcess(process *p, const bool halted);
209
210 public:
211   static bool deliverPtrace(process *p, enum ptracereq req, void *addr,
212                             int data, void *addr2);
213 //  static bool deliverPtraceFast(process *p, enum ptracereq req, void *addr,
214 //                              int data, void *addr2);
215 //      // like deliverPtrace() but assumes process is paused.
216 };
217
218 bool ptraceKludge::haltProcess(process *p) {
219   bool wasStopped = (p->status() == stopped);
220   if (p->status() != neonatal && !wasStopped) {
221     if (!p->loopUntilStopped()) {
222       cerr << "error in loopUntilStopped\n";
223       assert(0);
224     }
225   }
226   return wasStopped;
227 }
228
229 void ptraceKludge::continueProcess(process *p, const bool wasStopped) {
230   // First handle the cases where we shouldn't issue a PTRACE_CONT:
231   if (p->status() == neonatal) return;
232   if (wasStopped) return;
233
234   // Choose either one of the following methods to continue a process.
235   // The choice must be consistent with that in process::continueProc_ and stop_
236
237 #ifndef PTRACE_ATTACH_DETACH
238   if (P_ptrace(PTRACE_CONT, p->pid, (caddr_t) 1, SIGCONT, NULL) == -1) {
239 #else
240   if (P_ptrace(PTRACE_DETACH, p->pid, (caddr_t) 1, SIGCONT, NULL) == -1) {
241 #endif
242       perror("error in continueProcess");
243       assert(0);
244   }
245 }
246
247 bool ptraceKludge::deliverPtrace(process *p, enum ptracereq req, void *addr,
248                                  int data, void *addr2) {
249   bool halted;
250
251   if (req != PTRACE_DETACH)
252      halted = haltProcess(p);
253
254   bool ret = (P_ptrace(req, p->getPid(), (char*)addr, data, (char*)addr2) != -1);
255
256   if (req != PTRACE_DETACH)
257      continueProcess(p, halted);
258
259   return ret;
260 }
261
262 /* ********************************************************************** */
263
264 void *process::getRegisters() {
265    // ptrace - GETREGS call
266    // assumes the process is stopped (ptrace requires it)
267    assert(status_ == stopped);
268
269    // See <machine/reg.h> and <machine/fp.h>
270    const int numbytesPart1 = sizeof(struct regs);
271    const int numbytesPart2 = sizeof(struct fp_status);
272    assert(numbytesPart1 % 4 == 0);
273    assert(numbytesPart2 % 4 == 0);
274
275    void *buffer = new char[numbytesPart1 + numbytesPart2];
276    assert(buffer);
277
278    struct regs theIntRegs;
279    int result = P_ptrace(PTRACE_GETREGS, pid, (char*)&theIntRegs, 0, 0);
280    assert(result != -1);
281
282    struct fp_status theFpRegs;
283    result = P_ptrace(PTRACE_GETFPREGS, pid, (char*)&theFpRegs, 0, 0);
284    assert(result != -1);
285
286    memcpy(buffer, &theIntRegs, sizeof(theIntRegs));
287    memcpy((char*)buffer + sizeof(theIntRegs), &theFpRegs, sizeof(theFpRegs));
288
289    return buffer;
290 }
291
292 static bool changePC(int pid, struct regs &theIntRegs, unsigned loc) {
293    assert(loc % 4 == 0);
294
295    theIntRegs.r_pc = loc;
296    theIntRegs.r_npc = loc+4;
297
298    if (0 != P_ptrace(PTRACE_SETREGS, pid, (char*)&theIntRegs, 0, 0)) {
299       cerr << "process::changePC failed" << endl;
300       return false;
301    }
302
303    return true;
304 }
305
306 bool process::executingSystemCall() {
307    // this is not implemented yet - naim 5/15/97
308    return false;
309 }
310
311 bool process::changePC(unsigned loc, const void *savedRegs) {
312    assert(status_ == stopped);
313    struct regs theIntRegs = *(const struct regs*)savedRegs; // makes a copy (on purpose)
314
315    return ::changePC(pid, theIntRegs, loc);
316 }
317
318 bool process::changePC(unsigned loc) {
319    assert(status_ == stopped);
320    struct regs theIntRegs;
321    int result = P_ptrace(PTRACE_GETREGS, pid, (char*)&theIntRegs, 0, 0);
322    assert(result != -1);
323
324    return ::changePC(pid, theIntRegs, loc);
325 }
326
327
328 bool process::restoreRegisters(void *buffer) {
329    // two ptrace - SETREGS calls
330    // assumes process is stopped (ptrace requires it)
331    assert(status_ == stopped);
332
333    struct regs theIntRegs = *(struct regs *)buffer;
334    struct fp_status theFpRegs = *(struct fp_status *)((char *)buffer + sizeof(struct regs));
335
336    int result = P_ptrace(PTRACE_SETREGS, pid, (char *)&theIntRegs, 0, 0);
337    if (result == -1) {
338       perror("process::restoreRegisters PTRACE_SETREGS failed");
339       return false;
340    }
341
342    result = P_ptrace(PTRACE_SETFPREGS, pid, (char *)&theFpRegs, 0, 0);
343    if (result == -1) {
344       perror("process::restoreRegisters PTRACE_SETFPREGS failed");
345       return false;
346    }
347
348    return true;
349 }
350
351 bool process::getActiveFrame(int *fp, int *pc)
352 {
353   struct regs regs;
354   if (ptraceKludge::deliverPtrace(this,PTRACE_GETREGS,(char *)&regs,0,0)) {
355     *fp=regs.r_o6;
356     *pc=regs.r_pc;
357
358     return(true);
359   }
360   else return(false);
361 }
362
363 // TODO: implement this
364 bool process::needToAddALeafFrame(Frame,unsigned int &){
365     return false;
366 }
367
368 bool process::readDataFromFrame(int currentFP, int *fp, int *rtn, bool uppermost)
369 {
370   bool readOK=true;
371   struct {
372     int fp;
373     int rtn;
374   } addrs;
375
376   pd_Function *func;
377   int pc = *rtn;
378   struct regs regs; 
379
380   if (uppermost) {
381       func = symbols -> findFunctionIn(pc,this);
382       if (func) {
383           if (func ->hasNoStackFrame()) {
384               if (ptraceKludge::deliverPtrace(this,PTRACE_GETREGS,
385                                               (char *)&regs,0,0)) {
386                   *rtn = regs.r_o7 + 8;
387                   return readOK;
388               }    
389           }
390       }
391   }
392
393   //
394   // For the sparc, register %i7 is the return address - 8 and the fp is
395   // register %i6. These registers can be located in currentFP+14*5 and
396   // currentFP+14*4 respectively, but to avoid two calls to readDataSpace,
397   // we bring both together (i.e. 8 bytes of memory starting at currentFP+14*4
398   // or currentFP+56).
399   //
400
401   if (readDataSpace((caddr_t) (currentFP + 56),
402                     sizeof(int)*2, (caddr_t) &addrs, true)) {
403     // this is the previous frame pointer
404     *fp = addrs.fp;
405     // return address
406     *rtn = addrs.rtn + 8;
407
408     // if pc==0, then we are in the outermost frame and we should stop. We
409     // do this by making fp=0.
410
411     if ( (addrs.rtn == 0) || !isValidAddress(this,(Address) addrs.rtn) ) {
412       readOK=false;
413     }
414   }
415   else {
416     readOK=false;
417   }
418
419   return(readOK);
420 }
421
422 // already setup on this FD.
423 // disconnect from controlling terminal 
424 void OS::osDisconnect(void) {
425   int ttyfd = open ("/dev/tty", O_RDONLY);
426   ioctl (ttyfd, TIOCNOTTY, NULL); 
427   P_close (ttyfd);
428 }
429
430 bool process::stop_() {
431    // formerly OS::osStop()
432
433 /* Choose either one of the following methods for stopping a process, but not both. 
434  * The choice must be consistent with that in process::continueProc_ 
435  * and ptraceKludge::continueProcess
436  */
437
438 #ifndef PTRACE_ATTACH_DETACH
439         return (P_kill(pid, SIGSTOP) != -1); 
440 #else
441         return attach_();
442 #endif
443 }
444
445 bool process::continueWithForwardSignal(int sig) {
446    // formerly OS::osForwardSignal
447    return (P_ptrace(PTRACE_CONT, pid, (char*)1, sig, 0) != -1);
448 }
449
450 void OS::osTraceMe(void) { P_ptrace(PTRACE_TRACEME, 0, 0, 0, 0); }
451
452
453 // wait for a process to terminate or stop
454 #ifdef BPATCH_LIBRARY
455 int process::waitProcs(int *status, bool block) {
456   int options;
457   if (block) options = 0;
458   else options = WNOHANG;
459   return waitpid(0, status, options);
460 }
461 #else
462 int process::waitProcs(int *status) {
463   return waitpid(0, status, WNOHANG);
464 }
465 #endif
466
467 // attach to an inferior process.
468 bool process::attach() {
469   // we only need to attach to a process that is not our direct children.
470   if (parent != 0)
471     return attach_();
472   else
473     return true;
474 }
475
476 bool process::attach_() {
477    return (P_ptrace(PTRACE_ATTACH, getPid(), 0, 0, 0) != -1);
478 }
479
480 bool process::isRunning_() const {
481    // determine if a process is running by doing low-level system checks, as
482    // opposed to checking the 'status_' member vrble.  May assume that attach()
483    // has run, but can't assume anything else.
484
485    assert(false); // not yet implemented!   
486 }
487
488
489 // TODO is this safe here ?
490 bool process::continueProc_() {
491   int ret;
492
493   if (!checkStatus()) 
494     return false;
495
496   ptraceOps++; ptraceOtherOps++;
497
498 /* choose either one of the following ptrace calls, but not both. 
499  * The choice must be consistent with that in stop_ and
500  * ptraceKludge::continueProcess.
501  */
502 #ifndef PTRACE_ATTACH_DETACH
503   if (!ptraceKludge::deliverPtrace(this, PTRACE_CONT, (char*)1, 0, NULL))
504     ret = -1;
505   else
506     ret = 0;
507   //ret = P_ptrace(PTRACE_CONT, pid, (char*)1, 0, (char*)NULL);
508 #else
509   ret = P_ptrace(PTRACE_DETACH, pid, (char*)1, SIGCONT, (char*)NULL);
510 #endif
511
512   if (ret == -1)
513      perror("continueProc_()");
514
515   return ret != -1;
516 }
517
518 #ifdef BPATCH_LIBRARY
519 bool process::terminateProc_()
520 {
521   if (!checkStatus()) 
522     return false;
523
524   if (P_ptrace(PTRACE_KILL, pid, NULL, NULL, NULL) != 0)
525     return false;
526   else
527     return true;
528 }
529 #endif
530
531 // TODO ??
532 bool process::pause_() {
533   if (!checkStatus()) 
534     return false;
535   ptraceOps++; ptraceOtherOps++;
536   bool wasStopped = (status() == stopped);
537   if (status() != neonatal && !wasStopped)
538     return (loopUntilStopped());
539   else
540     return true;
541 }
542
543 bool process::detach_() {
544   if (!checkStatus())
545     return false;
546   ptraceOps++; ptraceOtherOps++;
547   return (ptraceKludge::deliverPtrace(this, PTRACE_DETACH, (char*)1, SIGCONT, NULL));
548 }
549
550 #ifdef BPATCH_LIBRARY
551 bool process::API_detach_(const bool cont) {
552 //  assert(cont);
553   if (!checkStatus())
554     return false;
555   ptraceOps++; ptraceOtherOps++;
556   if (!cont) P_kill(pid, SIGSTOP);
557   return (ptraceKludge::deliverPtrace(this, PTRACE_DETACH, (char*)1, SIGCONT, NULL));
558 }
559 #endif
560
561 // temporarily unimplemented, PTRACE_DUMPCORE is specific to sunos4.1
562 bool process::dumpCore_(const string coreFile) {
563   if (!checkStatus()) 
564     return false;
565   ptraceOps++; ptraceOtherOps++;
566
567   errno = 0;
568   int ret;
569   if (coreFile.length() > 0)
570     ret = P_ptrace(PTRACE_DUMPCORE, pid, P_strdup(coreFile.string_of()), 0, (char*) NULL);
571   else
572     ret = P_ptrace(PTRACE_DUMPCORE, pid, (char *) NULL, 0 , (char *) NULL);
573
574   return (ret != -1);
575 }
576
577 bool process::writeTextWord_(caddr_t inTraced, int data) {
578   if (!checkStatus()) 
579     return false;
580   ptraceBytes += sizeof(int); ptraceOps++;
581
582 //  cerr << "writeTextWord @ " << (void *)inTraced << endl; cerr.flush();
583
584   return (ptraceKludge::deliverPtrace(this, PTRACE_POKETEXT, inTraced, data, NULL));
585 }
586
587 bool process::writeTextSpace_(void *inTraced, int amount, const void *inSelf) {
588   if (!checkStatus()) 
589     return false;
590   ptraceBytes += amount; ptraceOps++;
591
592 //  cerr << "writeTextSpace pid=" << getPid() << ", @ " << (void *)inTraced << " len=" << amount << endl; cerr.flush();
593
594   return (ptraceKludge::deliverPtrace(this, PTRACE_WRITETEXT, inTraced, amount, (void *)inSelf));
595 }
596
597 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
598 bool process::readTextSpace_(void *inTraced, int amount, const void *inSelf) {
599   bool result;
600   if (!checkStatus())
601     result = false;
602   else {
603      ptraceOps++; ptraceBytes += amount;
604      result = ptraceKludge::deliverPtrace(this, PTRACE_READTEXT, 
605                                         (void *)inTraced, amount, inSelf);
606   }
607
608   return result;
609 }
610 #endif
611
612 bool process::writeDataSpace_(void *inTraced, int amount, const void *inSelf) {
613   if (!checkStatus())
614     return false;
615
616   ptraceOps++; ptraceBytes += amount;
617
618 //  cerr << "process::writeDataSpace_ pid " << getPid() << " writing " << amount << " bytes at loc " << inTraced << endl;
619
620   bool result = ptraceKludge::deliverPtrace(this, PTRACE_WRITEDATA, inTraced, amount, (void*)inSelf);
621
622   return result;
623 }
624
625 bool process::readDataSpace_(const void *inTraced, int amount, void *inSelf) {
626   bool result;
627   if (!checkStatus())
628     result = false;
629   else {
630      ptraceOps++; ptraceBytes += amount;
631      result = ptraceKludge::deliverPtrace(this, PTRACE_READDATA, 
632                                         (void *)inTraced, amount, inSelf);
633   }
634
635   return result;
636 }
637
638 #ifdef SHM_SAMPLING
639 time64 process::getInferiorProcessCPUtime() const {
640    // kvm_getproc returns a ptr to a _copy_ of the proc structure
641    // in static memory.
642 //   time64 wall1 = getCurrWallTime();
643    proc *p = kvm_getproc(kvmHandle, getPid());
644    if (p == NULL) {
645       perror("could not getInferiorProcessCPUtime because kvm_getproc failed");
646       exit(5);
647    }
648 //   time64 wall2 = getCurrWallTime();
649 //   time64 difference = wall2-wall1;
650 //   unsigned long difference_long = difference;
651 //   cout << "took " << difference_long << " usecs to kvm_getproc" << endl;
652
653    // kvm_getu returns a copy to a _copy_ of the process' uarea
654    // in static memory.
655    user *u = kvm_getu(kvmHandle, p);
656    if (u == NULL) {
657       perror("could not kvm_getu()");
658       exit(5);
659    }
660
661    return userAndSysTime2uSecs(u->u_ru.ru_utime,
662                                u->u_ru.ru_stime);
663
664    assert(false);
665
666
667
668
669    
670    if (childUareaPtr == NULL) {
671       cout << "cannot read inferior proc cpu time since unmapped...try to implement kvm_getproc instead" << endl;
672       return 0;
673    }
674
675    static time64 prevResult = 0;  // to check for rollback
676
677    while (true) {
678       time64 result = userAndSysTime2uSecs(childUareaPtr->u_ru.ru_utime,
679                                                        childUareaPtr->u_ru.ru_stime);
680       if (result < prevResult) {
681          cout << "process::getInferiorProcessCPUtime() retrying due to rollback!" << endl;
682          continue;
683       }
684       else {
685 cout << "sunos done getting virtual time." << endl; cout.flush();
686          prevResult = result;
687          return result;
688       }
689    }
690 }
691
692 user *process::tryToMapChildUarea(int childpid) {
693    // a static member fn
694    // see DYNINSTprobeUarea of rtinst/src/sunos.c
695
696 assert(0);
697
698    kvm_t *kvmfd = kvm_open(0, 0, 0, O_RDONLY, 0);
699    if (kvmfd == NULL) {
700       perror("could not map child's uarea because kvm_open failed");
701       return NULL;
702    }
703
704    // kvm_getproc returns a ptr to a _copy_ of the proc structure
705    // in static memory.
706    time64 wall1 = getCurrWallTime();
707    proc *p = kvm_getproc(kvmfd, childpid);
708    if (p == NULL) {
709       perror("could not map child's uarea because kvm_getproc failed");
710       return NULL;
711    }
712    time64 wall2 = getCurrWallTime();
713    time64 difference = wall2-wall1;
714    unsigned long difference_long = difference;
715    cout << "took " << difference_long << " usecs to kvm_getproc" << endl;
716
717    // kvm_getu returns a copy to a _copy_ of the process' uarea
718    // in static memory.
719    user *u = kvm_getu(kvmfd, p);
720    if (u == NULL) {
721       perror("could not map child's uarea because kvm_getu failed");
722       return NULL;
723    }
724
725    kvm_close(kvmfd);
726
727    void *uareaPtr = p->p_uarea;
728
729    int kmemfd = open("/dev/kmem", O_RDONLY, 0);
730    if (kmemfd == -1) {
731       perror("could not map child's uarea because could not open /dev/kmem for reading");
732       return NULL;
733    }
734
735    void *result = P_mmap(NULL, sizeof(user), PROT_READ, MAP_SHARED, kmemfd,
736                          (off_t)uareaPtr);
737    if (result == (void *)-1) {
738       perror("could not map child's uarea because could not mmap /dev/kmem");
739       close(kmemfd);
740       return NULL;
741    }
742
743    cout << "mmap of child's uarea succeeded!" << endl;
744
745    return (user *)result;
746 }
747 #endif
748
749 //time64 process::getInferiorProcessCPUtime() const {
750 //   // We get the inferior process's cpu time via a ptrace() of the u-area
751 //   // of the inferior process, though it should be possible to mmap()
752 //   // the inferior process's uarea into paradynd if we really want to...
753 //
754 //   // UH OH: this will only work if the inferior process has been stopped!!!
755 //
756 //   static time64 prevResult = 0;
757 //
758 //   while (true) {
759 //      // assumes child process has been stopped
760 //      user childUareaPtr; // just a dummy
761 //      unsigned addrOffset = (void *)&childUareaPtr.u_ru.ru_utime - (void *)&childUareaPtr;
762 //      unsigned numBytesNeeded = (void *)&childUareaPtr.u_ru.ru_maxrss -
763 //                                (void *)&childUareaPtr.u_ru.ru_utime;
764 //      assert(numBytesNeeded % 4 == 0);
765 //
766 //      rusage theUsage; // we'll write into the first few bytes of this structure
767 //      void *ptr = &theUsage.ru_utime;
768 //
769 //      cout << "peeking from uarea for pid " << this->getPid() << endl; cout.flush();
770 //      while (numBytesNeeded) {
771 //         errno = 0;
772 //         unsigned result = P_ptrace(PTRACE_PEEKUSER, this->getPid(),
773 //                                  (char*)addrOffset, 0, NULL);
774 //         if (errno != 0) {
775 //            perror("could not getChildCPUtimeViaPtraceOfUarea: ptrace()");
776 //            exit(5);
777 //         }
778 //
779 //         memcpy(ptr, &result, 4);
780 //         ptr += 4;
781 //         addrOffset += 4;
782 //         numBytesNeeded -= 4;
783 //      }
784 //
785 //      time64 result = userAndSysTime2uSecs(theUsage.ru_utime, theUsage.ru_stime);
786 //      if (result < prevResult) {
787 //         cout << "process::getInferiorProcessCPUtime() retrying due to rollback!" << endl;
788 //         continue;
789 //      }
790 //      else {
791 //         prevResult = result;
792 //         return result;
793 //      }
794 //   }
795 //}
796
797 bool process::loopUntilStopped() {
798   /* make sure the process is stopped in the eyes of ptrace */
799   stop_(); // sends SIGSTOP signal to the process
800
801   while (true) {
802     int waitStatus;
803     int ret = P_waitpid(pid, &waitStatus, WUNTRACED);
804     if ((ret == -1 && errno == ECHILD) || (WIFEXITED(waitStatus))) {
805       // the child is gone.
806       handleProcessExit(this, WEXITSTATUS(waitStatus));
807       return(false);
808     } else if (WIFSIGNALED(waitStatus)) {
809       handleProcessExit(this, WTERMSIG(waitStatus));
810       return false;
811     } else if (WIFSTOPPED(waitStatus)) {
812       int sig = WSTOPSIG(waitStatus);
813       if (sig == SIGSTOP) {
814         break; // success
815       } else {
816         extern int handleSigChild(int, int);
817         handleSigChild(pid, waitStatus);
818       }
819     }
820     else {
821       logLine("Problem stopping process\n");
822       abort();
823     }
824   }
825   return true;
826 }
827
828 #ifdef BPATCH_LIBRARY
829 bool process::dumpImage(string outFile) {
830 #else
831 bool process::dumpImage() {
832 #endif
833   const string &imageFileName = symbols->file();
834   const Address codeOff = symbols->codeOffset();
835
836   u_int i;
837   int rd;
838   int ifd;
839   int ofd;
840   int total;
841   int length;
842   struct exec my_exec;
843   char buffer[4096];
844 #ifndef BPATCH_LIBRARY
845   char outFile[256];
846 #endif
847   extern int errno;
848   struct stat statBuf;
849
850   ifd = P_open(imageFileName.string_of(), O_RDONLY, 0);
851   if (ifd < 0) {
852     string msg = string("Dump core failed: unable to open file '") + imageFileName 
853                  + string("': ") + string(sys_errlist[errno]);
854     showErrorCallback(47, msg);
855     return false;
856   }
857
858   rd = P_read(ifd, (void *) &my_exec, sizeof(struct exec));
859   if (rd != sizeof(struct exec)) {
860     string msg = string("Dump core failed: read failed '") + imageFileName 
861                  + string("': ") + string(sys_errlist[errno]);
862     showErrorCallback(47, msg);
863     P_close(ifd);
864     return false;
865   }
866
867   rd = P_fstat(ifd, &statBuf);
868   if (rd != 0) {
869     string msg = string("Dump core failed: fstat failed: ") + string(sys_errlist[errno]);
870     showErrorCallback(47, msg);
871     P_close(ifd);
872     return false;
873   }
874   length = statBuf.st_size;
875 #ifdef BPATCH_LIBRARY
876   ofd = P_open(outFile.string_of(), O_WRONLY|O_CREAT, 0777);
877   if (ofd < 0) {
878     string msg = string("Dump core failed: unable to open file '") + outFile
879                  + string("': ") + string(sys_errlist[errno]);
880 #else
881   sprintf(outFile, "%s.real", imageFileName.string_of());
882   sprintf(errorLine, "saving program to %s\n", outFile);
883   logLine(errorLine);
884
885   ofd = P_open(outFile, O_WRONLY|O_CREAT, 0777);
886   if (ofd < 0) {
887     string msg = string("Dump core failed: unable to open file '") + string(outFile) 
888                  + string("': ") + string(sys_errlist[errno]);
889 #endif
890     showErrorCallback(47, msg);
891     P_close(ifd);
892     return false;
893     //P_perror("open");
894     //cleanUpAndExit(-1);
895   }
896   /* now copy the rest */
897
898   P_lseek(ofd, 0, SEEK_SET);
899   P_write(ofd, (void*) &my_exec, sizeof(struct exec));
900
901   if (!stopped) {
902     // make sure it is stopped.
903     stop_();
904     P_waitpid(pid, NULL, WUNTRACED);
905   }
906
907   P_lseek(ofd, N_TXTOFF(my_exec), SEEK_SET);
908   for (i=0; i < my_exec.a_text; i+= 4096) {
909     errno = 0;
910     P_ptrace(PTRACE_READTEXT, pid, (char*) (codeOff + i), 4096, buffer);
911     if (errno) {
912       string msg = string("Dump core failed: ptrace failed: ") 
913                    + string(sys_errlist[errno]);
914       showErrorCallback(47, msg);
915       P_close(ofd); P_close(ifd);
916       return false;
917     }
918     P_write(ofd, buffer, 4096);
919   }
920
921   P_ptrace(PTRACE_CONT, pid, (char*) 1, SIGCONT, 0);
922
923   rd = P_lseek(ofd, N_DATOFF(my_exec), SEEK_SET);
924   if (rd != N_DATOFF(my_exec)) {
925     string msg = string("Dump core failed: lseek failed: ") 
926                    + string(sys_errlist[errno]);
927     showErrorCallback(47, msg);
928     P_close(ofd); P_close(ifd);
929     return false;
930     //P_perror("lseek");
931     //cleanUpAndExit(-1);
932   }
933
934   rd = P_lseek(ifd, N_DATOFF(my_exec), SEEK_SET);
935   if (rd != N_DATOFF(my_exec)) {
936     string msg = string("Dump core failed: lseek failed: ") 
937                    + string(sys_errlist[errno]);
938     showErrorCallback(47, msg);
939     P_close(ofd); P_close(ifd);
940     return false;
941     //P_perror("lseek");
942     //cleanUpAndExit(-1);
943   }
944
945   total = N_DATOFF(my_exec);
946   for (i=N_DATOFF(my_exec); i < length; i += 4096) {
947     rd = P_read(ifd, buffer, 4096);
948     P_write(ofd, buffer, rd);
949     total += rd;
950   }
951   if (total != length) {
952     string msg = string("Dump core failed: tried to write ") + string(length) +
953                  string(" bytes, only ") + string(total) + string("written");
954     showErrorCallback(47, msg);
955     P_close(ofd); P_close(ifd);
956     return false;
957     //sprintf(errorLine, "Tried to write %d bytes, only %d written\n",
958     //      length, total);
959     //logLine(errorLine);
960     //showErrorCallback(57, (const char *) errorLine);
961   }
962
963   P_close(ofd);
964   P_close(ifd);
965   return true;
966 }
967
968 #ifdef BPATCH_LIBRARY
969 float OS::compute_rusage_cpu() { return 0; }
970
971 float OS::compute_rusage_sys() { return 0; }
972
973 float OS::compute_rusage_min() { return 0; }
974
975 float OS::compute_rusage_maj() { return 0; }
976
977 float OS::compute_rusage_swap() { return 0; }
978
979 float OS::compute_rusage_io_in() { return 0; }
980
981 float OS::compute_rusage_io_out() { return 0; }
982
983 float OS::compute_rusage_msg_send() { return 0; }
984
985 float OS::compute_rusage_msg_recv() { return 0; }
986
987 float OS::compute_rusage_sigs() { return 0; }
988
989 float OS::compute_rusage_vol_cs() { return 0; }
990
991 float OS::compute_rusage_inv_cs() { return 0; }
992
993 #else /* BPATCH_LIBRARY */
994 // TODO -- only call getrusage once per round
995 static struct rusage *get_usage_data() {
996   static bool init = false;
997   static struct rusage *mapped = NULL;
998   static struct rusage other;
999
1000   if (!init) {
1001     mapped = mapUarea();
1002     init = true;
1003   }
1004   if (!mapped) {
1005     mapped = &other;
1006     if (!getrusage(RUSAGE_SELF, &other))
1007       return mapped;
1008     else
1009       return NULL;
1010   } else
1011     return mapped;
1012 }
1013
1014 float OS::compute_rusage_cpu() {
1015   struct rusage *ru = get_usage_data();
1016   if (ru) {
1017     return ((float)ru->ru_utime.tv_sec + (float)ru->ru_utime.tv_usec / 1000000.0);
1018   } else
1019     return 0;
1020 }
1021
1022 float OS::compute_rusage_sys() {
1023   struct rusage *ru = get_usage_data();
1024   if (ru) {
1025     return ((float)ru->ru_stime.tv_sec + (float)ru->ru_stime.tv_usec / 1000000.0);
1026   } else
1027     return 0;
1028 }
1029
1030 float OS::compute_rusage_min() {
1031   struct rusage *ru = get_usage_data();
1032   if (ru) {
1033     return ((float) ru->ru_minflt);
1034   } else
1035     return 0;
1036 }
1037 float OS::compute_rusage_maj() {
1038   struct rusage *ru = get_usage_data();
1039   if (ru) {
1040     return ((float) ru->ru_majflt);
1041   } else
1042     return 0;
1043 }
1044 float OS::compute_rusage_swap() {
1045   struct rusage *ru = get_usage_data();
1046   if (ru) {
1047     return ((float) ru->ru_nswap);
1048   } else
1049     return 0;
1050 }
1051 float OS::compute_rusage_io_in() {
1052   struct rusage *ru = get_usage_data();
1053   if (ru) {
1054     return ((float) ru->ru_inblock);
1055   } else
1056     return 0;
1057 }
1058 float OS::compute_rusage_io_out() {
1059   struct rusage *ru = get_usage_data();
1060   if (ru) {
1061     return ((float) ru->ru_oublock);
1062   } else
1063     return 0;
1064 }
1065 float OS::compute_rusage_msg_send() {
1066   struct rusage *ru = get_usage_data();
1067   if (ru) {
1068     return ((float) ru->ru_msgsnd);
1069   } else
1070     return 0;
1071 }
1072 float OS::compute_rusage_msg_recv() {
1073   struct rusage *ru = get_usage_data();
1074   if (ru) {
1075     return ((float) ru->ru_msgrcv);
1076   } else
1077     return 0;
1078 }
1079 float OS::compute_rusage_sigs() {
1080   struct rusage *ru = get_usage_data();
1081   if (ru) {
1082     return ((float) ru->ru_nsignals);
1083   } else
1084     return 0;
1085 }
1086 float OS::compute_rusage_vol_cs() {
1087   struct rusage *ru = get_usage_data();
1088   if (ru) {
1089     return ((float) ru->ru_nvcsw);
1090   } else
1091     return 0;
1092 }
1093 float OS::compute_rusage_inv_cs() {
1094   struct rusage *ru = get_usage_data();
1095   if (ru) {
1096     return ((float) ru->ru_nivcsw);
1097   } else
1098     return 0;
1099 }
1100 #endif /* BPATCH_LIBRARY */
1101
1102 int getNumberOfCPUs()
1103 {
1104   return(1);
1105 }
1106
1107 string process::tryToFindExecutable(const string &progpath, int pid) {
1108    // returns empty string on failure
1109
1110    if (progpath.length() == 0)
1111       return "";
1112
1113    if (exists_executable(progpath))
1114       return progpath;
1115
1116    return ""; // failure
1117 }
1118
1119 unsigned process::read_inferiorRPC_result_register(reg) {
1120    // on sparc, the result register is always in o0, so no need to use the input arg.
1121    struct regs regs;
1122    if (!ptraceKludge::deliverPtrace(this, PTRACE_GETREGS, (char*)&regs, 0, 0))
1123       assert(false);
1124    return regs.r_o0;
1125 }
1126
1127 bool process::set_breakpoint_for_syscall_completion() {
1128    // SUNos can't do this (as far as I know)
1129    return false;
1130 }