Change __FILE__ to FILE__ prints in stackwalker to shorten logs
[dyninst.git] / stackwalk / src / x86-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/basetypes.h"
32 #include "stackwalk/h/swk_errors.h"
33 #include "stackwalk/h/procstate.h"
34 #include "stackwalk/h/framestepper.h"
35 #include "stackwalk/h/frame.h"
36 #include "stackwalk/h/walker.h"
37
38 #include "stackwalk/src/symtab-swk.h"
39 #include "stackwalk/src/dbgstepper-impl.h"
40 #include "stackwalk/src/x86-swk.h"
41 #include "stackwalk/src/sw.h"
42 #include "stackwalk/src/libstate.h"
43
44 #include "common/src/lru_cache.h"
45
46 #include "common/h/SymReader.h"
47
48 using namespace Dyninst;
49 using namespace Dyninst::Stackwalker;
50
51 static volatile int always_zero = 0;
52
53 bool ProcSelf::getRegValue(Dyninst::MachRegister reg, THR_ID, Dyninst::MachRegisterVal &val)
54 {
55   unsigned long *frame_pointer = NULL;
56
57   if (always_zero) {
58      //Generate some (skipped) code involving frame_pointer before
59      // the assembly snippet.  This keeps gcc from optimizing 
60      // the below snippet by pulling it up into the function prolog.
61      sw_printf("%p%p\n", frame_pointer, &frame_pointer);
62   }
63
64 #if defined(arch_x86_64) && (defined(os_linux) || defined(os_freebsd))
65   __asm__("mov %%rbp, %0\n"
66           : "=r"(frame_pointer));
67 #elif defined(os_linux) || defined(os_freebsd)
68   __asm__("movl %%ebp, %0\n"
69           : "=r"(frame_pointer));
70 #elif defined(os_windows)
71    __asm
72    {
73       mov frame_pointer, ebp ;
74    }   
75 #endif
76
77   frame_pointer = (unsigned long *) *frame_pointer;
78   
79   switch(reg.val())
80   {
81      case Dyninst::x86_64::irip:
82      case Dyninst::x86::ieip:
83      case Dyninst::iReturnAddr:
84         val = (Dyninst::MachRegisterVal) frame_pointer[1];
85         break;
86      case Dyninst::iFrameBase:
87         val = (Dyninst::MachRegisterVal) frame_pointer[0];
88         break;
89      case Dyninst::x86_64::irsp:
90      case Dyninst::x86::iesp:
91      case Dyninst::iStackTop:
92         val = (Dyninst::MachRegisterVal) (frame_pointer + 2);
93         break;      
94      default:
95         sw_printf("[%s:%u] - Request for unsupported register %s\n",
96                   FILE__, __LINE__, reg.name().c_str());
97         setLastError(err_badparam, "Unknown register passed in reg field");
98   }
99
100   return true;
101 }
102
103 Dyninst::Architecture ProcSelf::getArchitecture()
104 {
105    if (sizeof(void *) == 8)
106       return Arch_x86_64;
107    return Arch_x86;
108 }
109
110 static gcframe_ret_t HandleStandardFrame(const Frame &in, Frame &out, ProcessState *proc)
111 {
112   Address in_fp, out_sp;
113   const unsigned addr_width = proc->getAddressWidth();
114   bool result;
115
116   struct {
117     Address out_fp;
118     Address out_ra;
119   } ra_fp_pair;
120
121   in_fp = in.getFP();
122   out_sp = in_fp + (2 * addr_width);
123
124 #if defined(arch_x86_64)
125   /**
126    * On AMD64 we may be reading from a process with a different
127    * address width than the current one.  We'll do the read at
128    * the correct size, then convert the addresses into the 
129    * local size
130    **/
131   struct {
132      unsigned out_fp;
133      unsigned out_ra;
134   } ra_fp_pair32;
135   if (addr_width != sizeof(Address))
136   {
137      result = proc->readMem(&ra_fp_pair32, in_fp, 
138                             sizeof(ra_fp_pair32));
139      ra_fp_pair.out_fp = (Address) ra_fp_pair32.out_fp;
140      ra_fp_pair.out_ra = (Address) ra_fp_pair32.out_ra;
141   }
142   else
143 #endif
144   {
145     result = proc->readMem(&ra_fp_pair, in_fp, sizeof(ra_fp_pair));
146   }
147
148   if (!result) {
149     sw_printf("[%s:%u] - Couldn't read from %lx\n", FILE__, __LINE__, in_fp);
150     return gcf_error;
151   }
152   
153   if (!ra_fp_pair.out_ra) {
154      return gcf_not_me;
155   }
156
157   location_t ra_loc, fp_loc;
158   ra_loc.location = loc_address;
159   fp_loc.location = loc_address;
160   ra_loc.val.addr = in_fp + addr_width;
161   fp_loc.val.addr = in_fp + addr_width*2;
162
163   out.setFP(ra_fp_pair.out_fp);
164   out.setRA(ra_fp_pair.out_ra);
165   out.setSP(out_sp);
166   out.setFPLocation(fp_loc);
167   out.setRALocation(ra_loc);
168
169   return gcf_success;
170 }
171
172 bool Walker::checkValidFrame(const Frame &in, const Frame &out)
173 {
174    if (out.getSP() <= in.getSP() && out.getSPLocation().location != loc_unknown) {
175       sw_printf("[%s:%u] - Stackwalk went backwards, %lx to %lx\n",
176                 FILE__, __LINE__, in.getSP(), out.getSP());
177       return false;
178    }
179    return true;
180 }
181
182 gcframe_ret_t FrameFuncStepperImpl::getCallerFrame(const Frame &in, Frame &out)
183 {
184   if (!in.getFP())
185      return gcf_not_me;
186
187   FrameFuncHelper::alloc_frame_t frame = helper->allocatesFrame(in.getRA());
188   if (frame.first != FrameFuncHelper::standard_frame) {
189      return gcf_not_me;
190   }
191
192   return HandleStandardFrame(in, out, getProcessState());
193 }
194  
195 std::map<Dyninst::PID, LookupFuncStart*> LookupFuncStart::all_func_starts;
196
197 static int hash_address(Address a)
198 {
199    return (int) a;
200 }
201
202 LookupFuncStart::LookupFuncStart(ProcessState *proc_) :
203    FrameFuncHelper(proc_),
204    cache(cache_size, hash_address)
205 {
206    all_func_starts[proc->getProcessId()] = this;
207    ref_count = 1;
208 }
209
210 LookupFuncStart::~LookupFuncStart()
211 {
212    Dyninst::PID pid = proc->getProcessId();
213    all_func_starts.erase(pid);
214 }
215
216 LookupFuncStart *LookupFuncStart::getLookupFuncStart(ProcessState *p)
217 {
218    Dyninst::PID pid = p->getProcessId();
219    std::map<Dyninst::PID, LookupFuncStart*>::iterator i = all_func_starts.find(pid);
220    if (i == all_func_starts.end()) {
221       return new LookupFuncStart(p);
222    }
223    (*i).second->ref_count++;
224    return (*i).second;
225 }
226
227 void LookupFuncStart::releaseMe()
228 {
229    ref_count--;
230    if (!ref_count)
231       delete this;
232 }
233
234 FrameFuncStepperImpl::FrameFuncStepperImpl(Walker *w, FrameStepper *parent_,
235                                            FrameFuncHelper *helper_) :
236    FrameStepper(w),
237    parent(parent_),
238    helper(helper_)
239 {
240    helper = helper_ ? helper_ : LookupFuncStart::getLookupFuncStart(getProcessState());
241 }
242
243 FrameFuncStepperImpl::~FrameFuncStepperImpl()
244 {
245    LookupFuncStart *lookup = dynamic_cast<LookupFuncStart*>(helper);
246    if (lookup)
247       lookup->releaseMe();
248    else if (helper)
249       delete helper;
250 }
251
252 unsigned FrameFuncStepperImpl::getPriority() const
253 {
254   return frame_priority;
255 }
256
257 /**
258  * Look at the first few bytes in the function and see if they contain
259  * the standard set to allocate a stack frame.
260  **/
261 #define FUNCTION_PROLOG_TOCHECK 16
262 static unsigned char push_ebp = 0x55;
263 static unsigned char mov_esp_ebp[2][2] = { { 0x89, 0xe5 },
264                                            { 0x8b, 0xec } };
265 static unsigned char rex_mov_esp_ebp = 0x48;
266
267 FrameFuncHelper::alloc_frame_t LookupFuncStart::allocatesFrame(Address addr)
268 {
269    LibAddrPair lib;
270    unsigned char mem[FUNCTION_PROLOG_TOCHECK];
271    Address func_addr;
272    unsigned cur;
273    int push_ebp_pos = -1, mov_esp_ebp_pos = -1;
274    alloc_frame_t res = alloc_frame_t(unknown_t, unknown_s);
275    bool result;
276    SymReader *reader;
277    Offset off;
278    Symbol_t sym;
279
280    result = checkCache(addr, res);
281    if (result) {
282       sw_printf("[%s:%u] - Cached value for %lx is %d/%d\n",
283                 FILE__, __LINE__, addr, (int) res.first, (int) res.second);
284       return res;
285    }
286
287    result = proc->getLibraryTracker()->getLibraryAtAddr(addr, lib);
288    if (!result)
289    {
290       sw_printf("[%s:%u] - No library at %lx\n", FILE__, __LINE__, addr);
291       goto done;
292    }
293
294    reader = LibraryWrapper::getLibrary(lib.first);
295    if (!reader) {
296       sw_printf("[%s:%u] - Failed to open symbol reader %s\n",
297                 FILE__, __LINE__, lib.first.c_str() );
298       goto done;
299    }   
300    off = addr - lib.second;
301    sym = reader->getContainingSymbol(off);
302    if (!reader->isValidSymbol(sym)) {
303       sw_printf("[%s:%u] - Could not find symbol in binary\n", FILE__, __LINE__);
304       goto done;
305    }
306    func_addr = reader->getSymbolOffset(sym) + lib.second;
307
308    result = proc->readMem(mem, func_addr, FUNCTION_PROLOG_TOCHECK);
309    if (!result) {
310       sw_printf("[%s:%u] - Error.  Couldn't read from memory at %lx\n",
311                 FILE__, __LINE__, func_addr);
312       goto done;
313    }
314    
315    //Try to find a 'push (r|e)bp'
316    for (cur=0; cur<FUNCTION_PROLOG_TOCHECK; cur++)
317    {
318       if (mem[cur] == push_ebp)
319       {
320          push_ebp_pos = cur;
321          break;
322       }
323    }
324
325    //Try to find the mov esp->ebp
326    for (; cur<FUNCTION_PROLOG_TOCHECK; cur++)
327    {
328       if (proc->getAddressWidth() == 8) {
329          if (mem[cur] != rex_mov_esp_ebp)
330             continue;
331          cur++;
332       }
333       
334       if (cur+1 >= FUNCTION_PROLOG_TOCHECK) 
335          break;
336       if ((mem[cur] == mov_esp_ebp[0][0] && mem[cur+1] == mov_esp_ebp[0][1]) || 
337           (mem[cur] == mov_esp_ebp[1][0] && mem[cur+1] == mov_esp_ebp[1][1])) {
338          if (proc->getAddressWidth() == 8) 
339             mov_esp_ebp_pos = cur-1;
340          else
341             mov_esp_ebp_pos = cur;
342          break;
343       }
344    }
345
346    if ((push_ebp_pos != -1) && (mov_esp_ebp_pos != -1))
347       res.first = standard_frame;
348    else if ((push_ebp_pos != -1) && (mov_esp_ebp_pos == -1))
349       res.first = savefp_only_frame;
350    else 
351       res.first = no_frame;
352    
353    if ((push_ebp_pos != -1) && (addr <= func_addr + push_ebp_pos))
354       res.second = unset_frame;
355    else if ((mov_esp_ebp_pos != -1) && (addr <= func_addr + mov_esp_ebp_pos))
356       res.second = halfset_frame;
357    else
358       res.second = set_frame;
359
360  done:
361    sw_printf("[%s:%u] - Function containing %lx has frame type %d/%d\n",
362              FILE__, __LINE__, addr, (int) res.first, (int) res.second);
363    updateCache(addr, res);
364    return res;
365 }
366
367 void LookupFuncStart::updateCache(Address addr, alloc_frame_t result)
368 {
369    cache.insert(addr, result);
370 }
371
372 bool LookupFuncStart::checkCache(Address addr, alloc_frame_t &result)
373 {
374    return cache.lookup(addr, result);
375 }
376
377 void LookupFuncStart::clear_func_mapping(Dyninst::PID pid)
378 {
379    std::map<Dyninst::PID, LookupFuncStart *>::iterator i;
380    i = all_func_starts.find(pid);
381    if (i == all_func_starts.end())
382       return;
383
384    LookupFuncStart *fs = (*i).second;
385    all_func_starts.erase(i);
386    
387    delete fs;
388 }
389
390 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrameArch(const Frame &in, Frame &out, 
391                                                           Address /*base*/, Address lib_base,
392                                                           unsigned /*size*/, unsigned stack_height)
393 {
394   gcframe_ret_t ret = HandleStandardFrame(in, out, getProcessState());
395   if (ret != gcf_success)
396     return ret;
397   out.setRA(out.getRA() + lib_base);
398   out.setSP(out.getSP() + stack_height);
399   return gcf_success;
400 }
401
402
403 gcframe_ret_t DyninstDynamicStepperImpl::getCallerFrameArch(const Frame &in, Frame &out, 
404                                                             Address /*base*/, Address lib_base,
405                                                             unsigned /*size*/, unsigned stack_height,
406                                                             bool aligned,
407                                                             Address orig_ra, bool pEntryExit)
408 {
409   bool result = false;
410   const unsigned addr_width = getProcessState()->getAddressWidth();
411   unsigned long sp_value = 0x0;
412   Address sp_addr = 0x0;
413
414   sw_printf("[%s:%u] - DyninstDynamicStepper with lib_base 0x%lx, stack-height %d, orig_ra 0x%lx, aligned %d %s\n",
415             FILE__, __LINE__, lib_base, stack_height, orig_ra, aligned, pEntryExit ? "<entry/exit>" : "<normal>");
416   sw_printf("[%s:%u] - incoming frame has RA 0x%lx, SP 0x%lx, FP 0x%lx\n",
417             FILE__, __LINE__, in.getRA(), in.getSP(), in.getFP());
418   // Handle frameless instrumentation
419   if (0x0 != orig_ra)
420   {
421     location_t unknownLocation;
422     unknownLocation.location = loc_unknown;
423     out.setRA(orig_ra);
424     out.setFP(in.getFP());
425     out.setSP(in.getSP()); //Not really correct, but difficult to compute and unlikely to matter
426     out.setRALocation(unknownLocation);
427     sw_printf("[%s:%u] - DyninstDynamicStepper handled frameless instrumentation\n",
428               FILE__, __LINE__);
429     return gcf_success;
430   }
431
432
433   // Handle case where *previous* frame was entry/exit instrumentation
434   if (pEntryExit)
435   {
436     Address ra_value = 0x0;
437
438     // RA is pointed to by input SP
439     // TODO may have an additional offset in some cases...
440     Address newRAAddr = in.getSP();
441
442     location_t raLocation;
443     raLocation.location = loc_address;
444     raLocation.val.addr = newRAAddr;
445     out.setRALocation(raLocation);
446
447     // TODO handle 64-bit mutator / 32-bit mutatee
448
449     // get value of RA
450     result = getProcessState()->readMem(&ra_value, newRAAddr, addr_width);
451
452     if (!result) {
453       sw_printf("[%s:%u] - Couldn't read from %lx\n", FILE__, __LINE__, newRAAddr);
454       return gcf_error;
455     }
456
457     out.setRA(ra_value);
458     out.setFP(in.getFP()); // FP stays the same
459     out.setSP(newRAAddr + addr_width);
460     sw_printf("[%s:%u] - DyninstDynamicStepper handled post entry/exit instrumentation\n",
461               FILE__, __LINE__);
462     return gcf_success;
463   }
464
465   gcframe_ret_t ret = HandleStandardFrame(in, out, getProcessState());
466   if (ret != gcf_success)
467     return ret;
468   out.setRA(out.getRA() + lib_base);
469
470   // For tramps with frames, read the saved stack pointer
471   // TODO does this apply to static instrumentation?
472   if (stack_height)
473   {
474     sp_addr = in.getFP() + stack_height;
475     result = getProcessState()->readMem(&sp_value, sp_addr, addr_width);
476
477     if (!result) {
478       sw_printf("[%s:%u] - Couldn't read from %lx\n", FILE__, __LINE__, sp_addr);
479       return gcf_error;
480     }
481
482     sw_printf("[%s:%u] - Read SP %p from addr %p, using stack height of 0x%lx\n",
483               FILE__, __LINE__, sp_value, sp_addr, stack_height);
484     out.setSP(sp_value);
485   }
486
487   sw_printf("[%s:%u] - DyninstDynamicStepper handled normal instrumentation\n",
488             FILE__, __LINE__);
489   return gcf_success;
490 }
491
492 namespace Dyninst {
493 namespace Stackwalker {
494 void getTrapInstruction(char *buffer, unsigned buf_size, 
495                         unsigned &actual_len, bool include_return)
496 {
497    if (include_return)
498    {
499       assert(buf_size >= 2);
500       buffer[0] = (char) 0xcc; //trap
501       buffer[1] = (char) 0xc3; //ret
502       actual_len = 2;
503       return;
504    }
505    assert(buf_size >= 1);
506    buffer[0] = (char) 0xcc; //trap
507    actual_len = 1;
508    return;
509 }
510 }
511 }
512