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