Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / frame.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 // $Id: frame.C,v 1.24 2008/06/19 19:53:15 legendre Exp $
33
34 #include <stdio.h>
35 #include <iostream>
36 #include "frame.h"
37 #include "process.h"
38 #include "dyn_thread.h"
39 #include "dyn_lwp.h"
40 #include "function.h"
41 #include "instPoint.h"
42 #include "baseTramp.h"
43 #include "miniTramp.h"
44
45
46 Frame::Frame() : 
47   frameType_(FRAME_unset), 
48   uppermost_(false), 
49   pc_(0), 
50   fp_(0), 
51   sp_(0),
52   pid_(0), 
53   proc_(NULL), 
54   thread_(NULL), 
55   lwp_(NULL), 
56   range_(0), 
57 #if defined(arch_ia64)
58   hasValidCursor(false),
59 #endif
60   pcAddr_(0) {
61     stackwalk_cerr << "*** Null frame ***" << endl;
62 }
63
64
65 Frame::Frame(Address pc, Address fp, Address sp,
66              unsigned pid, process *proc, 
67              dyn_thread *thread, dyn_lwp *lwp, 
68              bool uppermost,
69              Address pcAddr ) :
70   frameType_(FRAME_unset),
71   uppermost_(uppermost),
72   pc_(pc), fp_(fp), sp_(sp),
73   pid_(pid), proc_(proc), thread_(thread), lwp_(lwp), 
74   range_(0), 
75 #if defined(arch_ia64)
76   hasValidCursor(false),
77 #endif
78   pcAddr_(pcAddr) {
79   stackwalk_cerr << "Base frame:   " << (*this) << endl;
80 };
81
82 Frame::Frame(Address pc, Address fp, Address sp,
83              Address pcAddr, Frame *f) : 
84     frameType_(FRAME_unset),
85   uppermost_(false),
86   pc_(pc), fp_(fp), 
87   sp_(sp),
88   pid_(f->pid_), proc_(f->proc_),
89   thread_(f->thread_), lwp_(f->lwp_),
90   range_(0), 
91 #if defined(arch_ia64)
92     hasValidCursor(false), 
93 #endif   
94 pcAddr_(pcAddr) {
95   stackwalk_cerr << "Called frame: " << (*this) << endl;
96 }
97
98 codeRange *Frame::getRange() {
99   if (!range_) {
100     // First time... so get it and cache
101     if (!getProc())
102       return NULL;
103     range_ = getProc()->findOrigByAddr(getPC());
104   }
105   return range_;
106 }
107
108 void Frame::setRange(codeRange *range) {
109   assert(!range_ ||
110          (range == range_));
111   range_ = range;
112 }
113
114 bool Frame::isLastFrame() const
115 {
116 #if !defined(arch_x86) && !defined(arch_x86_64)
117    if (fp_ == 0) return true;
118 #endif
119    if (pc_ == 0) return true;
120    return false;
121 }
122
123 #if defined(os_linux) && defined(arch_x86)
124 extern void calcVSyscallFrame(process *p);
125 #endif
126
127 void Frame::calcFrameType()
128 {
129     // Can be called multiple times...
130     if (frameType_ != FRAME_unset) {
131         return;
132     }
133
134    int_function *func;
135    miniTrampInstance *mini;
136    multiTramp *multi;
137
138    // Without a process pointer, we're not going to get far.
139    if (!getProc())
140        return;
141
142    // Checking for a signal handler must go before the vsyscall check
143    // since (on Linux) the signal handler is _inside_ the vsyscall page.
144    if (getProc()->isInSignalHandler(pc_)) {
145      frameType_ = FRAME_signalhandler;
146      return;
147    }
148
149    // Better to have one function that has platform-specific IFDEFs
150    // than a stack of 90% equivalent functions
151 #if defined(os_linux) && defined(arch_x86)
152    calcVSyscallFrame(getProc());
153    if ((pc_ >= getProc()->getVsyscallStart() && pc_ < getProc()->getVsyscallEnd()) || /* Hack for RH9 */ (pc_ >= 0xffffe000 && pc_ < 0xfffff000)) {
154      frameType_ = FRAME_syscall;
155      return;
156    }
157 #endif   
158    
159    codeRange *range = getRange();
160
161    func = range->is_function();
162    multi = range->is_multitramp();
163    mini = range->is_minitramp();
164
165    if (mini != NULL) {
166        frameType_ = FRAME_instrumentation;
167        return;
168    }
169    else if (multi != NULL) {
170        frameType_ = FRAME_instrumentation;
171        return;
172    }
173    else if (func != NULL) {
174      frameType_ = FRAME_normal;
175      return;
176    }
177    else if (range->is_inferior_rpc()) {
178        frameType_ = FRAME_iRPC;
179        return;
180    }
181    else {
182      frameType_ = FRAME_unknown;
183      return;
184    }
185    assert(0 && "Unreachable");
186    frameType_ = FRAME_unset;
187    return;
188 }
189
190 // Get the instPoint corresponding with this frame
191 instPoint *Frame::getPoint() {
192     // Easy check:
193     if (getPC() == getUninstAddr())
194         return NULL;
195
196     codeRange *range = getRange();
197     
198     multiTramp *m_ptr = range->is_multitramp();
199     miniTrampInstance *mt_ptr = range->is_minitramp();
200
201     if (mt_ptr) {
202         return mt_ptr->mini->instP();
203     }
204     else if (m_ptr) {
205         // We're in a multiTramp, so between instPoints. 
206         // However, we're in a multiTramp and not the original code, so 
207         // we do need to discover an instpoint. We're not in a baseTramp,
208         // so that's not a problem; other options are relocated instruction
209         // or trampEnd.
210         return m_ptr->findInstPointByAddr(getPC());
211     }
212     return NULL;
213 }
214             
215 int_function *Frame::getFunc() {
216     codeRange *range = getRange();
217     if (range->is_function())
218         return range->is_function();
219     else if (range->is_multitramp())
220         return range->is_multitramp()->func();
221     else if (range->is_minitramp())
222         return range->is_minitramp()->baseTI->multiT->func();
223     else 
224         return NULL;
225 }
226
227 Address Frame::getUninstAddr() {
228     codeRange *range = getRange();
229     multiTramp *m_ptr = range->is_multitramp();
230     miniTrampInstance *mt_ptr = range->is_minitramp();
231     baseTrampInstance *bt_ptr = range->is_basetramp_multi();
232     bblInstance *bbl_ptr = range->is_basicBlockInstance();
233
234     if (m_ptr) {
235         // Figure out where in the multiTramp we are
236         return m_ptr->instToUninstAddr(getPC());
237     }
238     else if (mt_ptr) {
239         // Don't need the actual PC for minitramps
240         return mt_ptr->uninstrumentedAddr();
241     }
242     else if (bt_ptr) {
243         // Don't need actual PC here either
244         return bt_ptr->uninstrumentedAddr();
245     }
246     else if (bbl_ptr) {
247         // Relocated function... back-track
248         assert(range->is_basicBlock());
249         return bbl_ptr->equivAddr(range->is_basicBlock()->origInstance(), getPC());
250     }
251     else {
252         // Where are we?
253         return getPC();
254     }
255 }
256
257
258 ostream & operator << ( ostream & s, Frame & f ) {
259     f.calcFrameType();
260         codeRange * range = f.getRange();
261         int_function * func_ptr = range->is_function();
262         multiTramp *multi_ptr = range->is_multitramp();
263         miniTrampInstance * minitramp_ptr = range->is_minitramp();
264
265         s << "PC: 0x" << std::hex << f.getPC() << " ";
266         switch (f.frameType_) {
267         case FRAME_unset:
268           s << "[UNSET FRAME TYPE]";
269           break;
270         case FRAME_instrumentation:
271           s << "[Instrumentation:";
272           if (minitramp_ptr) {
273             s << "mt from "
274               << minitramp_ptr->baseTI->multiT->func()->prettyName();
275           }
276           else if (multi_ptr) {
277               baseTrampInstance *bti = multi_ptr->getBaseTrampInstanceByAddr(f.getPC());
278               if (bti) {
279                   s << "bt from ";
280               }
281               else {
282                   s << "multitramp from ";
283               }
284               
285               s << multi_ptr->func()->prettyName();
286           }
287
288           // And the address
289           s << std::hex << "/0x" << f.getUninstAddr();
290           s << "]" << std::dec;
291           
292           break;
293         case FRAME_signalhandler:
294           s << "[SIGNAL HANDLER]";
295           break;
296         case FRAME_normal:
297           if( func_ptr ) {
298             s << "[" << func_ptr->prettyName() << "]";
299           }
300           break;
301         case FRAME_syscall:
302           s << "[SYSCALL]";
303           break;
304         case FRAME_iRPC:
305             s << "[iRPC]";
306             break;
307         case FRAME_unknown:
308           s << "[UNKNOWN]";
309           break;
310         default:
311             s << "[ERROR!]";
312             break;
313         }
314         s << " FP: 0x" << std::hex << f.getFP() << " SP: 0x" << f.getSP() << " PID: " << std::dec << f.getPID() << " "; 
315         if( f.getThread() ) {
316                 s << "TID: " << f.getThread()->get_tid() << " ";
317                 }
318         if( f.getLWP() ) {
319                 s << "LWP: " << f.getLWP()->get_lwp_id() << " ";
320                 }
321         
322         return s;
323         }
324
325 bool Frame::isSignalFrame()
326
327     calcFrameType();
328     return frameType_ == FRAME_signalhandler;
329 }
330
331 bool Frame::isInstrumentation()
332
333     calcFrameType();
334     return frameType_ == FRAME_instrumentation;
335 }
336
337 bool Frame::isSyscall()
338
339     calcFrameType();
340     return frameType_ == FRAME_syscall;
341 }
342
343 int_stackwalk::int_stackwalk() { 
344    isValid_ = false; 
345 }
346
347 bool int_stackwalk::isValid() { 
348    return isValid_; 
349 }
350
351 bool int_stackwalk::setStackwalk(pdvector<Frame> &new_stack) {
352    stackwalk_ = new_stack;
353    isValid_ = true;
354    return true;
355 }
356
357 bool int_stackwalk::clear() { 
358    isValid_ = false; 
359    return true;
360 }
361
362 pdvector<Frame>& int_stackwalk::getStackwalk() {
363    assert(isValid_);
364    return stackwalk_;
365 }