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