Don't rely on DebugInfo stepper for library tracking. Also, if we're not in a library...
[dyninst.git] / stackwalk / src / framestepper.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "stackwalk/h/framestepper.h"
32 #include "stackwalk/h/walker.h"
33 #include "stackwalk/h/procstate.h"
34 #include "stackwalk/h/swk_errors.h"
35 #include "stackwalk/h/steppergroup.h"
36 #include "stackwalk/h/frame.h"
37
38 #include "stackwalk/src/sw.h"
39
40 #include <assert.h>
41
42 using namespace Dyninst;
43 using namespace Dyninst::Stackwalker;
44
45 FrameStepper::FrameStepper(Walker *w) :
46   walker(w)
47 {
48   sw_printf("[%s:%u] - Creating FrameStepper %p with walker %p\n", 
49             __FILE__, __LINE__, this, walker);
50   assert(walker);
51 }
52
53 FrameStepper::~FrameStepper() 
54 {
55   walker = NULL;
56   sw_printf("[%s:%u] - Deleting FrameStepper %p\n", __FILE__, __LINE__, this);
57 }
58
59 Walker *FrameStepper::getWalker()
60 {
61   assert(walker);
62   return walker;
63 }
64
65 ProcessState *FrameStepper::getProcessState() 
66 {
67   return getWalker()->getProcessState();
68 }
69
70 void FrameStepper::newLibraryNotification(LibAddrPair *, lib_change_t)
71 {
72 }
73
74 void FrameStepper::registerStepperGroup(StepperGroup *group)
75 {
76    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
77    if (addr_width == 4)
78       group->addStepper(this, 0, 0xffffffff);
79 #if defined(arch_64bit)
80    else if (addr_width == 8)
81       group->addStepper(this, 0, 0xffffffffffffffff);
82 #endif
83    else
84       assert(0 && "Unknown architecture word size");
85 }
86
87 FrameFuncHelper::FrameFuncHelper(ProcessState *proc_) :
88    proc(proc_)
89 {
90 }
91
92 FrameFuncHelper::~FrameFuncHelper()
93 {
94 }
95
96 std::map<SymReader*, bool> DyninstInstrStepperImpl::isRewritten;
97
98 DyninstInstrStepperImpl::DyninstInstrStepperImpl(Walker *w, DyninstInstrStepper *p) :
99   FrameStepper(w),
100   parent(p)
101 {
102 }
103
104 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrame(const Frame &in, Frame &out)
105 {
106    unsigned stack_height = 0;
107    LibAddrPair lib;
108    bool result;
109
110    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
111    if (!result) {
112       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
113                  __FILE__, __LINE__, in.getRA());
114       return gcf_stackbottom;
115    }
116
117    SymReader *reader = LibraryWrapper::getLibrary(lib.first);
118    if (!reader) {
119       sw_printf("[%s:%u] - Could not open file %s\n",
120                  __FILE__, __LINE__, lib.first.c_str());
121       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
122       return gcf_error;
123    }
124
125    std::map<SymReader *, bool>::iterator i = isRewritten.find(reader);
126    bool is_rewritten_binary;
127    if (i == isRewritten.end()) {
128       Section_t sec = reader->getSectionByName(".dyninstInst");
129       is_rewritten_binary = reader->isValidSection(sec);
130       isRewritten[reader] = is_rewritten_binary;
131    }
132    else {
133      is_rewritten_binary = (*i).second;
134    }
135    if (!is_rewritten_binary) {
136      sw_printf("[%s:u] - Decided that current binary is not rewritten, "
137                "DyninstInstrStepper returning gcf_not_me at %lx\n",
138                __FILE__, __LINE__, in.getRA());
139      return gcf_not_me;
140    }
141
142    std::string name;
143    in.getName(name);
144    const char *s = name.c_str();
145    if (strstr(s, "dyninst") != s)
146    {
147      sw_printf("[%s:%u] - Current function %s not dyninst generated\n",
148                 __FILE__, __LINE__, s);
149      return gcf_not_me;
150    }
151
152    if (strstr(s, "dyninstBT") != s)
153    {
154      sw_printf("[%s:%u] - Dyninst, but don't know how to read non-tramp %s\n",
155                 __FILE__, __LINE__, s);
156      return gcf_not_me;
157    }
158     
159    sw_printf("[%s:%u] - Current function %s is baseTramp\n",
160               __FILE__, __LINE__, s);
161    Address base;
162    unsigned size;
163    int num_read = sscanf(s, "dyninstBT_%lx_%u_%x", &base, &size, &stack_height);
164    bool has_stack_frame = (num_read == 3);
165    if (!has_stack_frame) {
166      sw_printf("[%s:%u] - Don't know how to walk through instrumentation without a stack frame\n"
167                 __FILE__, __LINE__);
168      return gcf_not_me;
169    }
170      
171    return getCallerFrameArch(in, out, base, lib.second, size, stack_height);
172 }
173
174 unsigned DyninstInstrStepperImpl::getPriority() const
175 {
176   return dyninstr_priority;
177 }
178
179 void DyninstInstrStepperImpl::registerStepperGroup(StepperGroup *group)
180 {
181   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
182   if (addr_width == 4)
183     group->addStepper(parent, 0, 0xffffffff);
184 #if defined(arch_64bit)
185   else if (addr_width == 8)
186     group->addStepper(parent, 0, 0xffffffffffffffff);
187 #endif
188   else
189     assert(0 && "Unknown architecture word size");
190 }
191
192 DyninstInstrStepperImpl::~DyninstInstrStepperImpl()
193 {
194 }
195 BottomOfStackStepperImpl::BottomOfStackStepperImpl(Walker *w, BottomOfStackStepper *p) :
196    FrameStepper(w),
197    parent(p),
198    libc_init(false),
199    aout_init(false),
200    libthread_init(false)
201 {
202    sw_printf("[%s:%u] - Constructing BottomOfStackStepperImpl at %p\n",
203              __FILE__, __LINE__, this);
204    initialize();
205 }
206
207 gcframe_ret_t BottomOfStackStepperImpl::getCallerFrame(const Frame &in, Frame & /*out*/)
208 {
209    /**
210     * This stepper never actually returns an 'out' frame.  It simply 
211     * tries to tell if we've reached the top of a stack and returns 
212     * either gcf_stackbottom or gcf_not_me.
213     **/
214    std::vector<std::pair<Address, Address> >::iterator i;
215    for (i = ra_stack_tops.begin(); i != ra_stack_tops.end(); i++)
216    {
217       if (in.getRA() >= (*i).first && in.getRA() <= (*i).second)
218          return gcf_stackbottom;
219    }
220
221    for (i = sp_stack_tops.begin(); i != sp_stack_tops.end(); i++)
222    {
223       if (in.getSP() >= (*i).first && in.getSP() < (*i).second)
224          return gcf_stackbottom;
225    }
226    LibAddrPair lib;
227    bool result;
228    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
229    if (!result) {
230       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
231                 __FILE__, __LINE__, in.getRA());
232       return gcf_error;
233    }
234
235
236    return gcf_not_me;
237 }
238
239 unsigned BottomOfStackStepperImpl::getPriority() const
240 {
241    //Highest priority, test for top of stack first.
242    return stackbottom_priority;
243 }
244
245 void BottomOfStackStepperImpl::registerStepperGroup(StepperGroup *group)
246 {
247    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
248    if (addr_width == 4)
249       group->addStepper(parent, 0, 0xffffffff);
250 #if defined(arch_64bit)
251    else if (addr_width == 8)
252       group->addStepper(parent, 0, 0xffffffffffffffff);
253 #endif
254    else
255       assert(0 && "Unknown architecture word size");
256 }
257
258 BottomOfStackStepperImpl::~BottomOfStackStepperImpl()
259 {
260 }
261
262 DyninstDynamicHelper::~DyninstDynamicHelper()
263 {
264 }
265
266 DyninstDynamicStepperImpl::DyninstDynamicStepperImpl(Walker *w, DyninstDynamicStepper *p,
267                                                      DyninstDynamicHelper *h) :
268   FrameStepper(w),
269   parent(p),
270   helper(h),
271   prevEntryExit(false)
272 {
273 }
274
275 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrame(const Frame &in, Frame &out)
276 {
277    unsigned stack_height = 0;
278    Address orig_ra = 0x0;
279    bool entryExit = false;
280    bool aligned = false;
281
282    // Handle dynamic instrumentation
283    if (helper)
284    {
285       bool instResult = helper->isInstrumentation(in.getRA(), &orig_ra, &stack_height, &aligned, &entryExit);
286       bool pEntryExit = prevEntryExit;
287        
288       // remember that this frame was entry/exit instrumentation
289       prevEntryExit = entryExit;
290       
291       if (pEntryExit || instResult) {
292          out.setNonCall();
293          return getCallerFrameArch(in, out, 0, 0, 0, stack_height, aligned, orig_ra, pEntryExit);
294       }
295    }
296
297    return gcf_not_me;
298 }
299
300 unsigned DyninstDynamicStepperImpl::getPriority() const
301 {
302   return dyninstr_priority;
303 }
304
305 void DyninstDynamicStepperImpl::registerStepperGroup(StepperGroup *group)
306 {
307   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
308   if (addr_width == 4)
309     group->addStepper(parent, 0, 0xffffffff);
310 #if defined(arch_64bit)
311   else if (addr_width == 8)
312     group->addStepper(parent, 0, 0xffffffffffffffff);
313 #endif
314   else
315     assert(0 && "Unknown architecture word size");
316 }
317
318 DyninstDynamicStepperImpl::~DyninstDynamicStepperImpl()
319 {
320 }
321
322 //FrameFuncStepper defined here
323 #define PIMPL_IMPL_CLASS FrameFuncStepperImpl
324 #define PIMPL_CLASS FrameFuncStepper
325 #define PIMPL_NAME "FrameFuncStepper"
326 #define PIMPL_ARG1 FrameFuncHelper*
327 #include "framestepper_pimple.h"
328 #undef PIMPL_CLASS
329 #undef PIMPL_NAME
330 #undef PIMPL_IMPL_CLASS
331 #undef PIMPL_ARG1
332
333 //DyninstInstrStepper defined here
334 #define PIMPL_IMPL_CLASS DyninstInstrStepperImpl
335 #define PIMPL_CLASS DyninstInstrStepper
336 #define PIMPL_NAME "DyninstInstrStepper"
337 #include "framestepper_pimple.h"
338 #undef PIMPL_CLASS
339 #undef PIMPL_IMPL_CLASS
340 #undef PIMPL_NAME
341
342 //BottomOfStackStepper defined here
343 #if defined(os_linux) || defined(os_bg) || defined(os_freebsd) || defined(os_windows)
344 #define OVERLOAD_NEWLIBRARY
345 #define PIMPL_IMPL_CLASS BottomOfStackStepperImpl
346 #endif
347 #define PIMPL_CLASS BottomOfStackStepper
348 #define PIMPL_NAME "BottomOfStackStepper"
349 #include "framestepper_pimple.h"
350 #undef PIMPL_CLASS
351 #undef PIMPL_IMPL_CLASS
352 #undef PIMPL_NAME
353 #undef OVERLOAD_NEWLIBRARY
354
355 //DebugStepper defined here
356 #if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64))
357 #include "stackwalk/src/dbgstepper-impl.h"
358 #define PIMPL_IMPL_CLASS DebugStepperImpl
359 #endif
360 #define PIMPL_CLASS DebugStepper
361 #define PIMPL_NAME "DebugStepper"
362 #include "framestepper_pimple.h"
363 #undef PIMPL_CLASS
364 #undef PIMPL_IMPL_CLASS
365 #undef PIMPL_NAME
366
367 //StepperWanderer defined here
368 #if defined(arch_x86) || defined(arch_x86_64)
369 #include "stackwalk/src/x86-swk.h"
370 #define PIMPL_IMPL_CLASS StepperWandererImpl
371 #endif
372 #define PIMPL_CLASS StepperWanderer
373 #define PIMPL_NAME "StepperWanderer"
374 #define PIMPL_ARG1 WandererHelper*
375 #define PIMPL_ARG2 FrameFuncHelper*
376 #include "framestepper_pimple.h"
377 #undef PIMPL_CLASS
378 #undef PIMPL_IMPL_CLASS
379 #undef PIMPL_NAME
380 #undef PIMPL_ARG1
381 #undef PIMPL_ARG2
382
383 //SigHandlerStepper defined here
384 #define OVERLOAD_NEWLIBRARY
385 #if defined(os_linux) || defined(os_freebsd) || defined(os_bgq)
386 #include "stackwalk/src/linuxbsd-swk.h"
387 #define PIMPL_IMPL_CLASS SigHandlerStepperImpl
388 #endif
389 #define PIMPL_CLASS SigHandlerStepper
390 #define PIMPL_NAME "SigHandlerStepper"
391 #include "framestepper_pimple.h"
392 #undef PIMPL_CLASS
393 #undef PIMPL_IMPL_CLASS
394 #undef PIMPL_NAME
395 #undef OVERLOAD_NEWLIBRARY
396
397 //AnalysisStepper defined here
398 #ifndef WITHOUT_PARSE_API
399 #include "stackwalk/src/analysis_stepper.h"
400 #define PIMPL_IMPL_CLASS AnalysisStepperImpl
401 #define PIMPL_CLASS AnalysisStepper
402 #define PIMPL_NAME "AnalysisStepper"
403 #include "framestepper_pimple.h"
404 #undef PIMPL_CLASS
405 #undef PIMPL_IMPL_CLASS
406 #undef PIMPL_NAME
407 #endif
408
409 //DyninstDynamicStepper defined here
410 #define PIMPL_IMPL_CLASS DyninstDynamicStepperImpl
411 #define PIMPL_CLASS DyninstDynamicStepper
412 #define PIMPL_NAME "DyninstDynamicStepper"
413 #define PIMPL_ARG1 DyninstDynamicHelper*
414 #include "framestepper_pimple.h"
415 #undef PIMPL_CLASS
416 #undef PIMPL_IMPL_CLASS
417 #undef PIMPL_NAME
418 #undef PIMPL_ARG1
419