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