Infrastructure for SW CallTrees and group operations
[dyninst.git] / stackwalk / src / symtab-swk.C
1 /*
2  * Copyright (c) 1996-2011 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 using namespace std;
50
51 SymtabWrapper* SymtabWrapper::wrapper;
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 bool SwkSymtab::lookupAtAddr(Address addr, std::string &out_name,
108                                 void* &out_value)
109 {
110   Address load_addr;
111   std::string libname;
112   bool result;
113
114   LibraryState *libtracker = walker->getProcessState()->getLibraryTracker();
115   if (!libtracker) {
116      sw_printf("[%s:%u] - getLibraryTracker() failed\n", __FILE__, __LINE__);
117      setLastError(err_nolibtracker, "No library tracker object registered");
118      return false;
119   }
120
121   LibAddrPair lib;
122   result = libtracker->getLibraryAtAddr(addr, lib);
123   if (!result) {
124      sw_printf("[%s:%u] - getLibraryAtAddr() failed: %s\n", __FILE__, __LINE__, getLastErrorMsg());
125     return false;
126   }
127
128   Symtab *symtab = SymtabWrapper::getSymtab(lib.first);
129   assert(symtab);
130   load_addr = lib.second;
131
132   //TODO: Cache symbol vector and use binary search
133   std::vector<Symbol *> syms;
134   result = symtab->getAllSymbolsByType(syms, Symbol::ST_FUNCTION);
135   if (!result) {
136     sw_printf("[%s:%u] - Couldn't get symbols for %s\n", 
137               __FILE__, __LINE__, libname.c_str());
138     return false;
139   }
140   Symbol *candidate = NULL;
141   unsigned long distance = 0;
142   for (unsigned i = 0; i < syms.size(); i++)
143   {
144     unsigned long cur_distance = (addr - load_addr) - syms[i]->getAddr();
145     if (!candidate || cur_distance < distance) {
146       distance = cur_distance;
147       candidate = syms[i];
148     }
149   }
150
151   out_name = candidate->getTypedName();
152   if (!out_name.length())
153     out_name = candidate->getPrettyName();
154   if (!out_name.length())
155     out_name = candidate->getName();
156   out_value = (void *) candidate;
157
158   sw_printf("[%s:%u] - Found name for %lx : %s\n", __FILE__, __LINE__,
159             addr, out_name.c_str());  
160   
161   return true;
162 }
163
164 SwkSymtab::SwkSymtab(Walker *w, std::string exec_name) :
165    SymbolLookup(w, exec_name)
166 {
167 }
168
169 #endif