Fix SW issues that cropped up in merge. Recreate deleted commits.
[dyninst.git] / stackwalk / src / dbginfo-stepper.C
1 /*
2  * Copyright (c) 1996-2011 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "stackwalk/h/framestepper.h"
33 #include "stackwalk/h/frame.h"
34 #include "stackwalk/h/procstate.h"
35 #include "stackwalk/h/swk_errors.h"
36 #include "stackwalk/h/steppergroup.h"
37 #include "stackwalk/h/walker.h"
38 #include "stackwalk/src/dbgstepper-impl.h"
39 #include "stackwalk/src/linuxbsd-swk.h"
40 #include "stackwalk/src/libstate.h"
41 #include "dynutil/h/dyntypes.h"
42 #include "common/h/Types.h"
43
44 #include "symtabAPI/h/Symtab.h"
45
46 using namespace Dyninst;
47 using namespace Stackwalker;
48
49 static std::map<std::string, DwarfSW *> dwarf_info;
50
51 typedef enum {
52    storageAddr,
53    storageReg,
54    storageRegOffset
55 } storageClass;
56
57 typedef enum {
58    storageRef,
59    storageNoRef
60 } storageRefClass;
61
62 class VariableLocation {
63 public:
64    storageClass stClass;
65    storageRefClass refClass;
66    int reg;
67    MachRegister mr_reg;
68    long frameOffset;
69    Address lowPC;
70    Address hiPC;
71 };
72
73 #include <stdarg.h>
74 #include "dwarf.h"
75 #include "libdwarf.h"
76 #include "common/h/dwarfExpr.h"
77 #include "common/h/dwarfSW.h"
78
79 #define ELF_X_NAMESPACE Stackwalker
80 #include "common/h/Elf_X.h"
81
82 static DwarfSW *ll_getDwarfInfo(Elf_X *elfx)
83 {
84    Elf *elf = elfx->e_elfp();
85    Dwarf_Debug dbg;
86    Dwarf_Error err;
87    int status = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
88    if (status != DW_DLV_OK) {
89       sw_printf("Error opening dwarf information %u (0x%x): %s\n",
90                 (unsigned) dwarf_errno(err), (unsigned) dwarf_errno(err),
91                 dwarf_errmsg(err));
92       return NULL;
93    }
94    return new DwarfSW(dbg, elfx->wordSize());
95 }
96
97 static DwarfSW *getDwarfInfo(std::string s)
98 {
99    static std::map<std::string, DwarfSW *> dwarf_info;
100    
101    std::map<std::string, DwarfSW *>::iterator i = dwarf_info.find(s);
102    if (i != dwarf_info.end())
103       return i->second;
104    
105    Elf_X *elfx = getElfHandle(s);
106    DwarfSW *result = ll_getDwarfInfo(elfx);
107    dwarf_info[s] = result;
108    return result;
109 }
110
111 static DwarfSW *getAuxDwarfInfo(std::string s)
112 {
113    static std::map<std::string, DwarfSW *> dwarf_aux_info;
114    
115    std::map<std::string, DwarfSW *>::iterator i = dwarf_aux_info.find(s);
116    if (i != dwarf_aux_info.end())
117       return i->second;
118    
119    Elf_X *orig_elf = getElfHandle(s);
120    if (!orig_elf) {
121       sw_printf("[%s:%u] - Error. Could not find elf handle for file %s\n",
122                 __FILE__, __LINE__, s.c_str());
123       dwarf_aux_info[s] = NULL;
124       return NULL;
125    }
126    
127    string dbg_name;
128    char *dbg_buffer;
129    unsigned long dbg_buffer_size;
130    bool result = orig_elf->findDebugFile(s, dbg_name, dbg_buffer, dbg_buffer_size);
131    if (!result) {
132       sw_printf("[%s:%u] - No separate debug file associated with %s\n",
133                 __FILE__, __LINE__, s.c_str());
134       dwarf_aux_info[s] = NULL;
135       return NULL;
136    }
137    
138    SymbolReaderFactory *fact = getDefaultSymbolReader();
139    SymReader *reader = fact->openSymbolReader(dbg_buffer, dbg_buffer_size);
140    if (!reader) {
141       sw_printf("[%s:%u] - Error opening symbol reader for buffer associated with %s\n",
142                 __FILE__, __LINE__, dbg_name.c_str());
143       dwarf_aux_info[s] = NULL;
144       return NULL;
145    }
146    
147    Elf_X *elfx = (Elf_X *) reader->getElfHandle();
148    DwarfSW *dresult = ll_getDwarfInfo(elfx);
149    dwarf_aux_info[s] = dresult;
150    return dresult;
151 }
152
153
154 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
155    FrameStepper(w),
156    last_addr_read(0),
157    last_val_read(0),
158    parent_stepper(parent),
159    cur_frame(NULL),
160    depth_frame(NULL)
161 {
162 }
163
164 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
165 {
166    bool result = getProcessState()->readMem(buffer, addr, size);
167    if (!result)
168       return true;
169    
170    last_addr_read = 0;
171    if (!result)
172       return false;
173    if (size != addr_width)
174       return true;
175    
176    last_addr_read = addr;
177    if (addr_width == 4) {
178       uint32_t v = *((uint32_t *) buffer);
179       last_val_read = v;
180    }
181    else if (addr_width == 8) {
182       uint64_t v = *((uint64_t *) buffer);
183       last_val_read = v;
184    }
185    else {
186       assert(0); //Unknown size
187    }
188
189    return true;
190 }
191
192 location_t DebugStepperImpl::getLastComputedLocation(unsigned long value)
193 {
194    location_t loc;
195    if (last_addr_read && last_val_read == value) {
196       loc.val.addr = last_addr_read;
197       loc.location = loc_address;
198    }
199    else {
200       loc.val.addr = 0;
201       loc.location = loc_unknown;
202    }
203    last_addr_read = 0;
204    last_val_read = 0;
205    return loc;
206 }
207
208 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
209 {
210    using namespace SymtabAPI;
211    
212    const Frame *prevDepthFrame = depth_frame;
213   
214    if (reg.isFramePointer()) {
215       val = static_cast<MachRegisterVal>(depth_frame->getFP());
216       return true;
217    }
218
219    if (reg.isStackPointer()) {
220       val = static_cast<MachRegisterVal>(depth_frame->getSP());
221       return true;
222    }
223    
224    if (reg.isPC()) {
225       val = static_cast<MachRegisterVal>(depth_frame->getRA());
226       return true;
227    }
228
229    depth_frame = depth_frame->getPrevFrame();
230    if (!depth_frame)
231    {
232       bool bres =  getProcessState()->getRegValue(reg, cur_frame->getThread(), val);
233       depth_frame = prevDepthFrame;
234       return bres;
235    }
236
237    Offset offset;
238    void *symtab_v;
239    std::string lib;
240    depth_frame->getLibOffset(lib, offset, symtab_v);
241    Symtab *symtab = (Symtab*) symtab_v;
242    if (!symtab)
243    {
244      depth_frame = prevDepthFrame;
245      return false;
246    }
247
248    bool result = symtab->getRegValueAtFrame(offset, reg, val, this);
249    depth_frame = prevDepthFrame;
250    return result;
251 }
252
253 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
254 {
255    LibAddrPair lib;
256    bool result;
257
258    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
259    if (!result) {
260       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
261                 __FILE__, __LINE__, in.getRA());
262       return gcf_stackbottom;
263    }
264
265    Address pc = in.getRA() - lib.second;
266    if (in.getRALocation().location != loc_register) {
267       /**
268        * If we're here, then our in.getRA() should be pointed at the
269        * instruction following a call.  We could either use the
270        * call instruction's debug info (pc - 1) or the following
271        * instruction's debug info (pc) to continue the stackwalk.
272        *
273        * In most cases it doesn't matter.  Because of how DWARF debug
274        * info is defined, the stack doesn't change between these two points.
275        *
276        * However, if the call is a non-returning call (e.g, a call to exit)
277        * then the next instruction may not exist or may be part of a separate
278        * block with different debug info.  In these cases we want to use the
279        * debug info associated with the call.  So, we subtract 1 from the
280        * pc to get at the call instruction.
281        **/
282       pc = pc - 1;
283    }
284
285    bool isVsyscallPage = false;
286 #if defined(os_linux)
287    isVsyscallPage = (strstr(lib.first.c_str(), "[vsyscall-") != NULL);
288 #endif
289
290    if (!isVsyscallPage)
291    {
292       /**
293        * Some system libraries on some systems have their debug info split
294        * into separate files, usually in /usr/lib/debug/.  Check these 
295        * for DWARF debug info
296        **/
297       DwarfSW *dauxinfo = getAuxDwarfInfo(lib.first);
298       if (dauxinfo && dauxinfo->hasFrameDebugInfo()) {
299          sw_printf("[%s:%u] - Using separate DWARF debug file for %s", 
300                    __FILE__, __LINE__, lib.first.c_str());
301          cur_frame = &in;
302          gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dauxinfo, false);
303          cur_frame = NULL;
304          if (gcresult == gcf_success) {
305             sw_printf("[%s:%u] - Success walking with DWARF aux file\n",
306                       __FILE__, __LINE__);
307             return gcf_success;
308          }
309       }
310    }
311    
312    /**
313     * Check the actual file for DWARF stackwalking data
314     **/
315    DwarfSW *dinfo = getDwarfInfo(lib.first);
316    if (!dinfo) {
317       sw_printf("[%s:%u] - Could not open file %s for DWARF info\n",
318                 __FILE__, __LINE__, lib.first.c_str());
319       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
320       return gcf_error;
321    }
322    if (!dinfo->hasFrameDebugInfo())
323    {
324       sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
325                  __FILE__, __LINE__, lib.first.c_str());
326       return gcf_not_me;
327    }
328
329    cur_frame = &in;
330    gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dinfo, isVsyscallPage);
331    cur_frame = NULL;
332    return gcresult;
333 }
334
335 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
336 {
337    addr_width = group->getWalker()->getProcessState()->getAddressWidth();
338    if (addr_width == 4)
339       group->addStepper(parent_stepper, 0, 0xffffffff);
340 #if defined(arch_64bit)
341    else if (addr_width == 8)
342       group->addStepper(parent_stepper, 0, 0xffffffffffffffff);
343 #endif
344    else
345       assert(0 && "Unknown architecture word size");
346 }
347
348 unsigned DebugStepperImpl::getPriority() const
349 {
350    return debugstepper_priority;
351 }
352
353 DebugStepperImpl::~DebugStepperImpl()
354 {
355 }
356
357 #if defined(arch_x86) || defined(arch_x86_64)
358 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in, 
359                                                    Frame &out, DwarfSW *dinfo,
360                                                    bool isVsyscallPage)
361 {
362    MachRegisterVal frame_value, stack_value, ret_value;
363    bool result;
364    FrameErrors_t frame_error = FE_No_Error;
365
366    Dyninst::Architecture arch;
367    addr_width = getProcessState()->getAddressWidth();
368    if (addr_width == 4)
369       arch = Dyninst::Arch_x86;
370    else
371       arch = Dyninst::Arch_x86_64;
372
373    depth_frame = cur_frame;
374
375    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
376                                       ret_value, arch, this, frame_error);
377
378    if (!result && frame_error == FE_No_Frame_Entry && isVsyscallPage) {
379       //Work-around kernel bug.  The vsyscall page location was randomized, but
380       // the debug info still has addresses from the old, pre-randomized days.
381       // See if we get any hits by assuming the address corresponds to the 
382       // old PC.
383       pc += 0xffffe000;
384       result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
385                                          ret_value, arch, this, frame_error);
386
387    }
388    if (!result) {
389       sw_printf("[%s:%u] - Couldn't get return debug info at %lx, error: %u\n",
390                 __FILE__, __LINE__, in.getRA(), frame_error);
391       return gcf_not_me;
392    }
393    location_t ra_loc = getLastComputedLocation(ret_value);
394    
395    Dyninst::MachRegister frame_reg;
396    if (addr_width == 4)
397       frame_reg = x86::ebp;
398    else
399       frame_reg = x86_64::rbp;
400
401    result = dinfo->getRegValueAtFrame(pc, frame_reg,
402                                       frame_value, arch, this, frame_error);
403    if (!result) {
404       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
405                  __FILE__, __LINE__, in.getRA());
406       return gcf_not_me;
407    }
408    location_t fp_loc = getLastComputedLocation(frame_value);
409
410    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
411                                       stack_value, arch, this, frame_error);
412    if (!result) {
413       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
414                  __FILE__, __LINE__, in.getRA());
415       return gcf_not_me;
416    }
417    location_t sp_loc = getLastComputedLocation(stack_value);   
418
419    out.setRA(ret_value);
420    out.setFP(frame_value);
421    out.setSP(stack_value);
422    out.setRALocation(ra_loc);
423    out.setFPLocation(fp_loc);
424    out.setSPLocation(sp_loc);
425
426    return gcf_success;
427 }
428 #endif
429