Merge branch 'master' into new-parallel-parsing
[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
46 FrameStepper::FrameStepper(Walker *w) :
47   walker(w)
48 {
49   sw_printf("[%s:%u] - Creating FrameStepper %p with walker %p\n",
50             FILE__, __LINE__, this, walker);
51   assert(walker);
52 }
53
54 FrameStepper::~FrameStepper()
55 {
56   walker = NULL;
57   sw_printf("[%s:%u] - Deleting FrameStepper %p\n", FILE__, __LINE__, this);
58 }
59
60 Walker *FrameStepper::getWalker()
61 {
62   assert(walker);
63   return walker;
64 }
65
66 ProcessState *FrameStepper::getProcessState()
67 {
68   return getWalker()->getProcessState();
69 }
70
71 void FrameStepper::newLibraryNotification(LibAddrPair *, lib_change_t)
72 {
73 }
74
75 void FrameStepper::registerStepperGroup(StepperGroup *group)
76 {
77    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
78    if (addr_width == 4)
79       group->addStepper(this, 0, 0xffffffff);
80    else if (addr_width == 8)
81       group->addStepper(this, 0, 0xffffffffffffffff);
82    else
83       assert(0 && "Unknown architecture word size");
84 }
85
86 FrameFuncHelper::FrameFuncHelper(ProcessState *proc_) :
87    proc(proc_)
88 {
89 }
90
91 FrameFuncHelper::~FrameFuncHelper()
92 {
93 }
94
95 std::map<SymReader*, bool> DyninstInstrStepperImpl::isRewritten;
96
97 DyninstInstrStepperImpl::DyninstInstrStepperImpl(Walker *w, DyninstInstrStepper *p) :
98   FrameStepper(w),
99   parent(p)
100 {
101 }
102
103 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrame(const Frame &in, Frame &out)
104 {
105    unsigned stack_height = 0;
106    LibAddrPair lib;
107    bool result;
108
109    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
110    if (!result) {
111       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
112                  FILE__, __LINE__, in.getRA());
113       return gcf_error;
114    }
115
116    SymReader *reader = LibraryWrapper::getLibrary(lib.first);
117    if (!reader) {
118       sw_printf("[%s:%u] - Could not open file %s\n",
119                  FILE__, __LINE__, lib.first.c_str());
120       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
121       return gcf_error;
122    }
123
124    std::map<SymReader *, bool>::iterator i = isRewritten.find(reader);
125    bool is_rewritten_binary;
126    if (i == isRewritten.end()) {
127       Section_t sec = reader->getSectionByName(".dyninstInst");
128       is_rewritten_binary = reader->isValidSection(sec);
129       isRewritten[reader] = is_rewritten_binary;
130    }
131    else {
132      is_rewritten_binary = (*i).second;
133    }
134    if (!is_rewritten_binary) {
135      sw_printf("[%s:u] - Decided that current binary is not rewritten, "
136                "DyninstInstrStepper returning gcf_not_me at %lx\n",
137                FILE__, __LINE__, in.getRA());
138      return gcf_not_me;
139    }
140
141    std::string name;
142    in.getName(name);
143    const char *s = name.c_str();
144    if (strstr(s, "dyninst") != s)
145    {
146      sw_printf("[%s:%u] - Current function %s not dyninst generated\n",
147                 FILE__, __LINE__, s);
148      return gcf_not_me;
149    }
150
151    if (strstr(s, "dyninstBT") != s)
152    {
153      sw_printf("[%s:%u] - Dyninst, but don't know how to read non-tramp %s\n",
154                 FILE__, __LINE__, s);
155      return gcf_not_me;
156    }
157
158    sw_printf("[%s:%u] - Current function %s is baseTramp\n",
159               FILE__, __LINE__, s);
160    Address base;
161    unsigned size;
162    int num_read = sscanf(s, "dyninstBT_%lx_%u_%x", &base, &size, &stack_height);
163    bool has_stack_frame = (num_read == 3);
164    if (!has_stack_frame) {
165       sw_printf("[%s:%u] - Don't know how to walk through instrumentation without a stack frame\n",
166                 FILE__, __LINE__);
167      return gcf_not_me;
168    }
169
170    return getCallerFrameArch(in, out, base, lib.second, size, stack_height);
171 }
172
173 unsigned DyninstInstrStepperImpl::getPriority() const
174 {
175   return dyninstr_priority;
176 }
177
178 void DyninstInstrStepperImpl::registerStepperGroup(StepperGroup *group)
179 {
180   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
181   if (addr_width == 4)
182     group->addStepper(parent, 0, 0xffffffff);
183   else if (addr_width == 8)
184     group->addStepper(parent, 0, 0xffffffffffffffff);
185   else
186     assert(0 && "Unknown architecture word size");
187 }
188
189 DyninstInstrStepperImpl::~DyninstInstrStepperImpl()
190 {
191 }
192 BottomOfStackStepperImpl::BottomOfStackStepperImpl(Walker *w, BottomOfStackStepper *p) :
193    FrameStepper(w),
194    parent(p),
195    libc_init(false),
196    aout_init(false),
197    libthread_init(false)
198 {
199    sw_printf("[%s:%u] - Constructing BottomOfStackStepperImpl at %p\n",
200              FILE__, __LINE__, this);
201    initialize();
202 }
203
204 gcframe_ret_t BottomOfStackStepperImpl::getCallerFrame(const Frame &in, Frame & /*out*/)
205 {
206    /**
207     * This stepper never actually returns an 'out' frame.  It simply
208     * tries to tell if we've reached the top of a stack and returns
209     * either gcf_stackbottom or gcf_not_me.
210     **/
211    std::vector<std::pair<Address, Address> >::iterator i;
212    for (i = ra_stack_tops.begin(); i != ra_stack_tops.end(); i++)
213    {
214       if (in.getRA() >= (*i).first && in.getRA() <= (*i).second)
215          return gcf_stackbottom;
216    }
217
218    for (i = sp_stack_tops.begin(); i != sp_stack_tops.end(); i++)
219    {
220       if (in.getSP() >= (*i).first && in.getSP() < (*i).second)
221          return gcf_stackbottom;
222    }
223    // So we would really like to do error checking here
224    // but we can't. Specifically, the (generic) bottom of stack
225    // stepper has no idea that instrumentation may have been overlaid
226    // on the regular address space, because it knows nothing of instrumentation
227    // at all.
228    // Which, in turn, means that we delegate down to every other stepper
229    // the responsibility to check for whether an RA is out of bounds
230    // and error out accordingly--any one of them might be first
231    // in a custom stepper group.
232    // This is sub-optimal.
233
234    return gcf_not_me;
235 }
236
237 unsigned BottomOfStackStepperImpl::getPriority() const
238 {
239    //Highest priority, test for top of stack first.
240    return stackbottom_priority;
241 }
242
243 void BottomOfStackStepperImpl::registerStepperGroup(StepperGroup *group)
244 {
245    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
246    if (addr_width == 4)
247       group->addStepper(parent, 0, 0xffffffff);
248    else if (addr_width == 8)
249       group->addStepper(parent, 0, 0xffffffffffffffff);
250    else
251       assert(0 && "Unknown architecture word size");
252 }
253
254 BottomOfStackStepperImpl::~BottomOfStackStepperImpl()
255 {
256 }
257
258 DyninstDynamicHelper::~DyninstDynamicHelper()
259 {
260 }
261
262 DyninstDynamicStepperImpl::DyninstDynamicStepperImpl(Walker *w, DyninstDynamicStepper *p,
263                                                      DyninstDynamicHelper *h) :
264   FrameStepper(w),
265   parent(p),
266   helper(h),
267   prevEntryExit(false)
268 {
269 }
270
271 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrame(const Frame &in, Frame &out)
272 {
273    unsigned stack_height = 0;
274    Address orig_ra = 0x0;
275    bool entryExit = false;
276    bool aligned = false;
277
278    // Handle dynamic instrumentation
279    if (helper)
280    {
281       bool instResult = helper->isInstrumentation(in.getRA(), &orig_ra, &stack_height, &aligned, &entryExit);
282       bool pEntryExit = prevEntryExit;
283
284       // remember that this frame was entry/exit instrumentation
285       prevEntryExit = entryExit;
286
287       if (pEntryExit || instResult) {
288          out.setNonCall();
289          return getCallerFrameArch(in, out, 0, 0, 0, stack_height, aligned, orig_ra, pEntryExit);
290       }
291    }
292
293    return gcf_not_me;
294 }
295
296 unsigned DyninstDynamicStepperImpl::getPriority() const
297 {
298   return dyninstr_priority;
299 }
300
301 void DyninstDynamicStepperImpl::registerStepperGroup(StepperGroup *group)
302 {
303   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
304   if (addr_width == 4)
305     group->addStepper(parent, 0, 0xffffffff);
306   else if (addr_width == 8)
307     group->addStepper(parent, 0, 0xffffffffffffffff);
308   else
309     assert(0 && "Unknown architecture word size");
310 }
311
312 DyninstDynamicStepperImpl::~DyninstDynamicStepperImpl()
313 {
314 }
315
316 DyninstInstFrameStepperImpl::DyninstInstFrameStepperImpl(Walker *w, DyninstInstFrameStepper *p) :
317   FrameStepper(w),
318   parent(p)
319 {
320 }
321
322 gcframe_ret_t DyninstInstFrameStepperImpl::getCallerFrame(const Frame &in, Frame &out)
323 {
324     /**    
325         This wralker is designed to "jump over" instrimentation frames when stack walker is 
326         used in first party mode. The return from this walker will be the next valid frame 
327         in the program. 
328
329         Frame layout that this walker is looking for (in x86-64 ASM):
330
331         ...
332         mov 0x48(%rsp),%rax
333         push %rax           // Previous Frame SP pulled from the location stored earlier.
334         mov beefdead,%rax   
335         push %rax           // Flag variable (can be changed in emit-x86.C)
336         mov 36b6e340,%rax   
337         push %rax           // Return Address used by Stackwalker Third Party for unwidning
338         push %rbp           // Previous Frame FP, end of dyninst inst frame
339
340         How this function generates a stack frame:
341
342         1. Compares the current FP to the SP to determine if the FP holds an address that is potentially
343            on the stack. The reason for this check is to prevent reading uninitialized memory. Right now
344            it checks if the FP is within 500 stack positions of the SP.
345
346         2. Check for the magic word by reading the memory loaction current FP + addr_width * 2.
347
348         3. If the magic word is detected, rthe frame is generated by the following:
349
350             Frame SP: reading the value at FP + addr_width * 3 then adding addr_width to this value.
351             Frame FP: reading the value at FP (should be the stored previous FP)
352             Frame RA: reading the value at the Previous Frames SP - addr_width.
353     */
354
355
356     // Magic word inserted into the stack by dyninst instrimentation frame creation.
357     // If the magic word is present at in.getFP()[1], accept this frame
358     uint64_t magicWord = 0xBEEFDEAD;
359
360     Address ret;
361     Address framePtr = in.getFP();
362     Address stackPtr = in.getSP();
363
364     const unsigned addr_width = getProcessState()->getAddressWidth();
365
366     Address magicWordPos =  addr_width * 2;
367     Address spPosition = addr_width * 3;
368
369     uint64_t diff = uint64_t(framePtr) - uint64_t(stackPtr);
370
371     // Get the address width for the architecture
372
373     // Check if the FP is close to the SP. If it is not, the FP is likely invalid and this
374     // isn't an instrimentation frame. This check is required to prevent a deref of an invalid FP. 
375     if ( diff >= (addr_width * 500) ) {
376       sw_printf("[%s:%u] - I am Rejecting frame because (FP - stackPtr) > 500 stack positions - FP: %lx , SP: %lx, DIFF: %llu, Check: %u\n",
377           FILE__, __LINE__, framePtr, stackPtr, diff,  (addr_width * 500));          
378       return gcf_not_me;
379     }
380
381     sw_printf("[%s:%u] - %lx reading from memory at location %lx with framePtr %lx\n",
382         FILE__, __LINE__, ret, framePtr + addr_width);    
383
384     // Read the location in the stack where the Special Value should be.
385     // This value was inserted into the stack at inst frame creation. 
386     if (getWord(ret, framePtr + magicWordPos)) {    
387         // check the return 
388         sw_printf("[%s:%u] - %lx read from memory at location %lx\n",
389             FILE__, __LINE__, ret, magicWordPos);
390         // Check if that value is equal to the magic word, if its not we are not in 
391         // an instrimentation frame
392         if ((uint64_t)ret == magicWord) {
393             // Accept the frame
394             Address sp, ra, fp;
395             // Read SP and FP for the next frame.
396             if (!getWord(fp, framePtr) || !getWord(sp, framePtr + spPosition)) {
397                 sw_printf("[%s:%u] - unable to read SP or FP from frame\n",
398                     FILE__, __LINE__);           
399                 return gcf_not_me;
400             }
401             // Get the return address by reading the SP.
402             if (!getWord(ra, sp)) {
403                 sw_printf("[%s:%u] - unable to read return address from %lx\n",
404                     FILE__, __LINE__, sp);           
405                 return gcf_not_me;
406             }
407             // Offset sp by addr_width to account for where the frame truely ends
408             // without this, debugsteppers will not function on the out frame.
409             sp = sp + addr_width;
410             out.setRA(ra);
411             out.setFP(fp);
412             out.setSP(sp);
413             sw_printf("[%s:%u] - Accepted frame, output new frame with SP: %lx\n",
414                     FILE__, __LINE__, sp);           
415             return gcf_success;
416         }
417     } 
418     return gcf_not_me;
419 }
420
421 bool DyninstInstFrameStepperImpl::getWord(Address &word_out, Address start)
422 {
423    const unsigned addr_width = getProcessState()->getAddressWidth();
424    if (start < 1024) {
425       sw_printf("[%s:%u] - %lx too low to be valid memory\n",
426                 FILE__, __LINE__, start);
427       return false;
428    }
429    word_out = 0x0;
430    bool result = getProcessState()->readMem(&word_out, start, addr_width);
431    if (!result) {
432       sw_printf("[%s:%u] - DyninstInstFrameStepperImpl couldn't read from stack at 0x%lx\n",
433                 FILE__, __LINE__, start);
434       return false;
435    }
436
437    return true;
438 }
439
440 unsigned DyninstInstFrameStepperImpl::getPriority() const
441 {
442   return dyninstr_priority;
443 }
444
445 void DyninstInstFrameStepperImpl::registerStepperGroup(StepperGroup *group)
446 {
447   unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
448   if (addr_width == 4)
449     group->addStepper(parent, 0, 0xffffffff);
450 #if defined(arch_64bit)
451   else if (addr_width == 8)
452     group->addStepper(parent, 0, 0xffffffffffffffff);
453 #endif
454   else
455     assert(0 && "Unknown architecture word size");
456 }
457
458 DyninstInstFrameStepperImpl::~DyninstInstFrameStepperImpl()
459 {
460 }
461
462
463 //FrameFuncStepper defined here
464 #define PIMPL_IMPL_CLASS FrameFuncStepperImpl
465 #define PIMPL_CLASS FrameFuncStepper
466 #define PIMPL_NAME "FrameFuncStepper"
467 #define PIMPL_ARG1 FrameFuncHelper*
468 #include "framestepper_pimple.h"
469 #undef PIMPL_CLASS
470 #undef PIMPL_NAME
471 #undef PIMPL_IMPL_CLASS
472 #undef PIMPL_ARG1
473
474 //DyninstInstrStepper defined here
475 #define PIMPL_IMPL_CLASS DyninstInstrStepperImpl
476 #define PIMPL_CLASS DyninstInstrStepper
477 #define PIMPL_NAME "DyninstInstrStepper"
478 #include "framestepper_pimple.h"
479 #undef PIMPL_CLASS
480 #undef PIMPL_IMPL_CLASS
481 #undef PIMPL_NAME
482
483 //BottomOfStackStepper defined here
484 #if defined(os_linux) || defined(os_bg) || defined(os_freebsd) || defined(os_windows)
485 #define OVERLOAD_NEWLIBRARY
486 #define PIMPL_IMPL_CLASS BottomOfStackStepperImpl
487 #endif
488 #define PIMPL_CLASS BottomOfStackStepper
489 #define PIMPL_NAME "BottomOfStackStepper"
490 #include "framestepper_pimple.h"
491 #undef PIMPL_CLASS
492 #undef PIMPL_IMPL_CLASS
493 #undef PIMPL_NAME
494 #undef OVERLOAD_NEWLIBRARY
495
496 //DebugStepper defined here
497 //#if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64))
498 #if (defined(os_linux) || defined(os_freebsd)) && (defined(arch_x86) || defined(arch_x86_64) || defined(arch_aarch64) )
499 #include "stackwalk/src/dbgstepper-impl.h"
500 #define PIMPL_IMPL_CLASS DebugStepperImpl
501 #endif
502 #define PIMPL_CLASS DebugStepper
503 #define PIMPL_NAME "DebugStepper"
504 #include "framestepper_pimple.h"
505 #undef PIMPL_CLASS
506 #undef PIMPL_IMPL_CLASS
507 #undef PIMPL_NAME
508
509 //StepperWanderer defined here
510 #if defined(arch_x86) || defined(arch_x86_64)
511 #include "stackwalk/src/x86-swk.h"
512 #define PIMPL_IMPL_CLASS StepperWandererImpl
513 #endif
514 #define PIMPL_CLASS StepperWanderer
515 #define PIMPL_NAME "StepperWanderer"
516 #define PIMPL_ARG1 WandererHelper*
517 #define PIMPL_ARG2 FrameFuncHelper*
518 #include "framestepper_pimple.h"
519 #undef PIMPL_CLASS
520 #undef PIMPL_IMPL_CLASS
521 #undef PIMPL_NAME
522 #undef PIMPL_ARG1
523 #undef PIMPL_ARG2
524
525 //SigHandlerStepper defined here
526 #define OVERLOAD_NEWLIBRARY
527 #if defined(os_linux) || defined(os_freebsd) || defined(os_bgq)
528 #include "stackwalk/src/linuxbsd-swk.h"
529 #define PIMPL_IMPL_CLASS SigHandlerStepperImpl
530 #endif
531 #define PIMPL_CLASS SigHandlerStepper
532 #define PIMPL_NAME "SigHandlerStepper"
533 #include "framestepper_pimple.h"
534 #undef PIMPL_CLASS
535 #undef PIMPL_IMPL_CLASS
536 #undef PIMPL_NAME
537 #undef OVERLOAD_NEWLIBRARY
538
539 //AnalysisStepper defined here
540 #ifdef USE_PARSE_API
541 #include "stackwalk/src/analysis_stepper.h"
542 #define PIMPL_IMPL_CLASS AnalysisStepperImpl
543 #endif
544 #define PIMPL_CLASS AnalysisStepper
545 #define PIMPL_NAME "AnalysisStepper"
546 #include "framestepper_pimple.h"
547 #undef PIMPL_CLASS
548 #undef PIMPL_IMPL_CLASS
549 #undef PIMPL_NAME
550
551
552 //DyninstDynamicStepper defined here
553 #define PIMPL_IMPL_CLASS DyninstDynamicStepperImpl
554 #define PIMPL_CLASS DyninstDynamicStepper
555 #define PIMPL_NAME "DyninstDynamicStepper"
556 #define PIMPL_ARG1 DyninstDynamicHelper*
557 #include "framestepper_pimple.h"
558 #undef PIMPL_CLASS
559 #undef PIMPL_IMPL_CLASS
560 #undef PIMPL_NAME
561 #undef PIMPL_ARG1
562
563 //DyninstInstFrameStepper defined here
564 #define PIMPL_IMPL_CLASS DyninstInstFrameStepperImpl
565 #define PIMPL_CLASS DyninstInstFrameStepper
566 #define PIMPL_NAME "DyninstInstFrameStepper"
567 #include "framestepper_pimple.h"
568 #undef PIMPL_CLASS
569 #undef PIMPL_IMPL_CLASS
570 #undef PIMPL_NAME