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