added some comments
[dyninst.git] / dyninstAPI / src / solaris.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 #include "symtab.h"
43 #include "util/h/headers.h"
44 #include "os.h"
45 #include "paradynd/src/process.h"
46 #include "symtab.h"
47 #include "stats.h"
48 #include "util/h/Types.h"
49 #include <sys/ioctl.h>
50 #include <fcntl.h>
51 #include <sys/termios.h>
52 #include <unistd.h>
53 #include "showerror.h"
54
55 #include <sys/procfs.h>
56 #include <poll.h>
57 #include <limits.h>
58 #include <link.h>
59
60 extern "C" {
61 extern int ioctl(int, int, ...);
62 extern long sysconf(int);
63 };
64
65 /*
66    Define the indices of some registers to be used with pr_reg.
67    These values are different on sparc and x86 platforms.
68    RETVAL_REG: the registers that holds the return value of calls ($o0 on sparc,
69                %eax on x86).
70    PC_REG: program counter
71    FP_REG: frame pointer (%i7 on sparc, %ebp on x86) 
72 */
73 #ifdef sparc_sun_solaris2_4
74 #define RETVAL_REG (R_O0)
75 #define PC_REG (R_PC)
76 #define FP_REG (R_O6)
77 #endif
78 #ifdef i386_unknown_solaris2_5
79 #define RETVAL_REG (EAX)
80 #define PC_REG (EIP)
81 #define FP_REG (EBP)
82 #endif
83
84
85 extern bool isValidAddress(process *proc, Address where);
86
87 /*
88    osTraceMe is called after we fork a child process to set
89    a breakpoint on the exit of the exec system call.
90    When /proc is used, this breakpoint **will not** cause a SIGTRAP to 
91    be sent to the process. The parent should use PIOCWSTOP to wait for 
92    the child.
93 */
94 void OS::osTraceMe(void) {
95   sysset_t exitSet;
96   char procName[128];
97
98   sprintf(procName,"/proc/%05d", (int)getpid());
99   int fd = P_open(procName, O_RDWR, 0);
100   if (fd < 0) {
101     fprintf(stderr, "osTraceMe: open failed: %s\n", sys_errlist[errno]); 
102     fflush(stderr);
103     P__exit(-1); // must use _exit here.
104   }
105
106   /* set a breakpoint at the exit of exec/execve */
107   premptyset(&exitSet);
108   praddset(&exitSet, SYS_exec);
109   praddset(&exitSet, SYS_execve);
110   if (ioctl(fd, PIOCSEXIT, &exitSet) < 0) {
111     fprintf(stderr, "osTraceMe: PIOCSEXIT failed: %s\n", sys_errlist[errno]); 
112     fflush(stderr);
113     P__exit(-1); // must use _exit here.
114   }
115
116   errno = 0;
117   close(fd);
118   return;
119 }
120
121
122 // already setup on this FD.
123 // disconnect from controlling terminal 
124 void OS::osDisconnect(void) {
125   int ttyfd = open ("/dev/tty", O_RDONLY);
126   ioctl (ttyfd, TIOCNOTTY, NULL); 
127   P_close (ttyfd);
128 }
129
130 bool process::continueWithForwardSignal(int) {
131    if (-1 == ioctl(proc_fd, PIOCRUN, NULL)) {
132       perror("could not forward signal in PIOCRUN");
133       return false;
134    }
135
136    return true;
137 }
138
139 bool process::dumpImage() {return false;}
140
141
142 /* 
143    execResult: return the result of an exec system call - true if succesful.
144    The traced processes will stop on exit of an exec system call, just before
145    returning to user code. At this point the return value (errno) is already
146    written to a register, and we need to check if the return value is zero.
147  */
148 static inline bool execResult(prstatus_t stat) {
149   return (stat.pr_reg[RETVAL_REG] == 0);
150 }
151
152 /*
153    wait for inferior processes to terminate or stop.
154 */
155 int process::waitProcs(int *status) {
156    extern vector<process*> processVec;
157
158    static struct pollfd fds[OPEN_MAX];  // argument for poll
159    static int selected_fds;             // number of selected
160    static int curr;                     // the current element of fds
161
162    /* Each call to poll may return many selected fds. Since we only report the status
163       of one process per each call to waitProcs, we keep the result of the last
164       poll buffered, and simply process an element from the buffer until all of
165       the selected fds in the last poll have been processed.
166    */
167
168    if (selected_fds == 0) {
169      for (unsigned u = 0; u < processVec.size(); u++) {
170        if (processVec[u] && (processVec[u]->status() == running || processVec[u]->status() == neonatal))
171          fds[u].fd = processVec[u]->proc_fd;
172        else
173          fds[u].fd = -1;
174        fds[u].events = POLLPRI;
175        fds[u].revents = 0;
176      }
177
178      selected_fds = poll(fds, processVec.size(), 0);
179      if (selected_fds < 0) {
180        fprintf(stderr, "waitProcs: poll failed: %s\n", sys_errlist[errno]);
181        selected_fds = 0;
182        return 0;
183      }
184
185      curr = 0;
186    }
187    
188    if (selected_fds > 0) {
189      while (fds[curr].revents == 0)
190        ++curr;
191
192      // fds[curr] has an event of interest
193      prstatus_t stat;
194      int ret = 0;
195
196      if (ioctl(fds[curr].fd, PIOCSTATUS, &stat) != -1 
197          && (stat.pr_flags & PR_STOPPED || stat.pr_flags & PR_ISTOP)) {
198        switch (stat.pr_why) {
199        case PR_SIGNALLED:
200          // return the signal number
201          *status = stat.pr_what << 8 | 0177;
202          ret = processVec[curr]->getPid();
203          break;
204        case PR_SYSEXIT:
205          // exit of exec
206          if (!execResult(stat)) {
207            // a failed exec. continue the process
208            processVec[curr]->continueProc_();
209            break;
210          }          
211
212          *status = SIGTRAP << 8 | 0177;
213          ret = processVec[curr]->getPid();
214          break;
215        case PR_REQUESTED:
216          assert(0);
217        case PR_JOBCONTROL:
218          assert(0);
219          break;
220        }        
221       }
222
223      --selected_fds;
224      ++curr;
225
226      if (ret > 0) {
227        return ret;
228      }
229    }
230
231    return waitpid(0, status, WNOHANG);
232 }
233
234
235 /*
236    Open the /proc file correspoding to process pid, 
237    set the signals to be caught to be only SIGSTOP and SIGTRAP,
238    and set the kill-on-last-close and inherit-on-fork flags.
239 */
240 bool process::attach() {
241   char procName[128];
242
243   // QUESTION: does this attach operation lead to a SIGTRAP being forwarded
244   // to paradynd in all cases?  How about when we are attaching to an
245   // already-running process?  (Seems that in the latter case, no SIGTRAP
246   // is automatically generated)
247
248   // step 1) /proc open: attach to the inferior process
249   sprintf(procName,"/proc/%05d", (int)pid);
250   int fd = P_open(procName, O_RDWR, 0);
251   if (fd < 0) {
252     fprintf(stderr, "attach: open failed: %s\n", sys_errlist[errno]);
253     return false;
254   }
255
256   // step 2) /proc PIOCSTRACE: define which signals should be forwarded to daemon
257   //   These are (1) SIGSTOP and (2) either SIGTRAP (sparc) or SIGILL (x86), to
258   //   implement inferiorRPC completion detection.
259   sigset_t sigs;
260   premptyset(&sigs);
261   praddset(&sigs, SIGSTOP);
262
263 #ifndef i386_unknown_solaris2_5
264   praddset(&sigs, SIGTRAP);
265 #endif
266
267 #ifdef i386_unknown_solaris2_5
268   praddset(&sigs, SIGILL);
269 #endif
270
271   if (ioctl(fd, PIOCSTRACE, &sigs) < 0) {
272     fprintf(stderr, "attach: ioctl failed: %s\n", sys_errlist[errno]);
273     close(fd);
274     return false;
275   }
276
277   // Step 3) /proc PIOCSET:
278   // a) turn on the kill-on-last-close flag (kills inferior with SIGKILL when
279   //    the last writable /proc fd closes)
280   // b) turn on inherit-on-fork flag (tracing flags inherited when child forks).
281   // c) turn on breakpoint trap pc adjustment (x86 only).
282   // Also, any child of this process will stop at the exit of an exec call.
283   long flags = PR_KLC | PR_FORK | PR_BPTADJ;
284   if (ioctl (fd, PIOCSET, &flags) < 0) {
285     fprintf(stderr, "attach: PIOCSET failed: %s\n", sys_errlist[errno]);
286     close(fd);
287     return false;
288   }
289
290   proc_fd = fd;
291   return true;
292 }
293
294 bool process::attach_() {assert(false);}
295 bool process::stop_() {assert(false);}
296
297 /* 
298    continue a process that is stopped 
299 */
300 bool process::continueProc_() {
301   ptraceOps++; ptraceOtherOps++;
302   prrun_t flags;
303   prstatus_t stat;
304
305 //cerr << "welcome to continueProc_()" << endl;
306
307   // a process that receives a stop signal stops twice. We need to run the process
308   // and wait for the second stop. (The first run simply absorbs the stop signal;
309   // the second one does the actual continue.)
310   if ((ioctl(proc_fd, PIOCSTATUS, &stat) != -1)
311       && (stat.pr_flags & PR_STOPPED)
312       && (stat.pr_why == PR_SIGNALLED)
313       && ((stat.pr_what == SIGSTOP) || (stat.pr_what == SIGINT))) {
314     flags.pr_flags = PRSTOP;
315     if (ioctl(proc_fd, PIOCRUN, &flags) == -1) {
316       fprintf(stderr, "continueProc_: PIOCRUN failed: %s\n", sys_errlist[errno]);
317       return false;
318     }
319     if (ioctl(proc_fd, PIOCWSTOP, 0) == -1) {
320       fprintf(stderr, "continueProc_: PIOCWSTOP failed: %s\n", sys_errlist[errno]);
321       return false;
322     }
323   }
324   flags.pr_flags = PRCSIG; // clear current signal
325   if (hasNewPC) {
326     // set new program counter
327     //cerr << "continueProc_ doing new currentPC: " << (void*)currentPC_ << endl;
328     flags.pr_vaddr = (caddr_t) currentPC_;
329     flags.pr_flags |= PRSVADDR;
330     hasNewPC = false;
331   }
332   if (ioctl(proc_fd, PIOCRUN, &flags) == -1) {
333     fprintf(stderr, "continueProc_: PIOCRUN 2 failed: %s\n", sys_errlist[errno]);
334     return false;
335   }
336   return true;
337 }
338
339 /*
340    pause a process that is running
341 */
342 bool process::pause_() {
343   ptraceOps++; ptraceOtherOps++;
344
345   // /proc PIOCSTOP: direct all LWPs to stop, _and_ wait for them to stop.
346   return (ioctl(proc_fd, PIOCSTOP, 0) != -1);
347 }
348
349 /*
350    close the file descriptor for the file associated with a process
351 */
352 bool process::detach_() {
353   close(proc_fd);
354   return true;
355 }
356
357 bool process::dumpCore_(const string) {
358   return false;
359 }
360
361 bool process::writeTextWord_(caddr_t inTraced, int data) {
362 //  cerr << "writeTextWord @ " << (void *)inTraced << endl; cerr.flush();
363   return writeDataSpace_(inTraced, sizeof(int), (caddr_t) &data);
364 }
365
366 bool process::writeTextSpace_(void *inTraced, int amount, const void *inSelf) {
367 //  cerr << "writeTextSpace pid=" << getPid() << ", @ " << (void *)inTraced << " len=" << amount << endl; cerr.flush();
368   return writeDataSpace_(inTraced, amount, inSelf);
369 }
370
371 bool process::writeDataSpace_(void *inTraced, int amount, const void *inSelf) {
372   ptraceOps++; ptraceBytes += amount;
373
374 //  cerr << "process::writeDataSpace_ pid " << getPid() << " writing " << amount << " bytes at loc " << inTraced << endl;
375
376   if (lseek(proc_fd, (off_t)inTraced, SEEK_SET) != (off_t)inTraced)
377     return false;
378   return (write(proc_fd, inSelf, amount) == amount);
379 }
380
381 bool process::readDataSpace_(const void *inTraced, int amount, void *inSelf) {
382   ptraceOps++; ptraceBytes += amount;
383   if((lseek(proc_fd, (off_t)inTraced, SEEK_SET)) != (off_t)inTraced) {
384     printf("error in lseek addr = 0x%x amount = %d\n",(u_int)inTraced,amount);
385     return false;
386   }
387   return (read(proc_fd, inSelf, amount) == amount);
388 }
389
390 bool process::loopUntilStopped() {
391   assert(0);
392 }
393
394 #ifdef notdef
395 // TODO -- only call getrusage once per round
396 static struct rusage *get_usage_data() {
397   return NULL;
398 }
399 #endif
400
401 float OS::compute_rusage_cpu() {
402   return 0;
403 }
404
405 float OS::compute_rusage_sys() {
406   return 0;
407 }
408
409 float OS::compute_rusage_min() {
410   return 0;
411 }
412 float OS::compute_rusage_maj() {
413   return 0;
414 }
415
416 float OS::compute_rusage_swap() {
417   return 0;
418 }
419 float OS::compute_rusage_io_in() {
420   return 0;
421 }
422 float OS::compute_rusage_io_out() {
423   return 0;
424 }
425 float OS::compute_rusage_msg_send() {
426   return 0;
427 }
428 float OS::compute_rusage_msg_recv() {
429   return 0;
430 }
431 float OS::compute_rusage_sigs() {
432   return 0;
433 }
434 float OS::compute_rusage_vol_cs() {
435   return 0;
436 }
437 float OS::compute_rusage_inv_cs() {
438   return 0;
439 }
440
441 int getNumberOfCPUs()
442 {
443   // _SC_NPROCESSORS_CONF is the number of processors configured in the
444   // system and _SC_NPROCESSORS_ONLN is the number of those processors that
445   // are online.
446   int numberOfCPUs;
447   numberOfCPUs = (int) sysconf(_SC_NPROCESSORS_ONLN);
448   if (numberOfCPUs) 
449     return(numberOfCPUs);
450   else 
451     return(1);
452 }  
453
454
455 bool process::getActiveFrame(int *fp, int *pc)
456 {
457   prgregset_t regs;
458   bool ok=false;
459
460   if (ioctl (proc_fd, PIOCGREG, &regs) != -1) {
461       *fp=regs[FP_REG];
462       *pc=regs[PC_REG];
463       ok=true;
464   }
465   return(ok);
466 }
467
468 #ifdef sparc_sun_solaris2_4
469
470 bool process::readDataFromFrame(int currentFP, int *fp, int *rtn, bool uppermost)
471 {
472   bool readOK=true;
473   struct {
474     int fp;
475     int rtn;
476   } addrs;
477
478   prgregset_t regs;
479   pdFunction *func;
480   int pc = *rtn;
481
482   if (uppermost) {
483       func = this->findFunctionIn(pc);
484       if (func) {
485           if (func ->isLeafFunc()) {
486               if (ioctl (proc_fd, PIOCGREG, &regs) != -1) {
487                   *rtn = regs[R_O7] + 8;
488                   return readOK;
489               }    
490           }
491       }
492   }
493
494   //
495   // For the sparc, register %i7 is the return address - 8 and the fp is
496   // register %i6. These registers can be located in currentFP+14*5 and
497   // currentFP+14*4 respectively, but to avoid two calls to readDataSpace,
498   // we bring both together (i.e. 8 bytes of memory starting at currentFP+14*4
499   // or currentFP+56).
500   // These values are copied to the stack when the application is paused,
501   // so we are assuming that the application is paused at this point
502
503   if (readDataSpace((caddr_t) (currentFP + 56),
504                     sizeof(int)*2, (caddr_t) &addrs, true)) {
505     // this is the previous frame pointer
506     *fp = addrs.fp;
507     // return address
508     *rtn = addrs.rtn + 8;
509
510     // if pc==0, then we are in the outermost frame and we should stop. We
511     // do this by making fp=0.
512
513     if ( (addrs.rtn == 0) || !isValidAddress(this,(Address) addrs.rtn) ) {
514       readOK=false;
515     }
516   }
517   else {
518     readOK=false;
519   }
520
521
522   return(readOK);
523 }
524
525 #endif
526
527 #ifdef SHM_SAMPLING
528 unsigned long long process::getInferiorProcessCPUtime() const {
529    // returns user+sys time from the u or proc area of the inferior process, which in
530    // turn is presumably obtained by mmapping it (sunos) or by using a /proc ioctl
531    // to obtain it (solaris).  It must not stop the inferior process in order
532    // to obtain the result, nor can it assue that the inferior has been stopped.
533    // The result MUST be "in sync" with rtinst's DYNINSTgetCPUtime().
534
535    // We use the PIOCUSAGE /proc ioctl
536
537    // Other /proc ioctls that should work too: PIOCPSINFO
538    // and the lower-level PIOCGETPR and PIOCGETU which return copies of the proc
539    // and u areas, respectively.
540    // PIOCSTATUS does _not_ work because its results are not in sync
541    // with DYNINSTgetCPUtime
542
543    prusage_t theUsage;
544    if (ioctl(proc_fd, PIOCUSAGE, &theUsage) == -1) {
545       perror("could not read CPU time of inferior PIOCUSAGE");
546       return 0;
547    }
548
549    timestruc_t &utime = theUsage.pr_utime;
550    timestruc_t &stime = theUsage.pr_stime;
551
552    // Note: we can speed up the multiplication and division; see RTsolaris.c in rtinst
553
554    unsigned long long result = utime.tv_sec + stime.tv_sec;
555    result *= 1000000; // sec to usec
556    result += utime.tv_nsec/1000 + stime.tv_nsec/1000;
557
558    return result;
559 }
560 #endif
561
562 void *process::getRegisters(bool &) {
563    // Astonishingly, this routine can be shared between solaris/sparc and
564    // solaris/x86.  All hail /proc!!!
565
566    // assumes the process is stopped (/proc requires it)
567    assert(status_ == stopped);
568
569    prgregset_t theIntRegs;
570    if (ioctl(proc_fd, PIOCGREG, &theIntRegs) == -1) {
571       perror("process::getRegisters PIOCGREG");
572       if (errno == EBUSY) {
573          cerr << "It appears that the process was not stopped in the eyes of /proc" << endl;
574          assert(false);
575       }
576
577       return NULL;
578    }
579
580    prfpregset_t theFpRegs;
581    if (ioctl(proc_fd, PIOCGFPREG, &theFpRegs) == -1) {
582       perror("process::getRegisters PIOCGFPREG");
583       if (errno == EBUSY)
584          cerr << "It appears that the process was not stopped in the eyes of /proc" << endl;
585       else if (errno == EINVAL)
586          // what to do in this case?  Probably shouldn't even do a print, right?
587          // And it certainly shouldn't be an error, right?
588          // But I wonder if any sparcs out there really don't have floating point.
589          cerr << "It appears that this machine doesn't have floating-point instructions" << endl;
590
591       return NULL;
592    }
593
594    const int numbytesPart1 = sizeof(prgregset_t);
595    const int numbytesPart2 = sizeof(prfpregset_t);
596    assert(numbytesPart1 % 4 == 0);
597    assert(numbytesPart2 % 4 == 0);
598
599    void *buffer = new char[numbytesPart1 + numbytesPart2];
600    assert(buffer);
601
602    memcpy(buffer, &theIntRegs, sizeof(theIntRegs));
603    memcpy((char *)buffer + sizeof(theIntRegs), &theFpRegs, sizeof(theFpRegs));
604
605    return buffer;
606 }
607
608 bool process::changePC(unsigned addr, void *savedRegs) {
609    assert(status_ == stopped);
610
611    prgregset_t theIntRegs = *(prgregset_t *)savedRegs; // makes a copy, on purpose
612
613    theIntRegs[R_PC] = addr; // EIP register
614 #ifdef R_nPC  // true for sparc, not for x86
615    theIntRegs[R_nPC] = addr + 4;
616 #endif
617
618    if (ioctl(proc_fd, PIOCSREG, &theIntRegs) == -1) {
619       perror("process::changePC PIOCSREG failed");
620       if (errno == EBUSY)
621          cerr << "It appears that the process wasn't stopped in the eyes of /proc" << endl;
622       return false;
623    }
624
625    return true;
626 }
627
628 bool process::restoreRegisters(void *buffer) {
629    // The fact that this routine can be shared between solaris/sparc and
630    // solaris/x86 is just really, really cool.  /proc rules!
631
632    assert(status_ == stopped); // /proc requires it
633
634    prgregset_t theIntRegs = *(prgregset_t *)buffer;
635    prfpregset_t theFpRegs = *(prfpregset_t *)((char *)buffer + sizeof(theIntRegs));
636
637    if (ioctl(proc_fd, PIOCSREG, &theIntRegs) == -1) {
638       perror("process::restoreRegisters PIOCSREG failed");
639       if (errno == EBUSY) {
640          cerr << "It appears that the process was not stopped in the eyes of /proc" << endl;
641          assert(false);
642       }
643       return false;
644    }
645
646    if (ioctl(proc_fd, PIOCSFPREG, &theFpRegs) == -1) {
647       perror("process::restoreRegisters PIOCSFPREG failed");
648       if (errno == EBUSY) {
649          cerr << "It appears that the process was not stopped in the eyes of /proc" << endl;
650          assert(false);
651       }
652       return false;
653    }
654
655    return true;
656 }
657
658 #ifdef i386_unknown_solaris2_5
659
660 bool process::readDataFromFrame(int currentFP, int *fp, int *rtn, bool )
661 {
662   bool readOK=true;
663   struct {
664     int fp;
665     int rtn;
666   } addrs;
667
668   //
669   // for the x86, the frame-pointer (EBP) points to the previous frame-pointer,
670   // and the saved return address is in EBP-4.
671   //
672
673   if (readDataSpace((caddr_t) (currentFP),
674                     sizeof(int)*2, (caddr_t) &addrs, true)) {
675     // this is the previous frame pointer
676     *fp = addrs.fp;
677     // return address
678     *rtn = addrs.rtn;
679
680     // if pc==0, then we are in the outermost frame and we should stop. We
681     // do this by making fp=0.
682
683     if ( (addrs.rtn == 0) || !isValidAddress(this,(Address) addrs.rtn) ) {
684       readOK=false;
685     }
686   }
687   else {
688     readOK=false;
689   }
690
691   return(readOK);
692 }
693
694 #endif
695
696
697 // needToAddALeafFrame: returns true if the between the current frame 
698 // and the next frame there is a leaf function (this occurs when the 
699 // current frame is the signal handler and the function that was executing
700 // when the sighandler was called is a leaf function)
701 bool process::needToAddALeafFrame(Frame current_frame, Address &leaf_pc){
702
703    // check to see if the current frame is the signal handler 
704    Address frame_pc = current_frame.getPC();
705    Address sig_addr = 0;
706    const image *sig_image = (signal_handler->file())->exec();
707    if(getBaseAddress(sig_image, sig_addr)){
708        sig_addr += signal_handler->getAddress(0);
709    } else {
710        sig_addr = signal_handler->getAddress(0);
711    }
712    u_int sig_size = signal_handler->size();
713    if(signal_handler&&(frame_pc >= sig_addr)&&(frame_pc < (sig_addr+sig_size))){
714        // get the value of the saved PC: this value is stored in the address
715        // specified by the value in register i2 + 44. Register i2 must contain
716        // the address of some struct that contains, among other things, the 
717        // saved PC value.  
718        u_int reg_i2;
719        int fp = current_frame.getFramePtr();
720        if (readDataSpace((caddr_t)(fp+40),sizeof(u_int),(caddr_t)&reg_i2,true)){
721           if (readDataSpace((caddr_t) (reg_i2+44), sizeof(int),
722                             (caddr_t) &leaf_pc,true)){
723               // if the function is a leaf function return true
724               pdFunction *func = findFunctionIn(leaf_pc);
725               if(func && func->isLeafFunc()) {
726                   return(true);
727               }
728           }
729       }
730    }
731    return false;
732 }
733