Update copyright disclaimer structure by outlining copyright notice. Add LLNL and...
[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
227    return gcf_not_me;
228 }
229
230 unsigned BottomOfStackStepperImpl::getPriority() const
231 {
232    //Highest priority, test for top of stack first.
233    return stackbottom_priority;
234 }
235
236 void BottomOfStackStepperImpl::registerStepperGroup(StepperGroup *group)
237 {
238    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
239    if (addr_width == 4)
240       group->addStepper(parent, 0, 0xffffffff);
241 #if defined(arch_64bit)
242    else if (addr_width == 8)
243       group->addStepper(parent, 0, 0xffffffffffffffff);
244 #endif
245    else
246       assert(0 && "Unknown architecture word size");
247 }
248
249 BottomOfStackStepperImpl::~BottomOfStackStepperImpl()
250 {
251 }
252
253 DyninstDynamicHelper::~DyninstDynamicHelper()
254 {
255 }
256
257 DyninstDynamicStepperImpl::DyninstDynamicStepperImpl(Walker *w, DyninstDynamicStepper *p,
258                                                      DyninstDynamicHelper *h) :
259   FrameStepper(w),
260   parent(p),
261   helper(h),
262   prevEntryExit(false)
263 {
264 }
265
266 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrame(const Frame &in, Frame &out)
267 {
268    unsigned stack_height = 0;
269    Address orig_ra = 0x0;
270    bool entryExit = false;
271    bool aligned = false;
272
273    // Handle dynamic instrumentation
274    if (helper)
275    {
276       bool instResult = helper->isInstrumentation(in.getRA(), &orig_ra, &stack_height, &aligned, &entryExit);
277       bool pEntryExit = prevEntryExit;
278        
279       // remember that this frame was entry/exit instrumentation
280       prevEntryExit = entryExit;
281       
282       if (pEntryExit || instResult) {
283          out.setNonCall();
284          return getCallerFrameArch(in, out, 0, 0, 0, stack_height, aligned, orig_ra, pEntryExit);
285       }
286    }
287
288    return gcf_not_me;
289 }
290
291 unsigned DyninstDynamicStepperImpl::getPriority() const
292 {
293   return dyninstr_priority;
294 }
295
296 void DyninstDynamicStepperImpl::registerStepperGroup(StepperGroup *group)
297 {
298   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
299   if (addr_width == 4)
300     group->addStepper(parent, 0, 0xffffffff);
301 #if defined(arch_64bit)
302   else if (addr_width == 8)
303     group->addStepper(parent, 0, 0xffffffffffffffff);
304 #endif
305   else
306     assert(0 && "Unknown architecture word size");
307 }
308
309 DyninstDynamicStepperImpl::~DyninstDynamicStepperImpl()
310 {
311 }
312
313 //FrameFuncStepper defined here
314 #define PIMPL_IMPL_CLASS FrameFuncStepperImpl
315 #define PIMPL_CLASS FrameFuncStepper
316 #define PIMPL_NAME "FrameFuncStepper"
317 #define PIMPL_ARG1 FrameFuncHelper*
318 #include "framestepper_pimple.h"
319 #undef PIMPL_CLASS
320 #undef PIMPL_NAME
321 #undef PIMPL_IMPL_CLASS
322 #undef PIMPL_ARG1
323
324 //DyninstInstrStepper defined here
325 #define PIMPL_IMPL_CLASS DyninstInstrStepperImpl
326 #define PIMPL_CLASS DyninstInstrStepper
327 #define PIMPL_NAME "DyninstInstrStepper"
328 #include "framestepper_pimple.h"
329 #undef PIMPL_CLASS
330 #undef PIMPL_IMPL_CLASS
331 #undef PIMPL_NAME
332
333 //BottomOfStackStepper defined here
334 #if defined(os_linux) || defined(os_bg) || defined(os_freebsd) || defined(os_windows)
335 #define OVERLOAD_NEWLIBRARY
336 #define PIMPL_IMPL_CLASS BottomOfStackStepperImpl
337 #endif
338 #define PIMPL_CLASS BottomOfStackStepper
339 #define PIMPL_NAME "BottomOfStackStepper"
340 #include "framestepper_pimple.h"
341 #undef PIMPL_CLASS
342 #undef PIMPL_IMPL_CLASS
343 #undef PIMPL_NAME
344 #undef OVERLOAD_NEWLIBRARY
345
346 //DebugStepper defined here
347 #if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64))
348 #include "stackwalk/src/dbgstepper-impl.h"
349 #define PIMPL_IMPL_CLASS DebugStepperImpl
350 #endif
351 #define PIMPL_CLASS DebugStepper
352 #define PIMPL_NAME "DebugStepper"
353 #include "framestepper_pimple.h"
354 #undef PIMPL_CLASS
355 #undef PIMPL_IMPL_CLASS
356 #undef PIMPL_NAME
357
358 //StepperWanderer defined here
359 #if defined(arch_x86) || defined(arch_x86_64)
360 #include "stackwalk/src/x86-swk.h"
361 #define PIMPL_IMPL_CLASS StepperWandererImpl
362 #endif
363 #define PIMPL_CLASS StepperWanderer
364 #define PIMPL_NAME "StepperWanderer"
365 #define PIMPL_ARG1 WandererHelper*
366 #define PIMPL_ARG2 FrameFuncHelper*
367 #include "framestepper_pimple.h"
368 #undef PIMPL_CLASS
369 #undef PIMPL_IMPL_CLASS
370 #undef PIMPL_NAME
371 #undef PIMPL_ARG1
372 #undef PIMPL_ARG2
373
374 //SigHandlerStepper defined here
375 #define OVERLOAD_NEWLIBRARY
376 #if defined(os_linux) || defined(os_freebsd) || defined(os_bgq)
377 #include "stackwalk/src/linuxbsd-swk.h"
378 #define PIMPL_IMPL_CLASS SigHandlerStepperImpl
379 #endif
380 #define PIMPL_CLASS SigHandlerStepper
381 #define PIMPL_NAME "SigHandlerStepper"
382 #include "framestepper_pimple.h"
383 #undef PIMPL_CLASS
384 #undef PIMPL_IMPL_CLASS
385 #undef PIMPL_NAME
386 #undef OVERLOAD_NEWLIBRARY
387
388 //AnalysisStepper defined here
389 #ifndef WITHOUT_PARSE_API
390 #include "stackwalk/src/analysis_stepper.h"
391 #define PIMPL_IMPL_CLASS AnalysisStepperImpl
392 #define PIMPL_CLASS AnalysisStepper
393 #define PIMPL_NAME "AnalysisStepper"
394 #include "framestepper_pimple.h"
395 #undef PIMPL_CLASS
396 #undef PIMPL_IMPL_CLASS
397 #undef PIMPL_NAME
398 #endif
399
400 //DyninstDynamicStepper defined here
401 #define PIMPL_IMPL_CLASS DyninstDynamicStepperImpl
402 #define PIMPL_CLASS DyninstDynamicStepper
403 #define PIMPL_NAME "DyninstDynamicStepper"
404 #define PIMPL_ARG1 DyninstDynamicHelper*
405 #include "framestepper_pimple.h"
406 #undef PIMPL_CLASS
407 #undef PIMPL_IMPL_CLASS
408 #undef PIMPL_NAME
409 #undef PIMPL_ARG1
410