StackwalkerAPI fixes for working with new register class
[dyninst.git] / stackwalk / src / x86-swk.C
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
32 #include "stackwalk/h/basetypes.h"
33 #include "stackwalk/h/swk_errors.h"
34 #include "stackwalk/h/procstate.h"
35 #include "stackwalk/h/framestepper.h"
36 #include "stackwalk/h/frame.h"
37 #include "stackwalk/h/walker.h"
38
39 #include "stackwalk/src/symtab-swk.h"
40 #include "stackwalk/src/dbgstepper-impl.h"
41 #include "stackwalk/src/x86-swk.h"
42 #include "stackwalk/src/sw.h"
43 #include "symtabAPI/h/Function.h"
44
45 #if defined(cap_cache_func_starts)
46 #include "common/h/lru_cache.h"
47 #endif
48
49 using namespace Dyninst;
50 using namespace Dyninst::Stackwalker;
51
52 bool ProcSelf::getRegValue(Dyninst::MachRegister reg, THR_ID, Dyninst::MachRegisterVal &val)
53 {
54   unsigned long *frame_pointer;
55
56 #if defined(arch_x86_64) && defined(os_linux)
57   __asm__("mov %%rbp, %0\n"
58           : "=r"(frame_pointer));
59 #elif defined(os_linux)
60   __asm__("movl %%ebp, %0\n"
61           : "=r"(frame_pointer));
62 #elif defined(os_windows)
63    __asm
64    {
65       mov frame_pointer, ebp ;
66    }   
67 #endif
68
69   frame_pointer = (unsigned long *) *frame_pointer;
70   
71   switch(reg.val())
72   {
73      case Dyninst::x86_64::irip:
74      case Dyninst::x86::ieip:
75      case Dyninst::iReturnAddr:
76         val = (Dyninst::MachRegisterVal) frame_pointer[1];
77         break;
78      case Dyninst::iFrameBase:
79         val = (Dyninst::MachRegisterVal) frame_pointer[0];
80         break;
81      case Dyninst::x86_64::irsp:
82      case Dyninst::x86::iesp:
83      case Dyninst::iStackTop:
84         val = (Dyninst::MachRegisterVal) (frame_pointer + 2);
85         break;      
86      default:
87         sw_printf("[%s:%u] - Request for unsupported register %s\n",
88                   __FILE__, __LINE__, reg.name());
89         setLastError(err_badparam, "Unknown register passed in reg field");
90   }
91
92   return true;
93 }
94
95 static gcframe_ret_t HandleStandardFrame(const Frame &in, Frame &out, ProcessState *proc)
96 {
97   Address in_fp, out_sp;
98   const unsigned addr_width = proc->getAddressWidth();
99   bool result;
100
101   struct {
102     Address out_fp;
103     Address out_ra;
104   } ra_fp_pair;
105
106   in_fp = in.getFP();
107   out_sp = in_fp + addr_width;
108
109 #if defined(arch_x86_64)
110   /**
111    * On AMD64 we may be reading from a process with a different
112    * address width than the current one.  We'll do the read at
113    * the correct size, then convert the addresses into the 
114    * local size
115    **/
116   struct {
117      unsigned out_fp;
118      unsigned out_ra;
119   } ra_fp_pair32;
120   if (addr_width != sizeof(Address))
121   {
122      result = proc->readMem(&ra_fp_pair32, in_fp, 
123                             sizeof(ra_fp_pair32));
124      ra_fp_pair.out_fp = (Address) ra_fp_pair32.out_fp;
125      ra_fp_pair.out_ra = (Address) ra_fp_pair32.out_ra;
126   }
127   else
128 #endif
129   {
130     result = proc->readMem(&ra_fp_pair, in_fp, sizeof(ra_fp_pair));
131   }
132
133   if (!result) {
134     sw_printf("[%s:%u] - Couldn't read from %lx\n", __FILE__, __LINE__, out_sp);
135     return gcf_error;
136   }
137   
138   if (!ra_fp_pair.out_ra) {
139      return gcf_not_me;
140   }
141
142   out.setFP(ra_fp_pair.out_fp);
143   out.setRA(ra_fp_pair.out_ra);
144   out.setSP(out_sp);
145
146   return gcf_success;
147 }
148
149 bool Walker::checkValidFrame(const Frame &in, const Frame &out)
150 {
151    if (out.getSP() <= in.getSP()) {
152       sw_printf("[%s:%u] - Stackwalk went backwards, %lx to %lx\n",
153                 __FILE__, __LINE__, in.getSP(), out.getSP());
154       return false;
155    }
156    return true;
157 }
158
159 gcframe_ret_t FrameFuncStepperImpl::getCallerFrame(const Frame &in, Frame &out)
160 {
161   if (!in.getFP())
162      return gcf_not_me;
163
164   FrameFuncHelper::alloc_frame_t frame = helper->allocatesFrame(in.getRA());
165   if (frame.first != FrameFuncHelper::standard_frame) {
166      return gcf_not_me;
167   }
168
169   return HandleStandardFrame(in, out, getProcessState());
170 }
171  
172 std::map<Dyninst::PID, LookupFuncStart*> LookupFuncStart::all_func_starts;
173
174 #if defined(cap_cache_func_starts)
175 static int hash_address(Address a)
176 {
177    return (int) a;
178 }
179 #endif
180
181 LookupFuncStart::LookupFuncStart(ProcessState *proc_) :
182    FrameFuncHelper(proc_)
183 #if defined(cap_cache_func_starts)
184    , cache(cache_size, hash_address)
185 #endif
186 {
187    all_func_starts[proc->getProcessId()] = this;
188    ref_count = 1;
189 }
190
191 LookupFuncStart::~LookupFuncStart()
192 {
193    Dyninst::PID pid = proc->getProcessId();
194    all_func_starts.erase(pid);
195 }
196
197 LookupFuncStart *LookupFuncStart::getLookupFuncStart(ProcessState *p)
198 {
199    Dyninst::PID pid = p->getProcessId();
200    std::map<Dyninst::PID, LookupFuncStart*>::iterator i = all_func_starts.find(pid);
201    if (i == all_func_starts.end()) {
202       return new LookupFuncStart(p);
203    }
204    (*i).second->ref_count++;
205    return (*i).second;
206 }
207
208 void LookupFuncStart::releaseMe()
209 {
210    ref_count--;
211    if (!ref_count)
212       delete this;
213 }
214
215 FrameFuncStepperImpl::FrameFuncStepperImpl(Walker *w, FrameStepper *parent_,
216                                            FrameFuncHelper *helper_) :
217    FrameStepper(w),
218    parent(parent_),
219    helper(helper_)
220 {
221    helper = helper_ ? helper_ : LookupFuncStart::getLookupFuncStart(getProcessState());
222 }
223
224 FrameFuncStepperImpl::~FrameFuncStepperImpl()
225 {
226    LookupFuncStart *lookup = dynamic_cast<LookupFuncStart*>(helper);
227    if (lookup)
228       lookup->releaseMe();
229    else if (helper)
230       delete helper;
231 }
232
233 unsigned FrameFuncStepperImpl::getPriority() const
234 {
235   return frame_priority;
236 }
237
238 #if defined(cap_stackwalker_use_symtab)
239
240 /**
241  * Look at the first few bytes in the function and see if they contain
242  * the standard set to allocate a stack frame.
243  **/
244 #define FUNCTION_PROLOG_TOCHECK 12
245 static unsigned char push_ebp = 0x55;
246 static unsigned char mov_esp_ebp[2][2] = { { 0x89, 0xe5 },
247                                            { 0x8b, 0xec } };
248 static unsigned char rex_mov_esp_ebp = 0x48;
249
250 FrameFuncHelper::alloc_frame_t LookupFuncStart::allocatesFrame(Address addr)
251 {
252    LibAddrPair lib;
253    Symtab *symtab = NULL;
254    SymtabAPI::Function *func = NULL;
255    unsigned char mem[FUNCTION_PROLOG_TOCHECK];
256    Address func_addr;
257    unsigned cur;
258    int push_ebp_pos = -1, mov_esp_ebp_pos = -1;
259    alloc_frame_t res = alloc_frame_t(unknown_t, unknown_s);
260    bool result;
261
262    result = checkCache(addr, res);
263    if (result) {
264       sw_printf("[%s:%u] - Cached value for %lx is %d/%d\n",
265                 __FILE__, __LINE__, addr, (int) res.first, (int) res.second);
266       return res;
267    }
268
269    result = proc->getLibraryTracker()->getLibraryAtAddr(addr, lib);
270    if (!result)
271    {
272       sw_printf("[%s:%u] - No library at %lx\n", __FILE__, __LINE__, addr);
273       goto done;
274    }
275
276    symtab = SymtabWrapper::getSymtab(lib.first);
277    if (!symtab) {
278       sw_printf("[%s:%u] - Error. SymtabAPI couldn't open %s\n",
279                 __FILE__, __LINE__, lib.first.c_str());
280       goto done;
281    }
282
283    result = symtab->getContainingFunction(addr - lib.second, func);
284    if (!result || !func) {
285       sw_printf("[%s:%u] - Error.  Address %lx wasn't part of a function\n",
286                 __FILE__, __LINE__, addr);
287       goto done;
288    }
289    func_addr = func->getOffset() + lib.second;
290    
291    result = proc->readMem(mem, func_addr, FUNCTION_PROLOG_TOCHECK);
292    if (!result) {
293       sw_printf("[%s:%u] - Error.  Couldn't read from memory at %lx\n",
294                 __FILE__, __LINE__, func_addr);
295       goto done;
296    }
297    
298    //Try to find a 'push (r|e)bp'
299    for (cur=0; cur<FUNCTION_PROLOG_TOCHECK; cur++)
300    {
301       if (mem[cur] == push_ebp)
302       {
303          push_ebp_pos = cur;
304          break;
305       }
306    }
307
308    //Try to find the mov esp->ebp
309    for (; cur<FUNCTION_PROLOG_TOCHECK; cur++)
310    {
311       if (proc->getAddressWidth() == 8) {
312          if (mem[cur] != rex_mov_esp_ebp)
313             continue;
314          cur++;
315       }
316       
317       if (cur+1 >= FUNCTION_PROLOG_TOCHECK) 
318          break;
319       if ((mem[cur] == mov_esp_ebp[0][0] && mem[cur+1] == mov_esp_ebp[0][1]) || 
320           (mem[cur] == mov_esp_ebp[1][0] && mem[cur+1] == mov_esp_ebp[1][1])) {
321          if (proc->getAddressWidth() == 8) 
322             mov_esp_ebp_pos = cur-1;
323          else
324             mov_esp_ebp_pos = cur;
325          break;
326       }
327    }
328
329    if (push_ebp_pos != -1 && mov_esp_ebp_pos != -1)
330       res.first = standard_frame;
331    else if (push_ebp_pos != -1 && mov_esp_ebp_pos == -1)
332       res.first = savefp_only_frame;
333    else 
334       res.first = no_frame;
335    
336    if (push_ebp_pos != -1 && addr <= func_addr + push_ebp_pos)
337       res.second = unset_frame;
338    else if (mov_esp_ebp_pos != -1 && addr <= func_addr + mov_esp_ebp_pos)
339       res.second = halfset_frame;
340    else
341       res.second = set_frame;
342
343  done:
344    sw_printf("[%s:%u] - Function containing %lx has frame type %d/%d\n",
345              __FILE__, __LINE__, addr, (int) res.first, (int) res.second);
346    updateCache(addr, res);
347    return res;
348 }
349
350 #if defined(cap_cache_func_starts)
351 void LookupFuncStart::updateCache(Address addr, alloc_frame_t result)
352 {
353    cache.insert(addr, result);
354 }
355
356 bool LookupFuncStart::checkCache(Address addr, alloc_frame_t &result)
357 {
358    return cache.lookup(addr, result);
359 }
360
361 #else
362 void LookupFuncStart::updateCache(Address /*addr*/, alloc_frame_t /*result*/)
363 {
364    return;
365 }
366
367 bool LookupFuncStart::checkCache(Address /*addr*/, alloc_frame_t &/*result*/)
368 {
369    return false;
370 }
371 #endif
372
373 void LookupFuncStart::clear_func_mapping(Dyninst::PID pid)
374 {
375    std::map<Dyninst::PID, LookupFuncStart *>::iterator i;
376    i = all_func_starts.find(pid);
377    if (i == all_func_starts.end())
378       return;
379
380    LookupFuncStart *fs = (*i).second;
381    all_func_starts.erase(i);
382    
383    delete fs;
384 }
385
386 gcframe_ret_t DebugStepperImpl::getCallerFrameArch(Address pc, const Frame &in, 
387                                                    Frame &out, Symtab *symtab)
388 {
389    MachRegisterVal frame_value, stack_value, ret_value;
390    bool result;
391
392    result = symtab->getRegValueAtFrame(pc, Dyninst::ReturnAddr,
393                                        ret_value, this);
394    if (!result) {
395       sw_printf("[%s:%u] - Couldn't get return debug info at %lx\n",
396                 __FILE__, __LINE__, in.getRA());
397       return gcf_not_me;
398    }
399
400    unsigned addr_width = getProcessState()->getAddressWidth();
401    
402    
403    Dyninst::MachRegister frame_reg;
404    if (addr_width == 4)
405       frame_reg = x86::ebp;
406    else
407       frame_reg = x86_64::rbp;
408
409    result = symtab->getRegValueAtFrame(pc, frame_reg,
410                                        frame_value, this);
411    if (!result) {
412       sw_printf("[%s:%u] - Couldn't get frame debug info at %lx\n",
413                  __FILE__, __LINE__, in.getRA());
414       return gcf_not_me;
415    }
416
417    result = symtab->getRegValueAtFrame(pc, Dyninst::FrameBase,
418                                        stack_value, this);
419    if (!result) {
420       sw_printf("[%s:%u] - Couldn't get stack debug info at %lx\n",
421                  __FILE__, __LINE__, in.getRA());
422       return gcf_not_me;
423    }
424
425    out.setRA(ret_value);
426    out.setFP(frame_value);
427    out.setSP(stack_value);
428
429    return gcf_success;
430 }
431 #else
432
433 FrameFuncHelper::alloc_frame_t LookupFuncStart::allocatesFrame(Address /*addr*/)
434 {
435    return FrameFuncHelper::alloc_frame_t(unknown_t, unknown_s);
436 }
437 #endif
438
439 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrameArch(const Frame &in, Frame &out, Address /*base*/, Address lib_base,
440                                                           unsigned /*size*/, unsigned stack_height)
441 {
442   gcframe_ret_t ret = HandleStandardFrame(in, out, getProcessState());
443   if (ret != gcf_success)
444     return ret;
445   out.setRA(out.getRA() + lib_base);
446   out.setSP(out.getSP() + stack_height);
447   return gcf_success;
448 }
449
450 namespace Dyninst {
451 namespace Stackwalker {
452 void getTrapInstruction(char *buffer, unsigned buf_size, 
453                         unsigned &actual_len, bool include_return)
454 {
455    if (include_return)
456    {
457       assert(buf_size >= 2);
458       buffer[0] = 0xcc; //trap
459       buffer[1] = 0xc3; //ret
460       actual_len = 2;
461       return;
462    }
463    assert(buf_size >= 1);
464    buffer[0] = 0xcc; //trap
465    actual_len = 1;
466    return;
467 }
468 }
469 }
470