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