2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
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
48 * Fixed several bugs in x86 instrumentation code related to parsing jump
50 * Made changes to work with gcc-built programs on NT.
52 * Revision 1.1.1.6 1997/07/17 18:15:25 buck
53 * Import latest changes from Wisconsin.
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
60 * Revision 1.33 1997/07/16 19:24:08 naim
61 * Minor change to my previous commit - naim
63 * Revision 1.32 1997/07/16 19:13:48 naim
64 * Fixing fork on sunos - naim
66 * Revision 1.31 1997/07/09 19:30:32 tamches
67 * isLeafFunc() --> hasNoStackFrame()
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.
73 * Revision 1.29 1997/07/01 16:54:56 tamches
74 * dummy set_breakpoint_for_syscall_completion
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
83 * Revision 1.1.1.3 1997/06/11 17:33:02 buck
84 * Update Maryland repository with latest changes from Wisconsin.
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
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
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.
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
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
108 * Revision 1.22 1997/01/30 18:14:12 tamches
109 * skeleton isRunning, tryToFindExecutable, and read_inferiorRPC_result_register
111 * Revision 1.21 1996/11/23 22:46:41 lzheng
112 * Finished the implementation of inferiorPRC on HPUX platfrom
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.
120 * Revision 1.19 1996/11/05 20:35:34 tamches
121 * changed some OS:: methods to process:: methods
123 * Revision 1.18 1996/10/31 08:55:11 tamches
124 * the shm-sampling commit; routines to do inferiorRPC; removed some warnings.
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
130 * Revision 1.16 1996/08/16 21:19:54 tamches
131 * updated copyright for release 1.1
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
138 * Revision 1.14 1996/04/03 14:27:58 naim
139 * Implementation of deallocation of instrumentation for solaris and sunos - naim
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
145 * Added error messages
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
152 * Revision 1.11 1996/02/09 23:53:48 naim
153 * Adding new internal metric number_of_nodes - naim
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
165 #include "dyninstAPI/src/process.h"
168 extern int ioctl(int, int, ...);
169 extern int getrusage(int, struct rusage*);
171 #include <sys/exec.h>
173 extern struct rusage *mapUarea();
175 #include <machine/reg.h> // for ptrace_getregs call
178 #include <sys/ioctl.h>
180 #include <machine/reg.h>
181 #include <sys/user.h> // for u-area stuff
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"
194 #include <sys/user.h>
197 // #include <sys/termios.h>
199 extern bool isValidAddress(process *proc, Address where);
201 extern struct rusage *mapUarea();
203 /* ********************************************************************** */
207 static bool haltProcess(process *p);
208 static void continueProcess(process *p, const bool halted);
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.
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";
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;
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_
237 #ifndef PTRACE_ATTACH_DETACH
238 if (P_ptrace(PTRACE_CONT, p->pid, (caddr_t) 1, SIGCONT, NULL) == -1) {
240 if (P_ptrace(PTRACE_DETACH, p->pid, (caddr_t) 1, SIGCONT, NULL) == -1) {
242 perror("error in continueProcess");
247 bool ptraceKludge::deliverPtrace(process *p, enum ptracereq req, void *addr,
248 int data, void *addr2) {
251 if (req != PTRACE_DETACH)
252 halted = haltProcess(p);
254 bool ret = (P_ptrace(req, p->getPid(), (char*)addr, data, (char*)addr2) != -1);
256 if (req != PTRACE_DETACH)
257 continueProcess(p, halted);
262 /* ********************************************************************** */
264 void *process::getRegisters() {
265 // ptrace - GETREGS call
266 // assumes the process is stopped (ptrace requires it)
267 assert(status_ == stopped);
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);
275 void *buffer = new char[numbytesPart1 + numbytesPart2];
278 struct regs theIntRegs;
279 int result = P_ptrace(PTRACE_GETREGS, pid, (char*)&theIntRegs, 0, 0);
280 assert(result != -1);
282 struct fp_status theFpRegs;
283 result = P_ptrace(PTRACE_GETFPREGS, pid, (char*)&theFpRegs, 0, 0);
284 assert(result != -1);
286 memcpy(buffer, &theIntRegs, sizeof(theIntRegs));
287 memcpy((char*)buffer + sizeof(theIntRegs), &theFpRegs, sizeof(theFpRegs));
292 static bool changePC(int pid, struct regs &theIntRegs, unsigned loc) {
293 assert(loc % 4 == 0);
295 theIntRegs.r_pc = loc;
296 theIntRegs.r_npc = loc+4;
298 if (0 != P_ptrace(PTRACE_SETREGS, pid, (char*)&theIntRegs, 0, 0)) {
299 cerr << "process::changePC failed" << endl;
306 bool process::executingSystemCall() {
307 // this is not implemented yet - naim 5/15/97
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)
315 return ::changePC(pid, theIntRegs, loc);
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);
324 return ::changePC(pid, theIntRegs, loc);
328 bool process::restoreRegisters(void *buffer) {
329 // two ptrace - SETREGS calls
330 // assumes process is stopped (ptrace requires it)
331 assert(status_ == stopped);
333 struct regs theIntRegs = *(struct regs *)buffer;
334 struct fp_status theFpRegs = *(struct fp_status *)((char *)buffer + sizeof(struct regs));
336 int result = P_ptrace(PTRACE_SETREGS, pid, (char *)&theIntRegs, 0, 0);
338 perror("process::restoreRegisters PTRACE_SETREGS failed");
342 result = P_ptrace(PTRACE_SETFPREGS, pid, (char *)&theFpRegs, 0, 0);
344 perror("process::restoreRegisters PTRACE_SETFPREGS failed");
351 bool process::getActiveFrame(int *fp, int *pc)
354 if (ptraceKludge::deliverPtrace(this,PTRACE_GETREGS,(char *)®s,0,0)) {
363 // TODO: implement this
364 bool process::needToAddALeafFrame(Frame,unsigned int &){
368 bool process::readDataFromFrame(int currentFP, int *fp, int *rtn, bool uppermost)
381 func = symbols -> findFunctionIn(pc,this);
383 if (func ->hasNoStackFrame()) {
384 if (ptraceKludge::deliverPtrace(this,PTRACE_GETREGS,
385 (char *)®s,0,0)) {
386 *rtn = regs.r_o7 + 8;
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
401 if (readDataSpace((caddr_t) (currentFP + 56),
402 sizeof(int)*2, (caddr_t) &addrs, true)) {
403 // this is the previous frame pointer
406 *rtn = addrs.rtn + 8;
408 // if pc==0, then we are in the outermost frame and we should stop. We
409 // do this by making fp=0.
411 if ( (addrs.rtn == 0) || !isValidAddress(this,(Address) addrs.rtn) ) {
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);
430 bool process::stop_() {
431 // formerly OS::osStop()
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
438 #ifndef PTRACE_ATTACH_DETACH
439 return (P_kill(pid, SIGSTOP) != -1);
445 bool process::continueWithForwardSignal(int sig) {
446 // formerly OS::osForwardSignal
447 return (P_ptrace(PTRACE_CONT, pid, (char*)1, sig, 0) != -1);
450 void OS::osTraceMe(void) { P_ptrace(PTRACE_TRACEME, 0, 0, 0, 0); }
453 // wait for a process to terminate or stop
454 #ifdef BPATCH_LIBRARY
455 int process::waitProcs(int *status, bool block) {
457 if (block) options = 0;
458 else options = WNOHANG;
459 return waitpid(0, status, options);
462 int process::waitProcs(int *status) {
463 return waitpid(0, status, WNOHANG);
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.
476 bool process::attach_() {
477 return (P_ptrace(PTRACE_ATTACH, getPid(), 0, 0, 0) != -1);
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.
485 assert(false); // not yet implemented!
489 // TODO is this safe here ?
490 bool process::continueProc_() {
496 ptraceOps++; ptraceOtherOps++;
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.
502 #ifndef PTRACE_ATTACH_DETACH
503 if (!ptraceKludge::deliverPtrace(this, PTRACE_CONT, (char*)1, 0, NULL))
507 //ret = P_ptrace(PTRACE_CONT, pid, (char*)1, 0, (char*)NULL);
509 ret = P_ptrace(PTRACE_DETACH, pid, (char*)1, SIGCONT, (char*)NULL);
513 perror("continueProc_()");
518 #ifdef BPATCH_LIBRARY
519 bool process::terminateProc_()
524 if (P_ptrace(PTRACE_KILL, pid, NULL, NULL, NULL) != 0)
532 bool process::pause_() {
535 ptraceOps++; ptraceOtherOps++;
536 bool wasStopped = (status() == stopped);
537 if (status() != neonatal && !wasStopped)
538 return (loopUntilStopped());
543 bool process::detach_() {
546 ptraceOps++; ptraceOtherOps++;
547 return (ptraceKludge::deliverPtrace(this, PTRACE_DETACH, (char*)1, SIGCONT, NULL));
550 #ifdef BPATCH_LIBRARY
551 bool process::API_detach_(const bool cont) {
555 ptraceOps++; ptraceOtherOps++;
556 if (!cont) P_kill(pid, SIGSTOP);
557 return (ptraceKludge::deliverPtrace(this, PTRACE_DETACH, (char*)1, SIGCONT, NULL));
561 // temporarily unimplemented, PTRACE_DUMPCORE is specific to sunos4.1
562 bool process::dumpCore_(const string coreFile) {
565 ptraceOps++; ptraceOtherOps++;
569 if (coreFile.length() > 0)
570 ret = P_ptrace(PTRACE_DUMPCORE, pid, P_strdup(coreFile.string_of()), 0, (char*) NULL);
572 ret = P_ptrace(PTRACE_DUMPCORE, pid, (char *) NULL, 0 , (char *) NULL);
577 bool process::writeTextWord_(caddr_t inTraced, int data) {
580 ptraceBytes += sizeof(int); ptraceOps++;
582 // cerr << "writeTextWord @ " << (void *)inTraced << endl; cerr.flush();
584 return (ptraceKludge::deliverPtrace(this, PTRACE_POKETEXT, inTraced, data, NULL));
587 bool process::writeTextSpace_(void *inTraced, int amount, const void *inSelf) {
590 ptraceBytes += amount; ptraceOps++;
592 // cerr << "writeTextSpace pid=" << getPid() << ", @ " << (void *)inTraced << " len=" << amount << endl; cerr.flush();
594 return (ptraceKludge::deliverPtrace(this, PTRACE_WRITETEXT, inTraced, amount, (void *)inSelf));
597 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
598 bool process::readTextSpace_(void *inTraced, int amount, const void *inSelf) {
603 ptraceOps++; ptraceBytes += amount;
604 result = ptraceKludge::deliverPtrace(this, PTRACE_READTEXT,
605 (void *)inTraced, amount, inSelf);
612 bool process::writeDataSpace_(void *inTraced, int amount, const void *inSelf) {
616 ptraceOps++; ptraceBytes += amount;
618 // cerr << "process::writeDataSpace_ pid " << getPid() << " writing " << amount << " bytes at loc " << inTraced << endl;
620 bool result = ptraceKludge::deliverPtrace(this, PTRACE_WRITEDATA, inTraced, amount, (void*)inSelf);
625 bool process::readDataSpace_(const void *inTraced, int amount, void *inSelf) {
630 ptraceOps++; ptraceBytes += amount;
631 result = ptraceKludge::deliverPtrace(this, PTRACE_READDATA,
632 (void *)inTraced, amount, inSelf);
639 time64 process::getInferiorProcessCPUtime() const {
640 // kvm_getproc returns a ptr to a _copy_ of the proc structure
642 // time64 wall1 = getCurrWallTime();
643 proc *p = kvm_getproc(kvmHandle, getPid());
645 perror("could not getInferiorProcessCPUtime because kvm_getproc failed");
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;
653 // kvm_getu returns a copy to a _copy_ of the process' uarea
655 user *u = kvm_getu(kvmHandle, p);
657 perror("could not kvm_getu()");
661 return userAndSysTime2uSecs(u->u_ru.ru_utime,
670 if (childUareaPtr == NULL) {
671 cout << "cannot read inferior proc cpu time since unmapped...try to implement kvm_getproc instead" << endl;
675 static time64 prevResult = 0; // to check for rollback
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;
685 cout << "sunos done getting virtual time." << endl; cout.flush();
692 user *process::tryToMapChildUarea(int childpid) {
693 // a static member fn
694 // see DYNINSTprobeUarea of rtinst/src/sunos.c
698 kvm_t *kvmfd = kvm_open(0, 0, 0, O_RDONLY, 0);
700 perror("could not map child's uarea because kvm_open failed");
704 // kvm_getproc returns a ptr to a _copy_ of the proc structure
706 time64 wall1 = getCurrWallTime();
707 proc *p = kvm_getproc(kvmfd, childpid);
709 perror("could not map child's uarea because kvm_getproc failed");
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;
717 // kvm_getu returns a copy to a _copy_ of the process' uarea
719 user *u = kvm_getu(kvmfd, p);
721 perror("could not map child's uarea because kvm_getu failed");
727 void *uareaPtr = p->p_uarea;
729 int kmemfd = open("/dev/kmem", O_RDONLY, 0);
731 perror("could not map child's uarea because could not open /dev/kmem for reading");
735 void *result = P_mmap(NULL, sizeof(user), PROT_READ, MAP_SHARED, kmemfd,
737 if (result == (void *)-1) {
738 perror("could not map child's uarea because could not mmap /dev/kmem");
743 cout << "mmap of child's uarea succeeded!" << endl;
745 return (user *)result;
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...
754 // // UH OH: this will only work if the inferior process has been stopped!!!
756 // static time64 prevResult = 0;
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);
766 // rusage theUsage; // we'll write into the first few bytes of this structure
767 // void *ptr = &theUsage.ru_utime;
769 // cout << "peeking from uarea for pid " << this->getPid() << endl; cout.flush();
770 // while (numBytesNeeded) {
772 // unsigned result = P_ptrace(PTRACE_PEEKUSER, this->getPid(),
773 // (char*)addrOffset, 0, NULL);
775 // perror("could not getChildCPUtimeViaPtraceOfUarea: ptrace()");
779 // memcpy(ptr, &result, 4);
782 // numBytesNeeded -= 4;
785 // time64 result = userAndSysTime2uSecs(theUsage.ru_utime, theUsage.ru_stime);
786 // if (result < prevResult) {
787 // cout << "process::getInferiorProcessCPUtime() retrying due to rollback!" << endl;
791 // prevResult = result;
797 bool process::loopUntilStopped() {
798 /* make sure the process is stopped in the eyes of ptrace */
799 stop_(); // sends SIGSTOP signal to the process
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));
808 } else if (WIFSIGNALED(waitStatus)) {
809 handleProcessExit(this, WTERMSIG(waitStatus));
811 } else if (WIFSTOPPED(waitStatus)) {
812 int sig = WSTOPSIG(waitStatus);
813 if (sig == SIGSTOP) {
816 extern int handleSigChild(int, int);
817 handleSigChild(pid, waitStatus);
821 logLine("Problem stopping process\n");
828 #ifdef BPATCH_LIBRARY
829 bool process::dumpImage(string outFile) {
831 bool process::dumpImage() {
833 const string &imageFileName = symbols->file();
834 const Address codeOff = symbols->codeOffset();
844 #ifndef BPATCH_LIBRARY
850 ifd = P_open(imageFileName.string_of(), O_RDONLY, 0);
852 string msg = string("Dump core failed: unable to open file '") + imageFileName
853 + string("': ") + string(sys_errlist[errno]);
854 showErrorCallback(47, msg);
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);
867 rd = P_fstat(ifd, &statBuf);
869 string msg = string("Dump core failed: fstat failed: ") + string(sys_errlist[errno]);
870 showErrorCallback(47, msg);
874 length = statBuf.st_size;
875 #ifdef BPATCH_LIBRARY
876 ofd = P_open(outFile.string_of(), O_WRONLY|O_CREAT, 0777);
878 string msg = string("Dump core failed: unable to open file '") + outFile
879 + string("': ") + string(sys_errlist[errno]);
881 sprintf(outFile, "%s.real", imageFileName.string_of());
882 sprintf(errorLine, "saving program to %s\n", outFile);
885 ofd = P_open(outFile, O_WRONLY|O_CREAT, 0777);
887 string msg = string("Dump core failed: unable to open file '") + string(outFile)
888 + string("': ") + string(sys_errlist[errno]);
890 showErrorCallback(47, msg);
894 //cleanUpAndExit(-1);
896 /* now copy the rest */
898 P_lseek(ofd, 0, SEEK_SET);
899 P_write(ofd, (void*) &my_exec, sizeof(struct exec));
902 // make sure it is stopped.
904 P_waitpid(pid, NULL, WUNTRACED);
907 P_lseek(ofd, N_TXTOFF(my_exec), SEEK_SET);
908 for (i=0; i < my_exec.a_text; i+= 4096) {
910 P_ptrace(PTRACE_READTEXT, pid, (char*) (codeOff + i), 4096, buffer);
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);
918 P_write(ofd, buffer, 4096);
921 P_ptrace(PTRACE_CONT, pid, (char*) 1, SIGCONT, 0);
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);
931 //cleanUpAndExit(-1);
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);
942 //cleanUpAndExit(-1);
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);
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);
957 //sprintf(errorLine, "Tried to write %d bytes, only %d written\n",
959 //logLine(errorLine);
960 //showErrorCallback(57, (const char *) errorLine);
968 #ifdef BPATCH_LIBRARY
969 float OS::compute_rusage_cpu() { return 0; }
971 float OS::compute_rusage_sys() { return 0; }
973 float OS::compute_rusage_min() { return 0; }
975 float OS::compute_rusage_maj() { return 0; }
977 float OS::compute_rusage_swap() { return 0; }
979 float OS::compute_rusage_io_in() { return 0; }
981 float OS::compute_rusage_io_out() { return 0; }
983 float OS::compute_rusage_msg_send() { return 0; }
985 float OS::compute_rusage_msg_recv() { return 0; }
987 float OS::compute_rusage_sigs() { return 0; }
989 float OS::compute_rusage_vol_cs() { return 0; }
991 float OS::compute_rusage_inv_cs() { return 0; }
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;
1001 mapped = mapUarea();
1006 if (!getrusage(RUSAGE_SELF, &other))
1014 float OS::compute_rusage_cpu() {
1015 struct rusage *ru = get_usage_data();
1017 return ((float)ru->ru_utime.tv_sec + (float)ru->ru_utime.tv_usec / 1000000.0);
1022 float OS::compute_rusage_sys() {
1023 struct rusage *ru = get_usage_data();
1025 return ((float)ru->ru_stime.tv_sec + (float)ru->ru_stime.tv_usec / 1000000.0);
1030 float OS::compute_rusage_min() {
1031 struct rusage *ru = get_usage_data();
1033 return ((float) ru->ru_minflt);
1037 float OS::compute_rusage_maj() {
1038 struct rusage *ru = get_usage_data();
1040 return ((float) ru->ru_majflt);
1044 float OS::compute_rusage_swap() {
1045 struct rusage *ru = get_usage_data();
1047 return ((float) ru->ru_nswap);
1051 float OS::compute_rusage_io_in() {
1052 struct rusage *ru = get_usage_data();
1054 return ((float) ru->ru_inblock);
1058 float OS::compute_rusage_io_out() {
1059 struct rusage *ru = get_usage_data();
1061 return ((float) ru->ru_oublock);
1065 float OS::compute_rusage_msg_send() {
1066 struct rusage *ru = get_usage_data();
1068 return ((float) ru->ru_msgsnd);
1072 float OS::compute_rusage_msg_recv() {
1073 struct rusage *ru = get_usage_data();
1075 return ((float) ru->ru_msgrcv);
1079 float OS::compute_rusage_sigs() {
1080 struct rusage *ru = get_usage_data();
1082 return ((float) ru->ru_nsignals);
1086 float OS::compute_rusage_vol_cs() {
1087 struct rusage *ru = get_usage_data();
1089 return ((float) ru->ru_nvcsw);
1093 float OS::compute_rusage_inv_cs() {
1094 struct rusage *ru = get_usage_data();
1096 return ((float) ru->ru_nivcsw);
1100 #endif /* BPATCH_LIBRARY */
1102 int getNumberOfCPUs()
1107 string process::tryToFindExecutable(const string &progpath, int pid) {
1108 // returns empty string on failure
1110 if (progpath.length() == 0)
1113 if (exists_executable(progpath))
1116 return ""; // failure
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.
1122 if (!ptraceKludge::deliverPtrace(this, PTRACE_GETREGS, (char*)®s, 0, 0))
1127 bool process::set_breakpoint_for_syscall_completion() {
1128 // SUNos can't do this (as far as I know)