Initialize thrd in a new FrameNode ctor
[dyninst.git] / stackwalk / src / ppc-swk.C
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
31 #include "stackwalk/h/swk_errors.h"
32 #include "stackwalk/h/procstate.h"
33 #include "stackwalk/h/framestepper.h"
34 #include "stackwalk/h/basetypes.h"
35 #include "stackwalk/h/frame.h"
36 #include "stackwalk/h/walker.h"
37
38 #include "stackwalk/src/sw.h"
39
40 #include "get_trap_instruction.h"
41 using namespace Dyninst;
42 using namespace Dyninst::Stackwalker;
43
44 #if defined(os_linux) || defined(os_bg)
45
46 #define GET_FRAME_BASE(spr) __asm__("or %0, %%r1, %%r1\n" : "=r"(spr))
47 typedef union {
48    struct {
49       uint32_t out_fp;
50       uint32_t out_ra;
51    } pair32;
52    struct {
53       uint64_t out_fp;
54       uint64_t unused_cr;
55       uint64_t out_ra;
56    } pair64;
57 } ra_fp_pair_t;
58
59 #elif defined(os_aix)
60
61 #define GET_FRAME_BASE(spr) __asm__("or %0, 1, 1\n" : "=r"(spr))
62 typedef union {
63    struct {
64       uint32_t out_fp;
65       uint32_t unused;
66       uint32_t out_ra;
67    } pair32;
68 } ra_fp_pair_t;
69
70 #else
71
72 #error Unknown platform
73
74 #endif
75
76 bool ProcSelf::getRegValue(Dyninst::MachRegister reg, THR_ID, Dyninst::MachRegisterVal &val)
77 {
78   ra_fp_pair_t **sp;
79   ra_fp_pair_t *fp_ra;
80
81   GET_FRAME_BASE(sp);
82
83   bool found_reg = false;
84   if (reg.isStackPointer()) {
85     val = (Dyninst::MachRegisterVal) sp;
86     found_reg = true;
87   }
88
89   fp_ra = *sp;
90   if (reg.isFramePointer()) {
91      val = (Dyninst::MachRegisterVal) fp_ra;
92      found_reg = true;
93   }
94
95   if (reg.isPC() || reg == Dyninst::ReturnAddr) {
96      if (getAddressWidth() == sizeof(uint64_t)) {
97        val = fp_ra->pair64.out_ra;
98      }
99      else {
100        val = fp_ra->pair32.out_ra;
101      }
102      found_reg = true;
103   }
104
105   sw_printf("[%s:%u] - Returning value %lx for reg %s\n", 
106             __FILE__, __LINE__, val, reg.name().c_str());
107   return true;
108 }
109
110 Dyninst::Architecture ProcSelf::getArchitecture()
111 {
112    return Arch_ppc32;
113 }
114
115 bool Walker::checkValidFrame(const Frame & /*in*/, const Frame & /*out*/)
116 {
117    return true;
118 }
119
120 FrameFuncStepperImpl::FrameFuncStepperImpl(Walker *w, FrameStepper *parent_,
121                                            FrameFuncHelper *helper_) :
122    FrameStepper(w),
123    parent(parent_),
124    helper(helper_)
125 {
126 }
127
128 gcframe_ret_t FrameFuncStepperImpl::getCallerFrame(const Frame &in, Frame &out)
129 {
130   // TODO set RA location
131
132   Address in_fp, out_sp, out_ra;
133   bool result;
134
135   ra_fp_pair_t this_frame_pair;
136   ra_fp_pair_t last_frame_pair;
137   ra_fp_pair_t *actual_frame_pair_p;
138
139   unsigned addrWidth;
140
141   addrWidth = getProcessState()->getAddressWidth();
142
143   // Assume a standard frame layout if no analysis is available
144   FrameFuncHelper::alloc_frame_t alloc_frame =  make_pair(FrameFuncHelper::standard_frame,
145                                                           FrameFuncHelper::set_frame);
146
147   if (helper && in.isTopFrame())
148   {
149     alloc_frame = helper->allocatesFrame(in.getRA());
150     sw_printf("[%s:%u] - FrameFuncHelper for 0x%lx reports %d, %d\n", __FILE__, __LINE__,
151               in.getRA(), alloc_frame.first, alloc_frame.second);
152   }
153
154   if (!in.getFP())
155     return gcf_stackbottom;
156
157   in_fp = in.getFP();
158
159   out_sp = in_fp;
160   out.setSP(out_sp);
161   
162   // Read the current frame
163   if (sizeof(uint64_t) == addrWidth) {
164      result = getProcessState()->readMem(&this_frame_pair.pair64, in_fp,
165                                          sizeof(this_frame_pair.pair64));
166   }
167   else {
168      result = getProcessState()->readMem(&this_frame_pair.pair32, in_fp, 
169                                          sizeof(this_frame_pair.pair32));
170   }
171   if (!result) {
172     sw_printf("[%s:%u] - Couldn't read from %lx\n", __FILE__, __LINE__, in_fp);
173     return gcf_error;
174   }
175
176   // Read the previous frame
177   if (sizeof(uint64_t) == addrWidth) {
178     result = getProcessState()->readMem(&last_frame_pair.pair64, this_frame_pair.pair64.out_fp, 
179                                         sizeof(last_frame_pair.pair64));
180   }
181   else {
182     result = getProcessState()->readMem(&last_frame_pair.pair32, this_frame_pair.pair32.out_fp, 
183                                         sizeof(last_frame_pair.pair32));
184   }
185   if (!result) {
186     sw_printf("[%s:%u] - Couldn't read from %lx\n", __FILE__, __LINE__,
187               out.getFP());
188     return gcf_error;
189   }
190
191   // Set actual stack frame based on
192   // whether the function creates a frame or not
193   if (FrameFuncHelper::no_frame == alloc_frame.first)
194   {
195     actual_frame_pair_p = &this_frame_pair;    
196   }
197   else
198   {
199     actual_frame_pair_p = &last_frame_pair;
200   }
201
202   // Handle leaf functions
203   if (FrameFuncHelper::unset_frame == alloc_frame.second)
204   {
205     // Leaf function - does not save return address
206     // Get the RA from the PC register
207     if (sizeof(uint64_t) == addrWidth)
208     {
209       result = getProcessState()->getRegValue(ppc64::lr, in.getThread(), out_ra);
210     }
211     else
212     {
213       result = getProcessState()->getRegValue(ppc32::lr, in.getThread(), out_ra);
214     }
215     if (!result) {
216         sw_printf("[%s:%u] - Error getting PC value for thrd %d\n",
217                   __FILE__, __LINE__, (int) in.getThread());
218         return gcf_error;
219     }
220   }
221   else
222   {
223     // Function saves return address
224     if (sizeof(uint64_t) == addrWidth)
225     {
226       out_ra = actual_frame_pair_p->pair64.out_ra;
227     }
228     else {
229       out_ra = actual_frame_pair_p->pair32.out_ra;
230     }
231   }
232
233   // Set new frame pointer
234   if (FrameFuncHelper::no_frame == alloc_frame.first)
235   {
236     // frame pointer stays the same
237     out.setFP(in_fp);
238   }
239   else
240   {
241     if (sizeof(uint64_t) == addrWidth) {
242       out.setFP(this_frame_pair.pair64.out_fp); 
243     }
244     else {
245       out.setFP(this_frame_pair.pair32.out_fp);
246     }
247   }
248
249   if (!out_ra) {
250     return gcf_stackbottom;
251   }
252
253   out.setRA(out_ra);
254
255   return gcf_success;
256 }
257  
258 unsigned FrameFuncStepperImpl::getPriority() const
259 {
260    return frame_priority;
261 }
262
263 FrameFuncStepperImpl::~FrameFuncStepperImpl()
264 {
265 }
266
267 WandererHelper::WandererHelper(ProcessState *proc_) :
268    proc(proc_)
269 {
270 }
271
272 bool WandererHelper::isPrevInstrACall(Address, Address&)
273 {
274    sw_printf("[%s:%u] - Unimplemented on this platform!\n");
275    assert(0);
276    return false;
277 }
278
279 WandererHelper::pc_state WandererHelper::isPCInFunc(Address, Address)
280 {
281    sw_printf("[%s:%u] - Unimplemented on this platform!\n");
282    assert(0);
283    return unknown_s;
284 }
285
286 bool WandererHelper::requireExactMatch()
287 {
288    sw_printf("[%s:%u] - Unimplemented on this platform!\n");
289    assert(0);
290    return true;
291 }
292
293 WandererHelper::~WandererHelper()
294 {
295 }
296
297 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrameArch(const Frame &/*in*/, Frame &/*out*/, 
298                                                           Address /*base*/, Address /*lib_base*/,
299                                                           unsigned /*size*/, unsigned /*stack_height*/)
300 {
301   return gcf_not_me;
302 }
303
304 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrameArch(const Frame &in, Frame &out, 
305                                                             Address /*base*/, Address /*lib_base*/,
306                                                             unsigned /*size*/, unsigned stack_height,
307                                                             bool /* aligned */,
308                                                             Address /*orig_ra*/, bool pEntryExit)
309 {
310   bool result;
311   Address in_fp, out_ra;
312   ra_fp_pair_t ra_fp_pair;
313   location_t raLocation;
314   unsigned addrWidth;
315
316   addrWidth = getProcessState()->getAddressWidth();
317
318   if (!in.getFP())
319     return gcf_stackbottom;
320
321   in_fp = in.getFP();
322   out.setSP(in_fp);
323   
324   if (sizeof(uint64_t) == addrWidth) {
325     result = getProcessState()->readMem(&ra_fp_pair.pair64, in_fp, 
326                                         sizeof(ra_fp_pair.pair64));
327   }
328   else {
329     result = getProcessState()->readMem(&ra_fp_pair.pair32, in_fp, 
330                                         sizeof(ra_fp_pair.pair32));
331   }
332   if (!result) {
333     sw_printf("[%s:%u] - Couldn't read frame from %lx\n", __FILE__, __LINE__, in_fp);
334     return gcf_error;
335   }
336   if (sizeof(uint64_t) == addrWidth) {
337     out.setFP(ra_fp_pair.pair64.out_fp);
338   }
339   else {
340     out.setFP(ra_fp_pair.pair32.out_fp);
341   }
342   
343   raLocation.location = loc_address;
344   raLocation.val.addr = in_fp + stack_height; // stack_height is the offset to the saved RA
345   out.setRALocation(raLocation);
346   
347   // TODO make 32-bit compatible
348   result = getProcessState()->readMem(&out_ra, raLocation.val.addr, 
349                                       sizeof(out_ra));
350   if (!result) {
351     sw_printf("[%s:%u] - Couldn't read instrumentation RA from %lx\n", __FILE__, __LINE__, raLocation.val.addr);
352     return gcf_error;
353   }
354   out.setRA(out_ra);
355
356   return gcf_success;
357 }
358
359 namespace Dyninst {
360   namespace Stackwalker {
361
362     void getTrapInstruction(char *buffer, unsigned buf_size, 
363                             unsigned &actual_len, bool include_return)
364     {
365       assert(buf_size >= 4);
366       buffer[0] = 0x7d;
367       buffer[1] = 0x82;
368       buffer[2] = 0x10;
369       buffer[3] = 0x08;
370       actual_len = 4;
371       if (include_return)
372       {   
373         assert(buf_size >= 8);
374         buffer[4] = 0x4e;
375         buffer[5] = 0x80;
376         buffer[6] = 0x00;
377         buffer[7] = 0x20;
378         actual_len = 8;
379         return;
380       }
381   
382       assert(buf_size >= 1);
383       actual_len = 1;
384       return;
385     }
386   }
387 }
388