Merge branch 'dyninst-master' into dyn_pc_integration
[dyninst.git] / stackwalk / h / local_var.h
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 #if !defined (local_var_h_)
32 #define local_var_h_
33
34 #include <vector>
35 #include "Symbol.h"
36 #include "Symtab.h"
37 #include "Type.h"
38 #include "Function.h"
39
40 #include "frame.h"
41 #include "procstate.h"
42 #include "walker.h"
43
44 #include <string>
45 #include <map>
46
47 using namespace Dyninst;
48 using namespace SymtabAPI;
49 using namespace Stackwalker;
50
51 static Symtab *getSymtabForName(std::string name)
52 {
53    static std::map<std::string, Symtab *> symtabs;
54    std::map<std::string, Symtab *>::iterator i;
55    
56    i = symtabs.find(name);
57    if (i != symtabs.end()) {
58       return i->second;
59    }
60
61    Symtab *obj = NULL;
62    Symtab::openFile(obj, name);
63    symtabs[name] = obj;
64    return obj;
65 }
66
67 class LVReader : public MemRegReader
68 {
69  private:
70    ProcessState *proc;
71    int current_depth;
72    std::vector<Frame> *swalk;
73    Dyninst::THR_ID thrd;
74
75    bool isFrameRegister(MachRegister reg)
76    {
77       return reg.isFramePointer();
78    }
79
80    bool isStackRegister(MachRegister reg)
81    {
82       return reg.isStackPointer();
83    }
84  public:
85
86    LVReader(ProcessState *p, int f, std::vector<Frame> *s, Dyninst::THR_ID t) :
87       proc(p),
88       current_depth(f),
89       swalk(s),
90       thrd(t)
91    {
92    }
93
94    virtual bool ReadMem(Address addr, void *buffer, unsigned size)
95    {
96       return proc->readMem(buffer, addr, size);
97    }
98
99
100    virtual bool GetReg(MachRegister reg, MachRegisterVal &val)
101    {
102       Frame &f = (*swalk)[current_depth];
103       if (isFrameRegister(reg)) {
104          val = static_cast<MachRegisterVal>(f.getFP());
105          return true;
106       }
107       if (isStackRegister(reg)) {
108          val = static_cast<MachRegisterVal>(f.getSP());
109          return true;
110       }
111       if (reg.isPC() || reg == Dyninst::ReturnAddr) {
112          val = static_cast<MachRegisterVal>(f.getRA());
113          return true;
114       }
115
116       if (!current_depth) {
117          return proc->getRegValue(reg, thrd, val);
118       }
119
120       current_depth--;
121       Frame &g = (*swalk)[current_depth];
122       Offset offset;
123       void *symtab_v;
124       std::string lib;
125       g.getLibOffset(lib, offset, symtab_v);
126       Symtab *symtab = getSymtabForName(lib);
127       if (!symtab)
128          return false;
129       
130       bool result = symtab->getRegValueAtFrame(offset, reg, val, this);
131       current_depth++;
132       return result;
133    }
134
135    virtual bool start() {
136       return true;
137    }
138    virtual bool done() {
139       return true;
140    }
141    virtual ~LVReader() {}
142 };
143
144 /**
145  * Given a StackwalkerAPI frame, return the SymtabAPI function
146  * that created the frame.
147  **/
148 static Dyninst::SymtabAPI::Function *getFunctionForFrame(Frame f)
149 {
150    Offset offset;
151    void *symtab_v;
152    std::string lib_name;
153    bool result = f.getLibOffset(lib_name, offset, symtab_v);
154    if (!result || !symtab_v)
155       return NULL;
156    Symtab *symtab = getSymtabForName(lib_name);
157    Function *func;
158    result = symtab->getContainingFunction(offset, func);
159    if (!result)
160       return NULL;
161    return func;
162 }
163
164 /**
165  * Given a frame in a stackwalk, and a local variable, get the value
166  * of that local variable in the frame.
167  *
168  * 'localVar' is the variable that we're getting the value of.
169  * 'swalk' is a stackwalk from StackwalkerAPI
170  * 'frame' is an index into swalk and notes the frame that we'll be reading
171  *   the variable from.  localVar should be part of the frame defined by
172  *   swalk[frame]
173  * 'out_buffer' is a buffer where we will write the value of the local variable.
174  * out_buffer_size should be the size of out_buffer, used to prevent buffer overflows
175  *
176  * getLocalVariableValue will return one of the following on success or error
177  **/
178 static int glvv_Success = 0;
179 static int glvv_EParam = -1;
180 static int glvv_EOutOfScope = -2;
181 static int glvv_EBufferSize = -3;
182 static int glvv_EUnknown = -4;
183
184 static int getLocalVariableValue(localVar *var, 
185                                  std::vector<Frame> &swalk, unsigned frame,
186                                  void *out_buffer, unsigned out_buffer_size)
187 {
188    bool result;
189
190    if (!var || frame < 0 || frame >= swalk.size() || !out_buffer) {
191       return glvv_EParam;
192    }
193
194    /**
195     * Find the SymtabAPI object for this frame
196     * Find the offset for this frame's RA()
197     **/
198    std::string lib_name;
199    Offset offset;
200    void *symtab_v;
201    swalk[frame].getLibOffset(lib_name, offset, symtab_v);
202    THR_ID thrd = swalk[frame].getThread();
203    ProcessState *proc = swalk[frame].getWalker()->getProcessState();
204
205    /**
206     * Find the variable location that is valid at this point.
207     **/
208    bool deref;
209    std::vector<VariableLocation> &locs = var->getLocationLists();
210    std::vector<VariableLocation>::iterator i;
211    for (i = locs.begin(); i != locs.end(); i++) {
212       if (i->lowPC <= offset && offset < i->hiPC) {
213          break;
214       }
215    }
216    if (i == locs.end()) {
217       return glvv_EOutOfScope;
218    }
219    VariableLocation &loc = *i;
220    
221    /**
222     * Interpret the variable location
223     **/
224    Address var_addr = 0;
225    deref = (loc.refClass == storageRef);
226    switch (loc.stClass) { 
227       case storageAddr:
228          var_addr = loc.frameOffset;
229          break;
230       case storageReg:
231       case storageRegOffset: {
232          MachRegisterVal reg_value;
233          MachRegister reg = loc.mr_reg;
234          if (loc.stClass == storageRegOffset && loc.reg == -1) {
235             reg = MachRegister::getFramePointer(proc->getAddressWidth() == 4 ? Arch_x86 : Arch_x86_64);
236          }
237          
238          LVReader r(proc, frame, &swalk, thrd);
239          result = r.GetReg(reg, reg_value);
240          
241          if (loc.stClass == storageReg) {
242             var_addr = reg_value;
243          }
244          else {
245             deref = true;
246             var_addr = reg_value + loc.frameOffset;
247          }
248          break;
249       }
250    }
251
252    /** 
253     * Get the size of the variable
254     **/
255    unsigned size = out_buffer_size;
256    Type *var_type = var->getType();
257    if (var_type) {
258       size = var_type->getSize();
259    }
260    if (size > out_buffer_size) {
261       return glvv_EBufferSize;
262    }
263
264    /**
265     * Read the resulting value
266     **/
267    if (deref) {
268       result = proc->readMem(out_buffer, var_addr, size);
269       if (!result) {
270          return glvv_EUnknown;
271       }
272       return glvv_Success;
273    }
274
275    if (size > sizeof(var_addr)) {
276       //Value stored in register, but larger than a register?
277       return glvv_EBufferSize;
278    }
279    memcpy(out_buffer, &var_addr, size);
280
281    return glvv_Success;
282 }
283
284 #endif