Have StackwalkerAPI use ProcControlAPI for debug interface, works on x86 family
[dyninst.git] / stackwalk / src / libstate.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 #include "stackwalk/src/libstate.h"
33
34 #include "stackwalk/h/swk_errors.h"
35 #include "stackwalk/h/steppergroup.h"
36 #include "stackwalk/h/walker.h"
37
38 #include <set>
39 #include <algorithm>
40 #include <iterator>
41
42 #include <string.h>
43
44 using namespace Dyninst;
45 using namespace Stackwalker;
46 using namespace std;
47
48 SymbolReaderFactory *TrackLibState::symfactory = NULL;
49
50 TrackLibState::TrackLibState(ProcessState *parent, std::string executable_) : 
51    LibraryState(parent),
52    needs_update(true),
53    has_updated(false),
54    translate(NULL),
55    procreader(parent, executable_)
56 {
57    PID pid = procstate->getProcessId();
58    
59    sw_printf("[%s:%u] - Creating a TrackLibState on pid %d\n",
60              __FILE__, __LINE__, pid);
61    if (!symfactory)
62       symfactory = getDefaultSymbolReader();
63
64    if (procstate->isFirstParty()) {
65       translate = AddressTranslate::createAddressTranslator(&procreader, symfactory);
66    }
67    else {
68       translate = AddressTranslate::createAddressTranslator(pid, &procreader, symfactory);
69    }
70    if (!translate) {
71       sw_printf("[%s:%u] - Creation of AddressTranslate failed "
72                 "on pid %d!\n", __FILE__, __LINE__, pid);
73    }
74    assert(translate);
75 }
76
77 void TrackLibState::getCurList(std::set<LibAddrPair> &list)
78 {
79    vector<LoadedLib *> libs;
80    bool result = translate->getLibs(libs);
81    if (!result) {
82       return;
83    }
84    vector<LoadedLib *>::iterator i;
85    for (i = libs.begin(); i != libs.end(); i++) {
86       LibAddrPair o;
87       o.first = (*i)->getName();
88       o.second = (*i)->getCodeLoadAddr();
89       list.insert(o);
90    }
91 }
92
93 bool TrackLibState::updateLibs()
94 {
95    if (!needs_update)
96       return true;
97    needs_update = false;
98
99    std::set<LibAddrPair> pre, post, diff;
100    if (has_updated) {
101       getCurList(pre);
102    }
103    has_updated = true;
104
105    PID pid = procstate->getProcessId();
106    bool result = translate->refresh();
107    if (!result) {
108       sw_printf("[%s:%u] - Could not get load addresses out of SymtabAPI for %d."
109                 "This may happen during process create before libs have be set up\n",
110                  __FILE__, __LINE__, pid);
111       needs_update = true;
112    }
113
114    vector<pair<LibAddrPair, unsigned int> > arch_libs;
115    if (!updateLibsArch(arch_libs)) {
116 #if !defined(os_linux) && !defined(arch_x86_64)
117       sw_printf("[%s:%u] - updateLibsArch failed\n",  __FILE__, __LINE__);
118 #endif
119    }
120
121    getCurList(post);
122    
123    StepperGroup *group = procstate->getWalker()->getStepperGroup();
124    set_difference(pre.begin(), pre.end(),
125                  post.begin(), post.end(), 
126                  inserter(diff, diff.begin()));
127    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
128       LibAddrPair la = *i;
129       group->newLibraryNotification(&la, library_unload);
130    }
131    diff.clear();
132
133    set_difference(post.begin(), post.end(),
134                  pre.begin(), pre.end(), 
135                  inserter(diff, diff.begin()));
136    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
137       LibAddrPair la = *i;
138       group->newLibraryNotification(&la, library_load);
139    }
140                  
141    return true;
142 }
143
144 bool TrackLibState::getLibraryAtAddr(Address addr, LibAddrPair &olib)
145 {
146    bool result = refresh();
147    if (!result) {
148       sw_printf("[%s:%u] - Failed to refresh library.\n", __FILE__, __LINE__);
149       setLastError(err_symtab, "Failed to refresh library list");
150       return false;
151    }
152    
153    Address load_addr;
154    
155    std::vector<std::pair<LibAddrPair, unsigned> >::iterator i;
156    for (i = arch_libs.begin(); i != arch_libs.end(); i++) {
157       load_addr = (*i).first.second;
158       unsigned size = (*i).second;
159       if ((addr >= load_addr) && (addr < load_addr + size)) {
160          olib = (*i).first;
161          return true;
162       }
163    }
164
165    LoadedLib *ll;
166    result = translate->getLibAtAddress(addr, ll);
167    if (!result) {
168       sw_printf("[%s:%u] - no file loaded at %lx\n", __FILE__, __LINE__, addr);
169       setLastError(err_nofile, "No file loaded at specified address");
170       return false;
171    }
172
173    olib.first = ll->getName();
174    olib.second = ll->getCodeLoadAddr();
175    
176    return true;
177 }
178
179 bool TrackLibState::getLibraries(std::vector<LibAddrPair> &olibs)
180 {
181    bool result = refresh();
182    if (!result) {
183       setLastError(err_symtab, "Failed to refresh library list");
184       return false;
185    }
186    
187    vector<LoadedLib *> libs;
188    result = translate->getLibs(libs);
189    if (!result) {
190       setLastError(err_symtab, "No objects in process");
191       return false;
192    }
193    
194    olibs.clear();
195    vector<LoadedLib *>::iterator i;
196    for (i = libs.begin(); i != libs.end(); i++) {
197       LibAddrPair o;
198       o.first = (*i)->getName();
199       o.second = (*i)->getCodeLoadAddr();
200       olibs.push_back(o);
201    }
202    return true;
203 }
204
205 bool TrackLibState::refresh()
206 {
207    bool result = updateLibs();
208    if (!result)
209       return false;
210    //TODO: Determine difference, notify steppergroup of diff
211    return true;
212 }
213
214 Address TrackLibState::getLibTrapAddress() {
215    return translate->getLibraryTrapAddrSysV();
216 }
217
218 TrackLibState::~TrackLibState() {
219 }
220
221 void TrackLibState::notifyOfUpdate() {
222    //This may be called under a signal handler, keep simple
223    needs_update = true;
224 }
225
226 static bool libNameMatch(const char *s, const char *libname)
227 {
228    // A poor-man's regex match for */lib<s>[0123456789-.]*.so*
229    const char *filestart = strrchr(libname, '/');
230    if (!filestart)
231       filestart = libname;
232    const char *lib_start = strstr(filestart, "lib");
233    if (lib_start != filestart+1)
234       return false;
235    const char *libname_start = lib_start+3;
236    int s_len = strlen(s);
237    if (strncmp(s, libname_start, s_len) != 0) {
238       return false;
239    }
240
241    const char *cur = libname_start + s_len;
242    const char *valid_chars = "0123456789-.";
243    while (*cur) {
244       if (!strchr(valid_chars, *cur)) {
245          cur--;
246          if (strstr(cur, ".so") == cur) {
247             return true;
248          }
249          return false;
250       }
251       cur++;
252    }
253    return false;
254 }
255
256 bool LibraryState::getLibc(LibAddrPair &addr_pair)
257 {
258    std::vector<LibAddrPair> libs;
259    getLibraries(libs);
260    if (libs.size() == 1) {
261       //Static binary.
262       addr_pair = libs[0];
263       return true;
264    }
265    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
266    {
267       if (libNameMatch("c", i->first.c_str())) {
268          addr_pair = *i;
269          return true;
270       }
271    }
272    return false;
273 }
274
275 bool LibraryState::getLibthread(LibAddrPair &addr_pair)
276 {
277    std::vector<LibAddrPair> libs;
278    getLibraries(libs);
279    if (libs.size() == 1) {
280       //Static binary.
281       addr_pair = libs[0];
282       return true;
283    }
284    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
285    {
286       if (libNameMatch("pthread", i->first.c_str())) {
287          addr_pair = *i;
288          return true;
289       }
290    }
291    return false;
292 }
293
294 bool TrackLibState::getAOut(LibAddrPair &addr_pair)
295 {
296    LoadedLib *aout;
297    updateLibs();
298    aout = translate->getExecutable();
299    if (!aout) {
300       sw_printf("[%s:%u] - Error.  SymtabAPI getAOut failed\n",
301                 __FILE__, __LINE__);
302       return false;
303    }
304    addr_pair = LibAddrPair(aout->getName(), aout->getCodeLoadAddr());
305    return true;
306 }
307
308 swkProcessReader::swkProcessReader(ProcessState *pstate, const std::string& /*executable*/) :
309    procstate(pstate)
310 {
311 }
312
313 bool swkProcessReader::ReadMem(Address inTraced, void *inSelf, unsigned amount)
314 {
315   return procstate->readMem(inSelf, inTraced, amount);
316 }
317
318 swkProcessReader::~swkProcessReader()
319 {
320 }
321
322 bool swkProcessReader::start()
323 {
324    return true;
325 }
326
327 bool swkProcessReader::done()
328 {
329    return true;
330 }
331
332 static LibraryWrapper libs;
333
334 SymReader *LibraryWrapper::getLibrary(std::string filename)
335 {
336    std::map<std::string, SymReader *>::iterator i = libs.file_map.find(filename);
337    if (i != libs.file_map.end()) {
338       return i->second;
339    }
340    
341    SymbolReaderFactory *fact = getDefaultSymbolReader();
342    SymReader *reader = fact->openSymbolReader(filename);
343    if (!reader)
344       return NULL;
345    libs.file_map[filename] = reader;
346    return reader;
347 }
348
349 void LibraryWrapper::registerLibrary(SymReader *reader, std::string filename)
350 {
351    libs.file_map[filename] = reader;
352 }