third party sw is good, not well tested
[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_error;
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    // So we would really like to do error checking here
227    // but we can't. Specifically, the (generic) bottom of stack
228    // stepper has no idea that instrumentation may have been overlaid
229    // on the regular address space, because it knows nothing of instrumentation
230    // at all.
231    // Which, in turn, means that we delegate down to every other stepper
232    // the responsibility to check for whether an RA is out of bounds
233    // and error out accordingly--any one of them might be first
234    // in a custom stepper group.
235    // This is sub-optimal.
236
237    return gcf_not_me;
238 }
239
240 unsigned BottomOfStackStepperImpl::getPriority() const
241 {
242    //Highest priority, test for top of stack first.
243    return stackbottom_priority;
244 }
245
246 void BottomOfStackStepperImpl::registerStepperGroup(StepperGroup *group)
247 {
248    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
249    if (addr_width == 4)
250       group->addStepper(parent, 0, 0xffffffff);
251 #if defined(arch_64bit)
252    else if (addr_width == 8)
253       group->addStepper(parent, 0, 0xffffffffffffffff);
254 #endif
255    else
256       assert(0 && "Unknown architecture word size");
257 }
258
259 BottomOfStackStepperImpl::~BottomOfStackStepperImpl()
260 {
261 }
262
263 DyninstDynamicHelper::~DyninstDynamicHelper()
264 {
265 }
266
267 DyninstDynamicStepperImpl::DyninstDynamicStepperImpl(Walker *w, DyninstDynamicStepper *p,
268                                                      DyninstDynamicHelper *h) :
269   FrameStepper(w),
270   parent(p),
271   helper(h),
272   prevEntryExit(false)
273 {
274 }
275
276 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrame(const Frame &in, Frame &out)
277 {
278    unsigned stack_height = 0;
279    Address orig_ra = 0x0;
280    bool entryExit = false;
281    bool aligned = false;
282
283    // Handle dynamic instrumentation
284    if (helper)
285    {
286       bool instResult = helper->isInstrumentation(in.getRA(), &orig_ra, &stack_height, &aligned, &entryExit);
287       bool pEntryExit = prevEntryExit;
288
289       // remember that this frame was entry/exit instrumentation
290       prevEntryExit = entryExit;
291
292       if (pEntryExit || instResult) {
293          out.setNonCall();
294          return getCallerFrameArch(in, out, 0, 0, 0, stack_height, aligned, orig_ra, pEntryExit);
295       }
296    }
297
298    return gcf_not_me;
299 }
300
301 unsigned DyninstDynamicStepperImpl::getPriority() const
302 {
303   return dyninstr_priority;
304 }
305
306 void DyninstDynamicStepperImpl::registerStepperGroup(StepperGroup *group)
307 {
308   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
309   if (addr_width == 4)
310     group->addStepper(parent, 0, 0xffffffff);
311 #if defined(arch_64bit)
312   else if (addr_width == 8)
313     group->addStepper(parent, 0, 0xffffffffffffffff);
314 #endif
315   else
316     assert(0 && "Unknown architecture word size");
317 }
318
319 DyninstDynamicStepperImpl::~DyninstDynamicStepperImpl()
320 {
321 }
322
323 //FrameFuncStepper defined here
324 #define PIMPL_IMPL_CLASS FrameFuncStepperImpl
325 #define PIMPL_CLASS FrameFuncStepper
326 #define PIMPL_NAME "FrameFuncStepper"
327 #define PIMPL_ARG1 FrameFuncHelper*
328 #include "framestepper_pimple.h"
329 #undef PIMPL_CLASS
330 #undef PIMPL_NAME
331 #undef PIMPL_IMPL_CLASS
332 #undef PIMPL_ARG1
333
334 //DyninstInstrStepper defined here
335 #define PIMPL_IMPL_CLASS DyninstInstrStepperImpl
336 #define PIMPL_CLASS DyninstInstrStepper
337 #define PIMPL_NAME "DyninstInstrStepper"
338 #include "framestepper_pimple.h"
339 #undef PIMPL_CLASS
340 #undef PIMPL_IMPL_CLASS
341 #undef PIMPL_NAME
342
343 //BottomOfStackStepper defined here
344 #if defined(os_linux) || defined(os_bg) || defined(os_freebsd) || defined(os_windows)
345 #define OVERLOAD_NEWLIBRARY
346 #define PIMPL_IMPL_CLASS BottomOfStackStepperImpl
347 #endif
348 #define PIMPL_CLASS BottomOfStackStepper
349 #define PIMPL_NAME "BottomOfStackStepper"
350 #include "framestepper_pimple.h"
351 #undef PIMPL_CLASS
352 #undef PIMPL_IMPL_CLASS
353 #undef PIMPL_NAME
354 #undef OVERLOAD_NEWLIBRARY
355
356 //DebugStepper defined here
357 #if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64))
358 #include "stackwalk/src/dbgstepper-impl.h"
359 #define PIMPL_IMPL_CLASS DebugStepperImpl
360 #endif
361 #define PIMPL_CLASS DebugStepper
362 #define PIMPL_NAME "DebugStepper"
363 #include "framestepper_pimple.h"
364 #undef PIMPL_CLASS
365 #undef PIMPL_IMPL_CLASS
366 #undef PIMPL_NAME
367
368 //StepperWanderer defined here
369 #if defined(arch_x86) || defined(arch_x86_64)
370 #include "stackwalk/src/x86-swk.h"
371 #define PIMPL_IMPL_CLASS StepperWandererImpl
372 #endif
373 #define PIMPL_CLASS StepperWanderer
374 #define PIMPL_NAME "StepperWanderer"
375 #define PIMPL_ARG1 WandererHelper*
376 #define PIMPL_ARG2 FrameFuncHelper*
377 #include "framestepper_pimple.h"
378 #undef PIMPL_CLASS
379 #undef PIMPL_IMPL_CLASS
380 #undef PIMPL_NAME
381 #undef PIMPL_ARG1
382 #undef PIMPL_ARG2
383
384 //SigHandlerStepper defined here
385 #define OVERLOAD_NEWLIBRARY
386 #if defined(os_linux) || defined(os_freebsd) || defined(os_bgq)
387 #include "stackwalk/src/linuxbsd-swk.h"
388 #define PIMPL_IMPL_CLASS SigHandlerStepperImpl
389 #endif
390 #define PIMPL_CLASS SigHandlerStepper
391 #define PIMPL_NAME "SigHandlerStepper"
392 #include "framestepper_pimple.h"
393 #undef PIMPL_CLASS
394 #undef PIMPL_IMPL_CLASS
395 #undef PIMPL_NAME
396 #undef OVERLOAD_NEWLIBRARY
397
398 //AnalysisStepper defined here
399 #ifdef USE_PARSE_API
400 #include "stackwalk/src/analysis_stepper.h"
401 #define PIMPL_IMPL_CLASS AnalysisStepperImpl
402 #endif
403 #define PIMPL_CLASS AnalysisStepper
404 #define PIMPL_NAME "AnalysisStepper"
405 #include "framestepper_pimple.h"
406 #undef PIMPL_CLASS
407 #undef PIMPL_IMPL_CLASS
408 #undef PIMPL_NAME
409
410
411 //DyninstDynamicStepper defined here
412 #define PIMPL_IMPL_CLASS DyninstDynamicStepperImpl
413 #define PIMPL_CLASS DyninstDynamicStepper
414 #define PIMPL_NAME "DyninstDynamicStepper"
415 #define PIMPL_ARG1 DyninstDynamicHelper*
416 #include "framestepper_pimple.h"
417 #undef PIMPL_CLASS
418 #undef PIMPL_IMPL_CLASS
419 #undef PIMPL_NAME
420 #undef PIMPL_ARG1
421