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