GCC 4.8 build fixes: ensure all extern template declarations are in fact extern'ed...
[dyninst.git] / stackwalk / src / dbginfo-stepper.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/frame.h"
33 #include "stackwalk/h/procstate.h"
34 #include "stackwalk/h/swk_errors.h"
35 #include "stackwalk/h/steppergroup.h"
36 #include "stackwalk/h/walker.h"
37 #include "stackwalk/src/dbgstepper-impl.h"
38 #include "stackwalk/src/linuxbsd-swk.h"
39 #include "stackwalk/src/libstate.h"
40 #include "common/h/dyntypes.h"
41 #include "common/h/VariableLocation.h"
42 #include "common/src/Types.h"
43 #include "dwarfFrameParser.h"
44 #include "dwarfHandle.h"
45
46 #if defined(WITH_SYMTAB_API)
47 #include "symtabAPI/h/Symtab.h"
48 #endif
49
50 using namespace Dyninst;
51 using namespace Stackwalker;
52 using namespace Dwarf;
53
54 static std::map<std::string, DwarfFrameParser::Ptr> dwarf_info;
55
56 #include <stdarg.h>
57 #include "dwarf.h"
58 #include "libdwarf.h"
59 #include "Elf_X.h"
60
61 static DwarfFrameParser::Ptr getAuxDwarfInfo(std::string s)
62 {
63    static std::map<std::string, DwarfFrameParser::Ptr > dwarf_aux_info;
64
65    std::map<std::string, DwarfFrameParser::Ptr >::iterator i = dwarf_aux_info.find(s);
66    if (i != dwarf_aux_info.end())
67       return i->second;
68
69    SymReader *orig_reader = LibraryWrapper::getLibrary(s);
70    if (!orig_reader) {
71       sw_printf("[%s:%u] - Error.  Could not find elf handle for %s\n",
72                 FILE__, __LINE__, s.c_str());
73       return DwarfFrameParser::Ptr();
74    }
75    Elf_X *orig_elf = (Elf_X *) orig_reader->getElfHandle();
76    if (!orig_elf) {
77       sw_printf("[%s:%u] - Error. Could not find elf handle for file %s\n",
78                 FILE__, __LINE__, s.c_str());
79       dwarf_aux_info[s] = DwarfFrameParser::Ptr();
80       return DwarfFrameParser::Ptr();
81    }
82
83    DwarfHandle::ptr dwarf = DwarfHandle::createDwarfHandle(s, orig_elf);
84    assert(dwarf);
85
86    // FIXME for ppc, if we ever support debug walking on ppc
87    Architecture arch;
88 #if defined(arch_x86) || defined(arch_x86_64)
89    if (orig_elf->wordSize() == 4)
90       arch = Dyninst::Arch_x86;
91    else
92       arch = Dyninst::Arch_x86_64;
93 #elif defined(arch_aarch64)
94     arch = Dyninst::Arch_aarch64;
95 #endif
96
97    DwarfFrameParser::Ptr dresult = DwarfFrameParser::create(*dwarf->frame_dbg(), arch);
98    dwarf_aux_info[s] = dresult;
99    return dresult;
100 }
101
102
103 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
104    FrameStepper(w),
105    last_addr_read(0),
106    last_val_read(0),
107    addr_width(0),
108    parent_stepper(parent),
109    cur_frame(NULL),
110    depth_frame(NULL)
111 {
112 }
113
114 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
115 {
116    bool result = getProcessState()->readMem(buffer, addr, size);
117
118    last_addr_read = 0;
119    if (!result)
120       return false;
121    if (size != addr_width)
122       return false;
123
124    last_addr_read = addr;
125    if (addr_width == 4) {
126       uint32_t v = *((uint32_t *) buffer);
127       last_val_read = v;
128    }
129    else if (addr_width == 8) {
130       uint64_t v = *((uint64_t *) buffer);
131       last_val_read = v;
132    }
133    else {
134       assert(0); //Unknown size
135    }
136
137    return true;
138 }
139
140 location_t DebugStepperImpl::getLastComputedLocation(unsigned long value)
141 {
142    location_t loc;
143    if (last_addr_read && last_val_read == value) {
144       loc.val.addr = last_addr_read;
145       loc.location = loc_address;
146    }
147    else {
148       loc.val.addr = 0;
149       loc.location = loc_unknown;
150    }
151    last_addr_read = 0;
152    last_val_read = 0;
153    return loc;
154 }
155
156 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
157 {
158    if (reg.isFramePointer()) {
159       val = static_cast<MachRegisterVal>(depth_frame->getFP());
160       return true;
161    }
162
163    if (reg.isStackPointer()) {
164       val = static_cast<MachRegisterVal>(depth_frame->getSP());
165       return true;
166    }
167
168    if (reg.isPC()) {
169       val = static_cast<MachRegisterVal>(depth_frame->getRA());
170       return true;
171    }
172
173    bool result = false;
174    const Frame *prevDepthFrame = depth_frame;
175    depth_frame = depth_frame->getPrevFrame();
176    if (!depth_frame)
177    {
178       result = getProcessState()->getRegValue(reg, cur_frame->getThread(), val);
179    }
180 #if defined(WITH_SYMTAB_API)
181    else
182    {
183       Offset offset;
184       void *symtab_v = NULL;
185       std::string lib;
186       depth_frame->getLibOffset(lib, offset, symtab_v);
187       SymtabAPI::Symtab *symtab = (SymtabAPI::Symtab*) symtab_v;
188       if (symtab)
189       {
190          result = symtab->getRegValueAtFrame(offset, reg, val, this);
191       }
192    }
193 #endif
194
195    depth_frame = prevDepthFrame;
196    return result;
197 }
198
199 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
200 {
201    LibAddrPair lib;
202    bool result;
203
204    if (lookupInCache(in, out)) {
205        result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(out.getRA(), lib);
206        if (result) {
207            // Hit, and valid RA found
208            return gcf_success;
209        }
210    }
211
212    // This error check is duplicated in BottomOfStackStepper.
213    // We should always call BOSStepper first; however, we need the
214    // library for the debug stepper as well. If this becomes
215    // a performance problem we can cache the library info in
216    // the input frame.
217    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
218    if (!result) {
219       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
220                 FILE__, __LINE__, in.getRA());
221       return gcf_error;
222    }
223    Address pc = in.getRA() - lib.second;
224    sw_printf("[%s:%u] Dwarf-based stackwalking, using local address 0x%lx from 0x%lx - 0x%lx\n",
225              FILE__, __LINE__, pc, in.getRA(), lib.second);
226    if (in.getRALocation().location != loc_register && !in.nonCall()) {
227       /**
228        * If we're here, then our in.getRA() should be pointed at the
229        * instruction following a call.  We could either use the
230        * call instruction's debug info (pc - 1) or the following
231        * instruction's debug info (pc) to continue the stackwalk.
232        *
233        * In most cases it doesn't matter.  Because of how DWARF debug
234        * info is defined, the stack doesn't change between these two points.
235        *
236        * However, if the call is a non-returning call (e.g, a call to exit)
237        * then the next instruction may not exist or may be part of a separate
238        * block with different debug info.  In these cases we want to use the
239        * debug info associated with the call.  So, we subtract 1 from the
240        * pc to get at the call instruction.
241        **/
242       pc = pc - 1;
243    }
244
245    /**
246     * Some system libraries on some systems have their debug info split
247     * into separate files, usually in /usr/lib/debug/.  Check these
248     * for DWARF debug info
249     **/
250    DwarfFrameParser::Ptr dauxinfo = getAuxDwarfInfo(lib.first);
251    if (!dauxinfo || !dauxinfo->hasFrameDebugInfo()) {
252       sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
253                  FILE__, __LINE__, lib.first.c_str());
254       return gcf_not_me;
255    }
256
257    bool isVsyscallPage = false;
258 #if defined(os_linux)
259    sw_printf("ARM-debug: dump lib========================\n");
260    sw_printf("%s\n", lib.first.c_str());
261    sw_printf("ARM-debug: dump lib========================\n");
262    isVsyscallPage = (strstr(lib.first.c_str(), "[vsyscall-") != NULL);
263 #endif
264
265    sw_printf("[%s:%u] - Using DWARF debug file info for %s\n",
266                    FILE__, __LINE__, lib.first.c_str());
267    cur_frame = &in;
268    gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dauxinfo, isVsyscallPage);
269    cur_frame = NULL;
270
271    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(out.getRA(), lib);
272    if (!result) return gcf_not_me;
273
274    if (gcresult == gcf_success) {
275       sw_printf("[%s:%u] - Success walking with DWARF aux file\n",
276                 FILE__, __LINE__);
277       return gcf_success;
278    }
279
280    return gcresult;
281 }
282
283 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
284 {
285    addr_width = group->getWalker()->getProcessState()->getAddressWidth();
286    if (addr_width == 4)
287       group->addStepper(parent_stepper, 0, 0xffffffff);
288 #if defined(arch_64bit)
289    else if (addr_width == 8)
290       group->addStepper(parent_stepper, 0, 0xffffffffffffffff);
291 #endif
292    else
293       assert(0 && "Unknown architecture word size");
294 }
295
296 unsigned DebugStepperImpl::getPriority() const
297 {
298    return debugstepper_priority;
299 }
300
301 DebugStepperImpl::~DebugStepperImpl()
302 {
303 }
304
305 #if defined(arch_x86) || defined(arch_x86_64)
306 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in,
307                                                    Frame &out, DwarfFrameParser::Ptr dinfo,
308                                                    bool isVsyscallPage)
309 {
310    MachRegisterVal frame_value, stack_value, ret_value;
311    bool result;
312    FrameErrors_t frame_error = FE_No_Error;
313
314    addr_width = getProcessState()->getAddressWidth();
315
316    depth_frame = cur_frame;
317
318    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
319                                       ret_value, this, frame_error);
320
321    if (!result && frame_error == FE_No_Frame_Entry && isVsyscallPage) {
322       //Work-around kernel bug.  The vsyscall page location was randomized, but
323       // the debug info still has addresses from the old, pre-randomized days.
324       // See if we get any hits by assuming the address corresponds to the
325       // old PC.
326       pc += 0xffffe000;
327       result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
328                                          ret_value, this, frame_error);
329    }
330    if (!result) {
331       sw_printf("[%s:%u] - Couldn't get return debug info at %lx, error: %u\n",
332                 FILE__, __LINE__, in.getRA(), frame_error);
333       return gcf_not_me;
334    }
335    location_t ra_loc = getLastComputedLocation(ret_value);
336
337    Dyninst::MachRegister frame_reg;
338    if (addr_width == 4)
339       frame_reg = x86::ebp;
340    else
341       frame_reg = x86_64::rbp;
342
343    result = dinfo->getRegValueAtFrame(pc, frame_reg,
344                                       frame_value, this, frame_error);
345    if (!result) {
346       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
347                  FILE__, __LINE__, in.getRA());
348       return gcf_not_me;
349    }
350    location_t fp_loc = getLastComputedLocation(frame_value);
351
352    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
353                                       stack_value, this, frame_error);
354    if (!result) {
355       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
356                  FILE__, __LINE__, in.getRA());
357       return gcf_not_me;
358    }
359    location_t sp_loc = getLastComputedLocation(stack_value);
360
361    if (isVsyscallPage) {
362       // RHEL6 has broken DWARF in the vsyscallpage; it has
363       // a double deref for the stack pointer. We detect this
364       // (as much as we can...) and ignore it
365       if (stack_value < in.getSP()) {
366          stack_value = 0;
367          sp_loc.location = loc_unknown;
368       }
369    }
370
371    Address MAX_ADDR;
372    if (addr_width == 4) {
373        MAX_ADDR = 0xffffffff;
374    }
375 #if defined(arch_64bit)
376    else if (addr_width == 8){
377        MAX_ADDR = 0xffffffffffffffff;
378    }
379 #endif
380    else {
381        assert(0 && "Unknown architecture word size");
382    }
383
384    if(ra_loc.val.addr > MAX_ADDR || fp_loc.val.addr > MAX_ADDR || sp_loc.val.addr > MAX_ADDR) return gcf_not_me;
385
386    out.setRA(ret_value);
387    out.setFP(frame_value);
388    out.setSP(stack_value);
389    out.setRALocation(ra_loc);
390    out.setFPLocation(fp_loc);
391    out.setSPLocation(sp_loc);
392
393    addToCache(in, out);
394
395    return gcf_success;
396 }
397
398 void DebugStepperImpl::addToCache(const Frame &cur, const Frame &caller) {
399   const location_t &calRA = caller.getRALocation();
400
401   const location_t &calFP = caller.getFPLocation();
402
403   unsigned raDelta = (unsigned) -1;
404   unsigned fpDelta = (unsigned) -1;
405   unsigned spDelta = (unsigned) -1;
406
407   if (calRA.location == loc_address) {
408     raDelta = calRA.val.addr - cur.getSP();
409   }
410
411   if (calFP.location == loc_address) {
412     fpDelta = calFP.val.addr - cur.getSP();
413   }
414
415   spDelta = caller.getSP() - cur.getSP();
416
417   cache_[cur.getRA()] = cache_t(raDelta, fpDelta, spDelta);
418 }
419
420 bool DebugStepperImpl::lookupInCache(const Frame &cur, Frame &caller) {
421   dyn_hash_map<Address,cache_t>::iterator iter = cache_.find(cur.getRA());
422   if (iter == cache_.end()) {
423       return false;
424   }
425
426   addr_width = getProcessState()->getAddressWidth();
427
428   if (iter->second.ra_delta == (unsigned) -1) {
429       return false;
430   }
431   if (iter->second.fp_delta == (unsigned) -1) {
432     return false;
433   }
434   assert(iter->second.sp_delta != (unsigned) -1);
435
436   Address MAX_ADDR;
437    if (addr_width == 4) {
438        MAX_ADDR = 0xffffffff;
439    }
440 #if defined(arch_64bit)
441    else if (addr_width == 8){
442        MAX_ADDR = 0xffffffffffffffff;
443    }
444 #endif
445    else {
446        assert(0 && "Unknown architecture word size");
447        return false;
448    }
449
450   location_t RA;
451   RA.location = loc_address;
452   RA.val.addr = cur.getSP() + iter->second.ra_delta;
453   RA.val.addr %= MAX_ADDR;
454
455   location_t FP;
456   FP.location = loc_address;
457   FP.val.addr = cur.getSP() + iter->second.fp_delta;
458
459   FP.val.addr %= MAX_ADDR;
460   int buffer[10];
461
462   caller.setRALocation(RA);
463   ReadMem(RA.val.addr, buffer, addr_width);
464   caller.setRA(last_val_read);
465
466   caller.setFPLocation(FP);
467   ReadMem(FP.val.addr, buffer, addr_width);
468   caller.setFP(last_val_read);
469
470   caller.setSP(cur.getSP() + iter->second.sp_delta);
471
472   return true;
473 }
474
475 #endif
476
477 // for aarch64 architecure specifically
478 #if defined(arch_aarch64)
479 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in,
480                                                    Frame &out, DwarfFrameParser::Ptr dinfo,
481                                                    bool isVsyscallPage)
482 {
483    MachRegisterVal frame_value, stack_value, ret_value;
484    bool result;
485    FrameErrors_t frame_error = FE_No_Error;
486
487    addr_width = getProcessState()->getAddressWidth();
488
489    depth_frame = cur_frame;
490
491    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
492    //result = dinfo->getRegValueAtFrame(pc, Dyninst::aarch64::x30,
493                                       ret_value, this, frame_error);
494
495    if (!result && frame_error == FE_No_Frame_Entry && isVsyscallPage) {
496       //Work-around kernel bug.  The vsyscall page location was randomized, but
497       // the debug info still has addresses from the old, pre-randomized days.
498       // See if we get any hits by assuming the address corresponds to the
499       // old PC.
500       pc += 0xffffe000;
501       result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
502                                          ret_value, this, frame_error);
503    }
504    if (!result) {
505       sw_printf("[%s:%u] - Couldn't get return debug info at %lx, error: %u\n",
506                 FILE__, __LINE__, in.getRA(), frame_error);
507       return gcf_not_me;
508    }
509    location_t ra_loc = getLastComputedLocation(ret_value);
510
511    Dyninst::MachRegister frame_reg;
512    frame_reg = Dyninst::aarch64::x29;
513
514    result = dinfo->getRegValueAtFrame(pc, frame_reg,
515                                       frame_value, this, frame_error);
516    if (!result) {
517       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
518                  FILE__, __LINE__, in.getRA());
519       return gcf_not_me;
520    }
521    location_t fp_loc = getLastComputedLocation(frame_value);
522
523    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
524                                       stack_value, this, frame_error);
525    if (!result) {
526       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
527                  FILE__, __LINE__, in.getRA());
528       return gcf_not_me;
529    }
530    location_t sp_loc = getLastComputedLocation(stack_value);
531
532    if (isVsyscallPage) {
533       // RHEL6 has broken DWARF in the vsyscallpage; it has
534       // a double deref for the stack pointer. We detect this
535       // (as much as we can...) and ignore it
536       if (stack_value < in.getSP()) {
537          stack_value = 0;
538          sp_loc.location = loc_unknown;
539       }
540    }
541
542    Address MAX_ADDR;
543    if (addr_width == 4) {
544        MAX_ADDR = 0xffffffff;
545    }
546    else if (addr_width == 8){
547        MAX_ADDR = 0xffffffffffffffff;
548    }
549    else {
550        assert(0 && "Unknown architecture word size");
551    }
552
553    if(ra_loc.val.addr > MAX_ADDR || fp_loc.val.addr > MAX_ADDR || sp_loc.val.addr > MAX_ADDR) return gcf_not_me;
554
555    out.setRA(ret_value);
556    out.setFP(frame_value);
557    out.setSP(stack_value);
558    out.setRALocation(ra_loc);
559    out.setFPLocation(fp_loc);
560    out.setSPLocation(sp_loc);
561
562    addToCache(in, out);
563
564    return gcf_success;
565 }
566
567 void DebugStepperImpl::addToCache(const Frame &cur, const Frame &caller) {
568   const location_t &calRA = caller.getRALocation();
569
570   const location_t &calFP = caller.getFPLocation();
571
572   unsigned raDelta = (unsigned) -1;
573   unsigned fpDelta = (unsigned) -1;
574   unsigned spDelta = (unsigned) -1;
575
576   if (calRA.location == loc_address) {
577     raDelta = calRA.val.addr - cur.getSP();
578   }
579
580   if (calFP.location == loc_address) {
581     fpDelta = calFP.val.addr - cur.getSP();
582   }
583
584   spDelta = caller.getSP() - cur.getSP();
585
586   cache_[cur.getRA()] = cache_t(raDelta, fpDelta, spDelta);
587 }
588
589 bool DebugStepperImpl::lookupInCache(const Frame &cur, Frame &caller) {
590   dyn_hash_map<Address,cache_t>::iterator iter = cache_.find(cur.getRA());
591   if (iter == cache_.end()) {
592       return false;
593   }
594
595   addr_width = getProcessState()->getAddressWidth();
596
597   if (iter->second.ra_delta == (unsigned) -1) {
598       return false;
599   }
600   if (iter->second.fp_delta == (unsigned) -1) {
601     return false;
602   }
603   assert(iter->second.sp_delta != (unsigned) -1);
604
605   Address MAX_ADDR;
606    if (addr_width == 4) {
607        assert(0);
608        MAX_ADDR = 0xffffffff;
609    }
610 #if defined(arch_64bit)
611    else if (addr_width == 8){
612        MAX_ADDR = 0xffffffffffffffff;
613    }
614 #endif
615    else {
616        assert(0 && "Unknown architecture word size");
617        return false;
618    }
619
620   location_t RA;
621   RA.location = loc_address;
622   RA.val.addr = cur.getSP() + iter->second.ra_delta;
623   RA.val.addr %= MAX_ADDR;
624
625   location_t FP;
626   FP.location = loc_address;
627   FP.val.addr = cur.getSP() + iter->second.fp_delta;
628
629   FP.val.addr %= MAX_ADDR;
630   int buffer[10];
631
632   caller.setRALocation(RA);
633   ReadMem(RA.val.addr, buffer, addr_width);
634   caller.setRA(last_val_read);
635
636   caller.setFPLocation(FP);
637   ReadMem(FP.val.addr, buffer, addr_width);
638   caller.setFP(last_val_read);
639
640   caller.setSP(cur.getSP() + iter->second.sp_delta);
641
642   return true;
643 }
644 #endif
645 //end if defined aarch64
646