PPC fixes for StackwalkerAPI
[dyninst.git] / stackwalk / src / symtab-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
33 #if defined(cap_stackwalker_use_symtab)
34
35 #include "stackwalk/h/symlookup.h"
36 #include "stackwalk/h/swk_errors.h"
37 #include "stackwalk/h/walker.h"
38 #include "stackwalk/h/frame.h"
39 #include <assert.h>
40
41 #include "symtabAPI/h/Symtab.h"
42 #include "symtabAPI/h/Symbol.h"
43 #include "symtabAPI/h/AddrLookup.h"
44 #include "stackwalk/src/symtab-swk.h"
45
46 using namespace Dyninst;
47 using namespace Dyninst::Stackwalker;
48 using namespace Dyninst::SymtabAPI;
49
50 SymtabWrapper* SymtabWrapper::wrapper;
51
52 SymtabWrapper::SymtabWrapper()
53 {
54 }
55
56 Symtab *SymtabWrapper::getSymtab(std::string filename)
57 {
58   if (!wrapper) {
59      //TODO: Thread safety
60      wrapper = new SymtabWrapper();
61   }
62   
63   if (wrapper->map.count(filename)) {
64      return wrapper->map[filename];
65   }
66   
67   sw_printf("[%s:%u] - Trying to open symtab object %s\n", 
68             __FILE__, __LINE__, filename.c_str());
69   Symtab *symtab;
70   bool result = Symtab::openFile(symtab, filename);
71   if (!result) {
72      setLastError(err_nofile, "Couldn't open file through SymtabAPI\n");
73      return NULL;
74   }
75
76   wrapper->map[filename] = symtab;
77   return symtab;
78 }
79
80 SymtabWrapper::~SymtabWrapper()
81 {
82    dyn_hash_map<std::string, Symtab *>::iterator i = map.begin();
83    for (; i != map.end(); i++)
84    {
85       Symtab *symtab = (*i).second;
86       delete symtab;
87    }
88    
89    wrapper = NULL;
90 }
91
92 void SymtabWrapper::notifyOfSymtab(Symtab *symtab, std::string name)
93 {
94   if (!wrapper) {
95      //TODO: Thread safety
96      wrapper = new SymtabWrapper();
97   }
98   
99   if (wrapper->map.count(name)) {
100      return;
101   }
102
103   wrapper->map[name] = symtab;
104 }
105
106 SymtabLibState::SymtabLibState(ProcessState *parent, std::string executable) : 
107    LibraryState(parent),
108    needs_update(true),
109    lookup(NULL),
110    procreader(parent, executable)
111 #if defined(os_linux)
112    , vsyscall_mem(NULL)
113    , vsyscall_symtab(NULL)
114    , vsyscall_page_set(vsys_unset)
115 #endif
116 {
117    PID pid = procstate->getProcessId();
118    sw_printf("[%s:%u] - Creating a SymtabLibState on pid %d\n",
119              __FILE__, __LINE__, pid);
120    if (procstate->isFirstParty()) {
121       lookup = AddressLookup::createAddressLookup(&procreader);
122    }
123    else {
124       lookup = AddressLookup::createAddressLookup(pid, &procreader);
125    }
126    if (!lookup) {
127       sw_printf("[%s:%u] - Creation of AddressLookup failed for ProcSelf "
128                 "on pid %d!\n", __FILE__, __LINE__, pid);
129    }
130    assert(lookup);
131 }
132
133 bool SymtabLibState::updateLibs()
134 {
135    if (!needs_update)
136       return true;
137    needs_update = false;
138
139    PID pid = procstate->getProcessId();
140    bool result = lookup->refresh();
141    if (!result) {
142       sw_printf("[%s:%u] - Could not get load addresses out of SymtabAPI for %d."
143                 "This may happen during process create before libs have be set up\n",
144                  __FILE__, __LINE__, pid);
145       needs_update = true;
146    }
147
148    if (!updateLibsArch())
149    {
150       sw_printf("[%s:%u] - updateLibsArch failed\n",  __FILE__, __LINE__);
151    }
152
153    return true;
154 }
155
156 bool SymtabLibState::getLibraryAtAddr(Address addr, LibAddrPair &olib)
157 {
158    bool result = refresh();
159    if (!result) {
160       sw_printf("[%s:%u] - Failed to refresh library.\n", __FILE__, __LINE__);
161       setLastError(err_symtab, "Failed to refresh library list");
162       return false;
163    }
164    
165    Address load_addr;
166    
167    std::vector<std::pair<LibAddrPair, unsigned> >::iterator i;
168    for (i = arch_libs.begin(); i != arch_libs.end(); i++) {
169       load_addr = (*i).first.second;
170       unsigned size = (*i).second;
171       if ((addr >= load_addr) && (addr < load_addr + size)) {
172          olib = (*i).first;
173          return true;
174       }
175    }
176
177    Symtab *symtab;
178    Offset offset;
179    result = lookup->getOffset(addr, symtab, offset);
180    if (!result) {
181       sw_printf("[%s:%u] - no file loaded at %x\n", __FILE__, __LINE__, offset);
182       setLastError(err_nofile, "No file loaded at specified address");
183       return false;
184    }
185    
186    result = lookup->getLoadAddress(symtab, load_addr);
187    if (!result) {
188       setLastError(err_symtab, "Couldn't get load address for Symtab object");
189       return false;
190    }
191    
192    std::string name = symtab->file();
193    olib.first = name;
194    olib.second = load_addr;
195    SymtabWrapper::notifyOfSymtab(symtab, name);
196    
197    return true;
198 }
199
200 bool SymtabLibState::getLibraries(std::vector<LibAddrPair> &olibs)
201 {
202    bool result = refresh();
203    if (!result) {
204       setLastError(err_symtab, "Failed to refresh library list");
205       return false;
206    }
207    
208    std::vector<Symtab *> tabs;
209    result = lookup->getAllSymtabs(tabs);
210    if (!result) {
211       setLastError(err_symtab, "No objects in process");
212       return false;
213    }
214    
215    for (unsigned i=0; i<tabs.size(); i++) {
216       Address load_addr;
217       result = lookup->getLoadAddress(tabs[i], load_addr);
218       if (!result) {
219          setLastError(err_symtab, "File has no load address");
220          return false;
221       }
222       std::string name = tabs[i]->file();
223
224       LibAddrPair olib;
225       olib.first = name;
226       olib.second = load_addr;
227       SymtabWrapper::notifyOfSymtab(tabs[i], name);      
228       olibs.push_back(olib);
229    }
230
231    std::vector<std::pair<LibAddrPair, unsigned> >::iterator i;
232    for (i = arch_libs.begin(); i != arch_libs.end(); i++) {
233       olibs.push_back((*i).first);
234    }
235
236    return true;
237 }
238
239 bool SymtabLibState::refresh()
240 {
241    bool result = updateLibs();
242    if (!result)
243       return false;
244    //TODO: Determine difference, notify steppergroup of diff
245    return true;
246 }
247
248 Address SymtabLibState::getLibTrapAddress() {
249    return lookup->getLibraryTrapAddrSysV();
250 }
251
252 SymtabLibState::~SymtabLibState() {
253 #if defined(os_linux)
254    if (vsyscall_mem)
255       free(vsyscall_mem);
256 #endif
257 }
258
259 void SymtabLibState::notifyOfUpdate() {
260    //This may be called under a signal handler, keep simple
261    needs_update = true;
262 }
263
264 LibAddrPair SymtabLibState::getAOut() {
265    LoadedLibrary exec;
266    updateLibs();
267    bool result = lookup->getExecutable(exec);
268    if (!result) {
269       sw_printf("[%s:%u] - Error.  SymtabAPI getExecutable failed\n",
270                 __FILE__, __LINE__);
271       return LibAddrPair(std::string(""), 0x0);
272    }
273
274    std::vector<LibAddrPair> libs;
275    result = getLibraries(libs);
276    if (!result) {
277       sw_printf("[%s:%u] - Error.  getLibraries failed\n",
278                 __FILE__, __LINE__);
279       return LibAddrPair(std::string(""), 0x0);
280    }
281
282    std::vector<LibAddrPair>::iterator i;
283    for (i = libs.begin(); i != libs.end(); i++) {
284       if ((*i).first == exec.name) {
285          return *i;
286       }
287    }
288
289    sw_printf("[%s:%u] - Could not find a.out in library list\n",
290              __FILE__, __LINE__);
291    return LibAddrPair(std::string(""), 0x0);
292 }
293
294 swkProcessReader::swkProcessReader(ProcessState *pstate, const std::string& executable) :
295    ProcessReader(0, executable),
296    procstate(pstate)
297 {
298 }
299
300 bool swkProcessReader::readAddressSpace(Address inTraced, unsigned amount,
301                                         void *inSelf)
302 {
303   pid = procstate->getProcessId();
304   return procstate->readMem(inSelf, inTraced, amount);
305 }
306
307 swkProcessReader::~swkProcessReader()
308 {
309 }
310
311 bool swkProcessReader::start()
312 {
313    return true;
314 }
315
316 bool swkProcessReader::done()
317 {
318    return true;
319 }
320
321 bool SwkSymtab::lookupAtAddr(Address addr, std::string &out_name,
322                                 void* &out_value)
323 {
324   Address load_addr;
325   std::string libname;
326   bool result;
327
328   LibraryState *libtracker = walker->getProcessState()->getLibraryTracker();
329   if (!libtracker) {
330      sw_printf("[%s:%u] - getLibraryTracker() failed\n", __FILE__, __LINE__);
331      setLastError(err_nolibtracker, "No library tracker object registered");
332      return false;
333   }
334
335   LibAddrPair lib;
336   result = libtracker->getLibraryAtAddr(addr, lib);
337   if (!result) {
338      sw_printf("[%s:%u] - getLibraryAtAddr() failed: %s\n", __FILE__, __LINE__, getLastErrorMsg());
339     return false;
340   }
341
342   Symtab *symtab = SymtabWrapper::getSymtab(lib.first);
343   assert(symtab);
344   load_addr = lib.second;
345
346   //TODO: Cache symbol vector and use binary search
347   std::vector<Symbol *> syms;
348   result = symtab->getAllSymbolsByType(syms, Symbol::ST_FUNCTION);
349   if (!result) {
350     sw_printf("[%s:%u] - Couldn't get symbols for %s\n", 
351               __FILE__, __LINE__, libname.c_str());
352     return false;
353   }
354   Symbol *candidate = NULL;
355   unsigned long distance = 0;
356   for (unsigned i = 0; i < syms.size(); i++)
357   {
358     unsigned long cur_distance = (addr - load_addr) - syms[i]->getAddr();
359     if (!candidate || cur_distance < distance) {
360       distance = cur_distance;
361       candidate = syms[i];
362     }
363   }
364
365   out_name = candidate->getTypedName();
366   if (!out_name.length())
367     out_name = candidate->getPrettyName();
368   if (!out_name.length())
369     out_name = candidate->getName();
370   out_value = (void *) candidate;
371
372   sw_printf("[%s:%u] - Found name for %lx : %s\n", __FILE__, __LINE__,
373             addr, out_name.c_str());  
374   
375   return true;
376 }
377
378 SwkSymtab::SwkSymtab(Walker *w, const std::string &exec_name) :
379    SymbolLookup(w, exec_name)
380 {
381 }
382
383 #if defined(arch_x86) || defined(arch_x86_64)
384 std::map<Symtab*, bool> DyninstInstrStepperImpl::isRewritten;
385
386 DyninstInstrStepperImpl::DyninstInstrStepperImpl(Walker *w, FrameStepper *p) :
387   FrameStepper(w),
388   parent(p)
389 {
390 }
391
392 gcframe_ret_t DyninstInstrStepperImpl::getCallerFrame(const Frame &in, Frame &out)
393 {
394    LibAddrPair lib;
395    bool result;
396
397    result = getProcessState()->getLibraryTracker()->getLibraryAtAddr(in.getRA(), lib);
398    if (!result) {
399       sw_printf("[%s:%u] - Stackwalking through an invalid PC at %lx\n",
400                  __FILE__, __LINE__, in.getRA());
401       return gcf_stackbottom;
402    }
403
404    Symtab *symtab = SymtabWrapper::getSymtab(lib.first);
405    if (!symtab) {
406       sw_printf("[%s:%u] - Could not open file %s with SymtabAPI %s\n",
407                  __FILE__, __LINE__, lib.first.c_str());
408       setLastError(err_nofile, "Could not open file for Debugging stackwalker\n");
409       return gcf_error;
410    }
411
412    std::map<Symtab*, bool>::iterator i = isRewritten.find(symtab);
413    bool is_rewritten_binary;
414    if (i == isRewritten.end()) {
415      Region *r = NULL;
416      result = symtab->findRegion(r, std::string(".dyninstInst"));
417      is_rewritten_binary = (r && result);
418      isRewritten[symtab] = is_rewritten_binary;
419    }
420    else {
421      is_rewritten_binary = (*i).second;
422    }
423    if (!is_rewritten_binary) {
424      sw_printf("[%s:u] - Decided that current binary is not rewritten, "
425                "DyninstInstrStepper returning gcf_not_me at %lx\n",
426                __FILE__, __LINE__, in.getRA());
427      return gcf_not_me;
428    }
429
430    std::string name;
431    in.getName(name);
432    const char *s = name.c_str();
433    if (strstr(s, "dyninst") != s)
434    {
435      sw_printf("[%s:%u] - Current function %s not dyninst generated\n",
436                 __FILE__, __LINE__, s);
437      return gcf_not_me;
438    }
439
440    if (strstr(s, "dyninstBT") != s)
441    {
442      sw_printf("[%s:%u] - Dyninst, but don't know how to read non-tramp %s\n",
443                 __FILE__, __LINE__, s);
444      return gcf_not_me;
445    }
446     
447    sw_printf("[%s:%u] - Current function %s is baseTramp\n",
448               __FILE__, __LINE__, s);
449    Address base;
450    unsigned size, stack_height;
451    int num_read = sscanf(s, "dyninstBT_%lx_%u_%x", &base, &size, &stack_height);
452    bool has_stack_frame = (num_read == 3);
453    if (!has_stack_frame) {
454      sw_printf("[%s:%u] - Don't know how to walk through instrumentation without a stack frame\n"
455                 __FILE__, __LINE__);
456      return gcf_not_me;
457    }
458      
459    return getCallerFrameArch(in, out, base, lib.second, size, stack_height);
460 }
461
462 unsigned DyninstInstrStepperImpl::getPriority() const
463 {
464   return dyninstr_priority;
465 }
466
467 void DyninstInstrStepperImpl::registerStepperGroup(StepperGroup *group)
468 {
469   FrameStepper::registerStepperGroup(group);
470 }
471
472 DyninstInstrStepperImpl::~DyninstInstrStepperImpl()
473 {
474 }
475 #endif
476
477 #endif