Fixes for accessing local variable via StackwalkerAPI
[dyninst.git] / stackwalk / src / dbginfo-stepper.C
1 /*
2  * Copyright (c) 1996-2009 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/linux-swk.h"
40 #include "dynutil/h/dyntypes.h"
41
42
43 using namespace Dyninst;
44 using namespace Stackwalker;
45
46 static std::map<std::string, DwarfSW *> dwarf_info;
47
48 typedef enum {
49    storageAddr,
50    storageReg,
51    storageRegOffset
52 } storageClass;
53
54 typedef enum {
55    storageRef,
56    storageNoRef
57 } storageRefClass;
58
59 class VariableLocation {
60 public:
61    storageClass stClass;
62    storageRefClass refClass;
63    int reg;
64    MachRegister mr_reg;
65    long frameOffset;
66    Address lowPC;
67    Address hiPC;
68 };
69
70 #include "dwarf.h"
71 #include "libdwarf.h"
72 #define setSymtabError(x) 
73 #define dwarf_printf sw_printf
74 #include "common/h/dwarfExpr.h"
75 #include "common/h/dwarfSW.h"
76 #include "common/h/Elf_X.h"
77
78 DwarfSW *getDwarfInfo(std::string s)
79 {
80    static std::map<std::string, DwarfSW *> dwarf_info;
81    std::map<std::string, DwarfSW *>::iterator i = dwarf_info.find(s);
82    if (i != dwarf_info.end())
83       return i->second;
84
85    DwarfSW *ret = NULL;
86    Elf_X *elfx = getElfHandle(s);
87    Elf *elf = elfx->e_elfp();
88    Dwarf_Debug dbg;
89    int status = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, NULL);
90    if (status != DW_DLV_OK)
91       goto done;
92    ret = new DwarfSW(dbg, elfx->wordSize());
93
94   done:
95    dwarf_info[s] = ret;
96    return ret;
97 }
98
99 DebugStepperImpl::DebugStepperImpl(Walker *w, DebugStepper *parent) :
100    FrameStepper(w),
101    parent_stepper(parent),
102    cur_frame(NULL)
103 {
104 }
105
106 bool DebugStepperImpl::ReadMem(Address addr, void *buffer, unsigned size)
107 {
108    return getProcessState()->readMem(buffer, addr, size);
109 }
110
111 bool DebugStepperImpl::GetReg(MachRegister reg, MachRegisterVal &val)
112 {
113    if (reg.isFramePointer()) {
114       val = static_cast<MachRegisterVal>(cur_frame->getFP());
115       return true;
116    }
117
118    if (reg.isStackPointer()) {
119       val = static_cast<MachRegisterVal>(cur_frame->getSP());
120       return true;
121    }
122    
123    if (reg.isPC()) {
124       val = static_cast<MachRegisterVal>(cur_frame->getRA());
125       return true;
126    }
127
128    return false;
129 }
130
131 gcframe_ret_t DebugStepperImpl::getCallerFrame(const Frame &in, Frame &out)
132 {
133    LibAddrPair lib;
134    bool result;
135
136    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
137    if (!result) {
138       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
139                 __FILE__, __LINE__, in.getRA());
140       return gcf_stackbottom;
141    }
142    
143    DwarfSW *dinfo = getDwarfInfo(lib.first);
144    if (!dinfo) {
145       sw_printf("[%s:%u] - Could not open file %s for DWARF info\n",
146                 __FILE__, __LINE__, lib.first.c_str());
147       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
148       return gcf_error;
149    }
150    if (!dinfo->hasFrameDebugInfo())
151    {
152       sw_printf("[%s:%u] - Library %s does not have stackwalking debug info\n",
153                  __FILE__, __LINE__, lib.first.c_str());
154       return gcf_not_me;
155    }   
156    Address pc = in.getRA() - lib.second;
157
158    cur_frame = &in;
159    gcframe_ret_t gcresult = getCallerFrameArch(pc, in, out, dinfo);
160    cur_frame = NULL;
161    return gcresult;
162 }
163
164 void DebugStepperImpl::registerStepperGroup(StepperGroup *group)
165 {
166    unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth();
167    if (addr_width == 4)
168       group->addStepper(parent_stepper, 0, 0xffffffff);
169 #if defined(arch_64bit)
170    else if (addr_width == 8)
171       group->addStepper(parent_stepper, 0, 0xffffffffffffffff);
172 #endif
173    else
174       assert(0 && "Unknown architecture word size");
175 }
176
177 unsigned DebugStepperImpl::getPriority() const
178 {
179    return debugstepper_priority;
180 }
181
182 DebugStepperImpl::~DebugStepperImpl()
183 {
184 }
185
186 #if defined(arch_x86) || defined(arch_x86_64)
187 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in, 
188                                                    Frame &out, DwarfSW *dinfo)
189 {
190    MachRegisterVal frame_value, stack_value, ret_value;
191    bool result;
192
193    Dyninst::Architecture arch;
194    unsigned addr_width = getProcessState()->getAddressWidth();
195    if (addr_width == 4)
196       arch = Dyninst::Arch_x86;
197    else
198       arch = Dyninst::Arch_x86_64;
199
200    result = dinfo->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
201                                       ret_value, arch, this);
202    if (!result) {
203       sw_printf("[%s:%u] - Couldn't get return debug info at %lx\n",
204                 __FILE__, __LINE__, in.getRA());
205       return gcf_not_me;
206    }
207
208  
209    
210    Dyninst::MachRegister frame_reg;
211    if (addr_width == 4)
212       frame_reg = x86::ebp;
213    else
214       frame_reg = x86_64::rbp;
215
216    result = dinfo->getRegValueAtFrame(pc, frame_reg,
217                                       frame_value, arch, this);
218    if (!result) {
219       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
220                  __FILE__, __LINE__, in.getRA());
221       return gcf_not_me;
222    }
223
224    result = dinfo->getRegValueAtFrame(pc, Dyninst::FrameBase,
225                                       stack_value, arch, this);
226    if (!result) {
227       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
228                  __FILE__, __LINE__, in.getRA());
229       return gcf_not_me;
230    }
231
232    out.setRA(ret_value);
233    out.setFP(frame_value);
234    out.setSP(stack_value);
235
236    return gcf_success;
237 }
238 #endif
239
240
241