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