Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / stackwalk-x86.C
1 /*
2  * Copyright (c) 1996-2009 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  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "dyninstAPI/src/process.h"
33 #include "dyninstAPI/src/frame.h"
34 #include "dyninstAPI/src/baseTramp.h"
35 #include "dyninstAPI/src/multiTramp.h"
36 #include "dyninstAPI/src/miniTramp.h"
37 #include "dyninstAPI/src/dyn_thread.h"
38 #include "dyninstAPI/src/function.h"
39 #include "dyninstAPI/src/mapped_object.h"
40
41 #if defined(cap_instruction_api)
42 #include "dyninstAPI/src/frameChecker.h"
43 #else
44 #include "dyninstAPI/src/InstrucIter.h"
45 #endif // defined(cap_instruction_api)
46 #include <ctype.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include "common/h/headers.h"
50
51 #if defined(os_windows)
52 #define caddr_t unsigned* //Fixes very odd windows compilation issue
53 #endif
54
55 //Possible return values for getFrameStatus
56 typedef enum frameStatus_t {
57     frame_unknown,               //Don't know
58     frame_sighandler,            //Current function is a signal handler
59     frame_allocates_frame,       //Function allocates a frame
60     frame_saves_fp_noframe,      //Function doesn't allocate a frame but does
61                                  // save the FP (result of gcc's 
62                                  // -fomit-frame-pointer)
63     frame_no_use_fp,             //Function doesn't allocate a frame and doesn't
64                                  // use the frame pointer (also result of gcc's
65                                  // -fomit-frame-pointer) 
66     frame_tramp,                 //Trampoline with stack frame
67     frameless_tramp,             //Trampoline without a stack frame
68     frame_vsyscall               //PC is in the vsyscall page (linux only)
69 } frameStatus_t;
70
71 // constants for walking out of a signal handler
72 // these are offsets from the stack pointer in the signal
73 // tramp (__restore or __restore_rt) into the sigcontext
74 // struct that is placed on the sigtramp's frame
75 // TODO: obtain these from the appropriate header files
76
77 #define SIG_HANDLER_FP_OFFSET_32 28
78 #define SIG_HANDLER_PC_OFFSET_32 60
79 #define SIG_HANDLER_FRAME_SIZE_32 64
80 #define SIG_HANDLER_FP_OFFSET_64 120
81 #define SIG_HANDLER_PC_OFFSET_64 168
82 #define SIG_HANDLER_FRAME_SIZE_64 576
83
84 static frameStatus_t getFrameStatus(process *p, unsigned long pc, int &extra_height)
85 {
86    codeRange *range;
87
88    int_function *func = NULL;
89    miniTrampInstance *mini = NULL;
90    multiTramp *multi = NULL;
91    baseTrampInstance *base = NULL;
92    extra_height = 0;
93
94    mapped_object *mobj = p->findObject(pc);
95    if (mobj) {
96      bool result = mobj->analyze();
97      assert(result);
98    }
99
100    if (p->isInSignalHandler(pc))
101       return frame_sighandler;
102 #if defined(os_linux)
103    calcVSyscallFrame(p);
104    if ((pc >= p->getVsyscallStart() && pc < p->getVsyscallEnd()) || /* RH9 Hack */ (pc >= 0xffffe000 && pc < 0xfffff000))
105       return frame_vsyscall;
106 #endif
107
108    range = p->findOrigByAddr(pc);
109    func = range->is_function();
110    multi = range->is_multitramp();
111    mini = range->is_minitramp();
112    if (multi)
113        base = multi->getBaseTrampInstanceByAddr(pc);
114
115    if (base) {
116       if (base->isInInstru(pc)) {
117          extra_height = base->trampStackHeight();
118          if (base->baseT->createFrame())
119             return frame_tramp;
120          else
121             return frameless_tramp;
122       }
123       else
124          func = base->multiT->func();
125    }
126    else if (multi) {
127        // Not in base tramp instrumented... we're effectively in the func
128        func = multi->func();
129    }
130    else if (mini) {
131        return frame_tramp;
132    }
133    
134    if (func == NULL) {
135       return frame_unknown;
136    }
137    else if (!func->hasNoStackFrame()) 
138       return frame_allocates_frame;   
139    else if (func->savesFramePointer())
140      return frame_saves_fp_noframe;
141    else
142      return frame_no_use_fp;
143 }
144
145 static bool isPrevInstrACall(Address addr, process *p, int_function **callee)
146 {
147    codeRange *range = p->findOrigByAddr(addr);
148    pdvector<instPoint *> callsites;
149
150    if (range == NULL)
151      return false;
152    
153    int_function *func_ptr = range->is_function();
154
155    if (func_ptr != NULL)
156      callsites = func_ptr->funcCalls();
157    else
158      return false;
159       
160    for (unsigned i = 0; i < callsites.size(); i++)
161    {
162      instPoint *site = callsites[i];
163
164      // Argh. We need to check for each call site in each
165      // instantiation of the function.
166 #if defined(cap_instruction_api)     
167      if (site->match(addr - site->insn()->size())) {
168 #else
169      if (site->match(addr - site->insn().size())) {
170 #endif         
171     *callee = site->findCallee();
172         return true;
173      }
174    }   
175    
176    return false; 
177 }
178
179
180
181 /**
182  * Sometimes a function that uses a stack frame may not yet have put up its
183  * frame or have already taken it down by the time we reach it during a stack
184  * walk.  This function returns true in this case.  offset is the distance
185  * from the top of the stack to the return value for the caller.
186  **/
187 static bool hasAllocatedFrame(Address addr, process *proc, int &offset)
188 {
189     codeRange *range = proc->findOrigByAddr(addr);
190
191     if (range &&
192         range->is_basicBlockInstance()) {
193 #if !defined(cap_instruction_api)
194         int frameSizeDontCare;
195         InstrucIter ii(range->get_address(),
196                        range->get_size(),
197                        proc);
198         ii.setCurrentAddress(addr);
199         if (ii.isAReturnInstruction() ||
200             ii.isStackFramePreamble(frameSizeDontCare))
201             {
202                 offset = 0;
203                 return false;
204             }
205         if (ii.isFrameSetup())
206             {
207                 offset = proc->getAddressWidth();
208                 return false;
209             }
210     }
211     
212 #else
213       frameChecker fc((const unsigned char*)(proc->getPtrToInstruction(addr)), range->get_size() - (addr - range->get_address()));
214       if(fc.isReturn() || fc.isStackPreamble())
215       {
216         offset = 0;
217         return false;
218       }
219       if(fc.isStackFrameSetup())
220       {
221         offset = proc->getAddressWidth();
222         return false;
223       }
224     }
225 #endif
226     return true;       
227 }
228
229 /**
230  * If frame 'f' is a trampoline frame, this function returns true
231  * if the trampoline was called by function entry or exit
232  * instrumentation.
233  **/
234 static bool isInEntryExitInstrumentation(Frame f)
235 {
236    codeRange *range = f.getRange();
237    miniTrampInstance *miniTI = range->is_minitramp();
238    multiTramp *multi = range->is_multitramp();
239    baseTrampInstance *baseTI = NULL;
240    if (multi) baseTI = multi->getBaseTrampInstanceByAddr(f.getPC());
241
242    if (baseTI == NULL)
243    {
244       if (miniTI == NULL)
245          return false;
246       baseTI = miniTI->baseTI;
247    }
248    const instPoint *instP = baseTI->baseT->instP();
249    if (!instP) return false; // Could be iRPC
250
251    if (instP->getPointType() == functionEntry ||
252        instP->getPointType() == functionExit)
253        // Not sure yet if function exit will be preInst or postInst...
254        return true;
255
256    return false;
257 }
258
259 class DyninstMemRegReader : public Dyninst::SymtabAPI::MemRegReader
260 {
261  private:
262    process *proc;
263    Frame *orig_frame;
264  public:
265    DyninstMemRegReader(process *p, Frame *f) { 
266       proc = p; 
267       orig_frame = f;
268    }
269    virtual bool ReadMem(Address addr, void *buffer, unsigned size) {
270       return proc->readDataSpace((void *) addr, size, buffer, false);
271    }
272
273    virtual bool GetReg(MachRegister reg, MachRegisterVal &val) {
274       if (proc->getAddressWidth() == 4) {
275          switch (reg) {
276             case MachRegPC:
277             case MachRegReturn:
278                val = orig_frame->getPC();
279                break;
280             case x86::ESP:
281             case MachRegStackBase:
282                val = orig_frame->getSP();
283                break;
284             case x86::EBP:
285             case MachRegFrameBase:
286                val = orig_frame->getFP();
287                break;
288             default:
289                assert(0);
290          }
291       }
292       else {
293          switch (reg) {
294             case MachRegPC:
295             case MachRegReturn:
296                val = orig_frame->getPC();
297                break;
298             case x86_64::RSP:
299             case MachRegStackBase:
300                val = orig_frame->getSP();
301                break;
302             case x86_64::RBP:
303             case MachRegFrameBase:
304                val = orig_frame->getFP();
305                break;
306             default:
307                assert(0);
308          }
309       }
310       return true;
311    }
312
313    virtual ~DyninstMemRegReader() {};
314 };
315
316 extern int tramp_pre_frame_size_32;
317 extern int tramp_pre_frame_size_64;
318
319 //The estimated maximum frame size when having to do an 
320 // exhaustive search for a frame.
321 #define MAX_STACK_FRAME_SIZE 8192
322
323 // x86_64 uses a different stack address than standard x86.
324 #define MAX_STACK_FRAME_ADDR_64 0x0000007fbfffffff
325 #define MAX_STACK_FRAME_ADDR_32 0xbfffffff
326
327 Frame Frame::getCallerFrame()
328 {
329     int_function *cur_func = getProc()->findFuncByAddr(pc_);
330     int addr_size = getProc()->getAddressWidth();
331     int extra_height = 0;
332 #if defined(os_linux)
333     // assume _start is never called, so just return if we're there
334     if (cur_func &&
335        cur_func->getAddress() == getProc()->getAOut()->parse_img()->getObject()->getEntryOffset()) {
336       stackwalk_printf("%s[%d]: stack walk at entry of a.out (_start), returning null frame\n", FILE__, __LINE__);
337        return Frame();
338     }
339 #endif
340    /**
341     * These two variables are only valid when this function is
342     * called recursively.
343     **/
344    static Frame prevFrame;
345    static bool prevFrameValid = false;
346
347    /**
348     * for the x86, the frame-pointer (EBP) points to the previous 
349     * frame-pointer, and the saved return address is in EBP-4.
350     **/
351    struct {
352       Address fp;
353       Address rtn;
354    } addrs;
355
356    frameStatus_t status;
357
358    Address newPC=0;
359    Address newFP=0;
360    Address newSP=0;
361    Address newpcAddr=0;
362    Address pcLoc=0;
363    addrs.fp = 0;
364    addrs.rtn = 0;
365
366    status = getFrameStatus(getProc(), getPC(), extra_height);
367
368    if (status == frame_vsyscall)
369    {
370 #if defined(os_linux)
371       Symtab *vsys_obj;
372
373       if ((vsys_obj = getProc()->getVsyscallObject()) == NULL ||
374           !vsys_obj->hasStackwalkDebugInfo())
375       {
376         /**
377          * No vsyscall stack walking data present (we're probably 
378          * on Linux 2.4) we'll go ahead and treat the vsyscall page 
379          * as a leaf
380          **/
381          stackwalk_printf("%s[%d]: no vsyscall data present, treating as leaf frame\n", FILE__, __LINE__);
382          if (!getProc()->readDataSpace((void *) sp_, addr_size, 
383                                        (void *) &addrs.rtn, true)) {
384             stackwalk_printf("%s[%d]: Failed to access memory at 0x%x, returning null frame \n", FILE__, __LINE__, sp_);
385             return Frame();
386          }
387          
388          newFP = fp_;
389          newPC = addrs.rtn;
390          newSP = sp_+addr_size;
391          goto done;
392       }
393       else
394       {
395          /**
396           * We have vsyscall stack walking data, which came from
397           * the .eh_frame section of the vsyscall DSO.  We'll use
398           * getRegValueAtFrame to parse the data and get the correct
399           * values for %esp, %ebp, and %eip
400           **/
401          Address vsys_base = 0x0;
402          DyninstMemRegReader reader(getProc(), this);
403          stackwalk_printf("%s[%d]: vsyscall data is present, analyzing\n", 
404                           FILE__, __LINE__);
405          bool result;
406          result = vsys_obj->getRegValueAtFrame(pc_, MachRegReturn,
407                                                newPC, &reader);
408          if (!result) {
409             //Linux in inconsistent about whether we should subtract the
410             // vys_start before using.  So we try both, stick with what works
411             vsys_base = getProc()->getVsyscallStart();
412             result = vsys_obj->getRegValueAtFrame(pc_ - vsys_base, MachRegReturn,
413                                                   newPC, &reader);
414          }
415          if (!result) {
416             //It gets worse, sometimes the vsyscall data is just plain wrong.
417             //FC-9 randomized the location of the vsyscall page, but didn't update
418             //the debug info.  We'll try the non-updated address.
419             vsys_base = getProc()->getVsyscallStart() - 0xffffe000;
420             result = vsys_obj->getRegValueAtFrame(pc_ - vsys_base, MachRegReturn,
421                                                   newPC, &reader);
422          }
423          if (!result) {
424             stackwalk_printf("[%s:%u] - Error getting PC value of vsyscall\n",
425                              __FILE__, __LINE__);
426             return Frame();                             
427          }         
428          Dyninst::MachRegister frame_reg;
429          if (getProc()->getAddressWidth() == 4)
430             frame_reg = x86::EBP;
431          else
432             frame_reg = x86_64::RBP;
433
434          result = vsys_obj->getRegValueAtFrame(pc_ - vsys_base, frame_reg,
435                                                newFP, &reader);
436          if (!result) {
437             stackwalk_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
438                               __FILE__, __LINE__, pc_);
439             return Frame();
440          }
441          
442          result = vsys_obj->getRegValueAtFrame(pc_ - vsys_base, MachRegFrameBase,
443                                                newSP, &reader);
444          if (!result) {
445             stackwalk_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
446                       __FILE__, __LINE__, pc_);
447             return Frame();
448          }
449          goto done;
450       }
451 #endif
452    }
453    else if (status == frame_sighandler)
454    {
455      stackwalk_printf("%s[%d]: parsing signal handler...\n", FILE__, __LINE__);
456       int fp_offset, pc_offset, frame_size;
457       if (addr_size == 4) {
458          fp_offset = SIG_HANDLER_FP_OFFSET_32;
459          pc_offset = SIG_HANDLER_PC_OFFSET_32;
460          frame_size = SIG_HANDLER_FRAME_SIZE_32;
461       }
462       else {
463          fp_offset = SIG_HANDLER_FP_OFFSET_64;
464          pc_offset = SIG_HANDLER_PC_OFFSET_64;
465          frame_size = SIG_HANDLER_FRAME_SIZE_64;
466       }
467       
468       if (!getProc()->readDataSpace((caddr_t)(sp_+fp_offset), addr_size,
469                                     &addrs.fp, true)) {
470         stackwalk_printf("%s[%d]: Failed to read memory at sp_+fp_offset 0x%lx\n", FILE__, __LINE__,sp_+fp_offset);
471          return Frame();
472       }
473       if (!getProc()->readDataSpace((caddr_t)(sp_+pc_offset), addr_size,
474                                     &addrs.rtn, true)) {
475         stackwalk_printf("%s[%d]: Failed to read memory at sp_+pc_offset 0x%lx\n", FILE__, __LINE__,sp_+pc_offset);
476          return Frame();
477       }
478       
479       
480       /**
481        * If the current frame is for the signal handler function, then we need 
482        * to read the information about the next frame from the data saved by 
483        * the signal handling mechanism.
484        **/
485       newFP = addrs.fp;
486       newPC = addrs.rtn;
487       newSP = sp_ + frame_size;
488       pcLoc = sp_ + pc_offset;
489       goto done;
490    }   
491    else if (status == frame_allocates_frame || status == frame_tramp)
492    {
493      stackwalk_printf("%s[%d]: walking with allocated frame\n", FILE__, __LINE__);      
494      /**
495       * The function that created this frame uses the standard 
496       * prolog: push %ebp; mov %esp->ebp .  We can read the 
497       * appropriate data from the frame pointer.
498       **/
499      int offset = 0;
500      // FIXME: for tramps, we need to check if we've saved the FP yet
501      if ((status != frame_tramp && 
502           !hasAllocatedFrame(pc_, getProc(), offset)) || 
503          (prevFrameValid && isInEntryExitInstrumentation(prevFrame)))
504      {
505         addrs.fp = offset + sp_;
506         if (!getProc()->readDataSpace((caddr_t) addrs.fp, addr_size, 
507                                       &addrs.rtn, true)) {
508            stackwalk_printf("%s[%d]: Failed to read memory at addrs.fp 0x%lx\n", 
509                             FILE__, __LINE__, addrs.fp);
510            return Frame();
511         }
512         newPC = addrs.rtn;
513         newFP = fp_;
514         newSP = addrs.fp + getProc()->getAddressWidth();
515         pcLoc = addrs.fp;
516      }
517      else
518      {
519         if (!fp_) {
520            stackwalk_printf("%s[%d]: No frame pointer!\n", FILE__, __LINE__);     
521            return Frame();
522         }
523         if (!getProc()->readDataSpace((caddr_t) fp_, addr_size, 
524                                       &addrs.fp, false)) {
525            stackwalk_printf("%s[%d]: Failed to read memory at fp_ 0x%lx\n", 
526                             FILE__, __LINE__, fp_);        
527            return Frame();
528         }
529         if (!getProc()->readDataSpace((caddr_t) (fp_ + addr_size), addr_size, 
530                                       &addrs.rtn, false)) {
531            stackwalk_printf("%s[%d]: Failed to read memory at pc (fp_+addr_size) 0x%lx\n",
532                             FILE__, __LINE__, fp_+addr_size);
533            return Frame();
534         }
535         newFP = addrs.fp;
536         newPC = addrs.rtn;
537         newSP = fp_+ (2 * addr_size);
538         pcLoc = fp_ + addr_size;
539      }
540      if (status == frame_tramp)
541         newSP += extra_height;
542      goto done;
543    }
544    else if (status == frameless_tramp)
545    {
546       codeRange *range = getProc()->findOrigByAddr(pc_);
547       multiTramp *mtramp = range->is_multitramp();
548       assert(mtramp);
549       baseTrampInstance *tramp = mtramp->getBaseTrampInstanceByAddr(pc_);
550       assert(tramp);
551
552       newPC = tramp->baseT->origInstAddr();
553       newFP = fp_;
554       newSP = sp_; //Not really correct, but difficult to compute and unlikely to matter
555       pcLoc = 0x0;
556    }
557    else if (status ==  frame_saves_fp_noframe || status == frame_no_use_fp ||
558             status == frame_unknown)
559    {
560       /**
561        * The evil case.  We don't have a valid frame pointer.  We'll
562        * start a search up the stack from the sp, looking for an address
563        * that could qualify as the result of a return.  We'll do a few
564        * things to try and keep ourselves from accidently following a 
565        * constant value that looks like a return:
566        *  - Make sure the address in the return follows call instruction.
567        *  - See if the resulting frame pointer is part of the stack.
568        *  - Peek ahead.  If the stack trace from following the address doesn't
569        *     end with the top of the stack, we probably shouldn't follow it.
570        **/
571
572      stackwalk_printf("%s[%d]: Going into heuristic stack walker...\n", FILE__, __LINE__);
573
574       Address estimated_sp;
575       Address estimated_ip;
576       Address estimated_fp;
577       Address stack_top;
578       int_function *callee = NULL;
579       bool result;
580
581       /**
582        * Calculate the top of the stack.
583        **/
584       Address max_stack_frame_addr =
585 #if defined(arch_x86_64)          
586       addr_size == 8 ? MAX_STACK_FRAME_ADDR_64 : MAX_STACK_FRAME_ADDR_32;
587 #else
588           MAX_STACK_FRAME_ADDR_32;
589 #endif
590
591       stack_top = 0;
592       if (sp_ < max_stack_frame_addr && sp_ > max_stack_frame_addr - 0x200000)
593       {
594           //If we're within two megs of the linux x86 default stack, we'll
595               // assume that's the one in use.
596           // Points to first possible integer
597           stack_top = max_stack_frame_addr - (addr_size - 1);
598       }
599       else if (getProc()->multithread_capable() && 
600                thread_ != NULL &&
601                thread_->get_stack_addr() != 0)
602       {
603          int stack_diff = thread_->get_stack_addr() - sp_;
604          if (stack_diff < MAX_STACK_FRAME_SIZE && stack_diff > 0)
605             stack_top = thread_->get_stack_addr();
606       }
607       if (stack_top == 0)
608          stack_top = sp_ + MAX_STACK_FRAME_SIZE;
609       assert(sp_ < stack_top);
610
611       /**
612        * Search for the correct return value.
613        **/
614       estimated_sp = sp_;
615       for (; estimated_sp <= stack_top; estimated_sp++)
616       {
617          estimated_ip = 0;
618          result = getProc()->readDataSpace((caddr_t) estimated_sp, addr_size, 
619                                            &estimated_ip, false);
620          
621          if (!result) break;
622
623          //If the instruction that preceeds this address isn't a call
624          // instruction, then we'll go ahead and look for another address.
625          if (!isPrevInstrACall(estimated_ip, getProc(), &callee))
626             continue;
627
628          //Given this point for the top of our stack frame, calculate the 
629          // frame pointer         
630          if (status == frame_saves_fp_noframe)
631          {
632             result = getProc()->readDataSpace((caddr_t) estimated_sp-addr_size,
633                               sizeof(int), (caddr_t) &estimated_fp, false);
634             if (!result) break;
635          }
636          else //status == NO_USE_FP
637          {
638             estimated_fp = fp_;
639          }
640
641          //If the call instruction calls into the current function, then we'll
642          // just skip everything else and assume we've got the correct return
643          // value (fingers crossed).
644          if (cur_func != NULL && cur_func == callee)
645          {
646             pcLoc = estimated_sp;
647             newPC = estimated_ip;
648             newFP = estimated_fp;
649             newSP = estimated_sp+addr_size;
650             goto done;
651          }
652          
653          //Check the validity of the frame pointer.  It's possible the
654          // previous frame doesn't have a valid fp, so we won't be able
655          // to rely on the check in this case.
656          int_function *next_func = getProc()->findFuncByAddr(estimated_ip);
657          if (next_func != NULL && 
658              getFrameStatus(getProc(), estimated_ip, extra_height) == frame_allocates_frame &&
659              (estimated_fp < fp_ || estimated_fp > stack_top))
660          {
661             continue;
662          }
663
664          //BAD HACK: The initial value of %esi when main starts sometimes
665          // points to an area in the guard_setup function that may look
666          // like a valid return value in some versions of libc.  Since it's
667          // easy for the value of %esi to get saved on the stack somewhere,
668          // we'll special case this.
669          if (callee == NULL && next_func != NULL &&
670              !strcmp(next_func->prettyName().c_str(), "__guard_setup"))
671          {
672            continue;
673          }
674
675          newPC = estimated_ip;
676          newFP = estimated_fp;
677          newSP = estimated_sp + getProc()->getAddressWidth();
678          goto done;
679       }
680    }
681    stackwalk_printf("%s[%d]: Heuristic stack walker failed, returning null frame\n", FILE__, __LINE__);
682
683    return Frame();
684
685  done:
686
687    Frame ret = Frame(newPC, newFP, newSP, newpcAddr, this);
688    ret.pcAddr_ = pcLoc;
689
690    if (status == frame_tramp)
691    {
692       /**
693        * Instrumentation has its own stack frame (created in the
694        * base tramp), but is really an extension of the function. 
695        * We skip the function. Platform-independent code can
696        * always regenerate it if desired.
697        **/
698       prevFrameValid = true;
699       prevFrame = *this;
700       ret = ret.getCallerFrame();
701       prevFrameValid = false;
702    }
703    return ret;
704 }
705