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