Infrastructure for SW CallTrees and group operations
[dyninst.git] / stackwalk / src / aix-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 #include "stackwalk/h/swk_errors.h"
33 #include "stackwalk/h/symlookup.h"
34 #include "stackwalk/h/walker.h"
35 #include "stackwalk/h/steppergroup.h"
36 #include "stackwalk/h/procstate.h"
37 #include "stackwalk/h/frame.h"
38
39 #include "stackwalk/src/sw.h"
40 #include "stackwalk/src/symtab-swk.h"
41
42 #include "common/h/headers.h"
43 #include "common/h/Types.h"
44
45 #include <string>
46 #include <sstream>
47
48 #include <string.h>
49 #include <errno.h>
50 #include <assert.h>
51 #include <signal.h>
52 #include <sys/thread.h>
53
54 using namespace Dyninst;
55 using namespace Dyninst::Stackwalker;
56
57 #if defined(cap_stackwalker_use_symtab)
58
59 #include "symtabAPI/h/Symtab.h"
60 #include "symtabAPI/h/Symbol.h"
61
62 using namespace Dyninst::SymtabAPI;
63 #endif
64
65 ProcSelf::ProcSelf(std::string exec_path) : 
66    ProcessState(getpid(), exec_path)
67 {
68 }
69
70 void ProcSelf::initialize()
71 {
72    setDefaultLibraryTracker();
73    assert(library_tracker);
74 }
75
76 #include <setjmp.h>
77
78 static bool registered_handler = false;
79 static bool reading_memory = false;
80 sigjmp_buf readmem_jmp;
81
82 void handle_fault(int /*sig*/)
83 {
84    if (!reading_memory) {
85       //The instruction that caused this fault was not from
86       // ProcSelf::readMem.  Restore the SIGSEGV handler, and 
87       // the faulting instruction should restart after we return.
88       sw_printf("[%s:%u] - Caught segfault that didn't come " \
89                 "from stackwalker memory read!", __FILE__, __LINE__);
90       signal(SIGSEGV, SIG_DFL);
91       return;
92    }
93    siglongjmp(readmem_jmp, 1);
94 }
95  
96 bool ProcSelf::readMem(void *dest, Address source, size_t size)
97 {
98    if (!registered_handler) {
99       signal(SIGSEGV, handle_fault);
100       registered_handler = true;
101    }
102    reading_memory = true;
103    if (sigsetjmp(readmem_jmp, 1)) {
104       sw_printf("[%s:%u] - Caught fault while reading from %lx to %lx\n", 
105                 __FILE__, __LINE__, source, source + size);
106       setLastError(err_procread, "Could not read from process");
107       return false;
108    }
109    
110    memcpy(dest, (const void *) source, size);
111    reading_memory = false;
112    return true;
113 }
114
115 bool ProcSelf::getThreadIds(std::vector<THR_ID> &threads)
116 {
117   bool result;
118   THR_ID tid;
119
120   result = getDefaultThread(tid);
121   if (!result) {
122     sw_printf("[%s:%u] - Could not read default thread\n", __FILE__, __LINE__);
123     return false;
124   }
125   threads.clear();
126   threads.push_back(tid);
127   return true;
128 }
129
130 bool ProcSelf::getDefaultThread(THR_ID &default_tid)
131 {
132    default_tid = thread_self();
133    return true;
134 }
135
136 bool Walker::createDefaultSteppers()
137 {
138   FrameStepper *stepper;
139   bool result;
140
141   stepper = new FrameFuncStepper(this);
142   result = addStepper(stepper);
143   if (!result) {
144     sw_printf("[%s:%u] - Error adding stepper %p\n", __FILE__, __LINE__,
145               stepper);
146     return false;
147   }
148
149   stepper = new BottomOfStackStepper(this);
150   result = addStepper(stepper);
151   if (!result) {
152     sw_printf("[%s:%u] - Error adding stepper %p\n", __FILE__, __LINE__,
153               stepper);
154     return false;
155   }  
156
157   return true;
158 }
159
160 bool LibraryState::updateLibsArch(vector<pair<LibAddrPair, unsigned int> > &)
161 {
162    return true;
163 }
164
165 #if defined(cap_stackwalker_use_symtab)
166
167 static bool libNameMatch(const char *s, const char *libname)
168 {
169    // A poor-man's regex match for */lib<s>[0123456789-.]*.a*
170    const char *filestart = strrchr(libname, '/');
171    if (!filestart)
172       filestart = libname;
173    const char *lib_start = strstr(filestart, "lib");
174    if (lib_start != filestart+1)
175       return false;
176    const char *libname_start = lib_start+3;
177    int s_len = strlen(s);
178    if (strncmp(s, libname_start, s_len) != 0) {
179       return false;
180    }
181
182    const char *cur = libname_start + s_len;
183    const char *valid_chars = "0123456789-.";
184    while (*cur) {
185       if (!strchr(valid_chars, *cur)) {
186          cur--;
187          if (strstr(cur, ".so") == cur) {
188             return true;
189          }
190          if (strstr(cur, ".a") == cur) {
191             return true;
192          }
193          return false;
194       }
195       cur++;
196    }
197    return false;
198 }
199
200 bool SymtabLibState::getLibc(LibAddrPair &addr_pair)
201 {
202    std::vector<LibAddrPair> libs;
203    getLibraries(libs);
204    if (libs.size() == 1) {
205       //Static binary.
206       addr_pair = libs[0];
207       return true;
208    }
209    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
210    {
211       if (libNameMatch("c", i->first.c_str())) {
212          addr_pair = *i;
213          return true;
214       }
215    }
216    return false;
217 }
218
219 bool SymtabLibState::getLibpthread(LibAddrPair &addr_pair)
220 {
221    std::vector<LibAddrPair> libs;
222    getLibraries(libs);
223    if (libs.size() == 1) {
224       //Static binary.
225       addr_pair = libs[0];
226       return true;
227    }
228    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
229    {
230       if (libNameMatch("pthread", i->first.c_str())) {
231          addr_pair = *i;
232          return true;
233       }
234    }
235    return false;
236 }
237
238 #endif
239
240 void BottomOfStackStepperImpl::initialize()
241 {
242 #if defined(cap_stackwalker_use_symtab)
243    std::vector<LibAddrPair> libs;
244    ProcessState *proc = walker->getProcessState();
245    assert(proc);
246
247    sw_printf("[%s:%u] - Initializing BottomOfStackStepper\n", __FILE__, __LINE__);
248    initialized = true;
249    
250    LibraryState *ls = proc->getLibraryTracker();
251    if (!ls) {
252       sw_printf("[%s:%u] - Error initing StackBottom.  No library state for process.\n",
253                 __FILE__, __LINE__);
254       return;
255    }
256    SymtabLibState *symtab_ls = dynamic_cast<SymtabLibState *>(ls);
257    if (!symtab_ls) {
258       sw_printf("[%s:%u] - Error initing StackBottom. Unknown library state.\n",
259                 __FILE__, __LINE__);
260    }
261
262    bool result = false;
263    std::vector<Function *> funcs;
264    std::vector<Function *>::iterator i;
265
266    //Find main in a.out
267    LibAddrPair aout_libaddr = symtab_ls->getAOut();
268    Symtab *aout = SymtabWrapper::getSymtab(aout_libaddr.first);
269    if (aout) {
270       result = aout->findFunctionsByName(funcs, "main");
271       if (!result || !funcs.size()) {
272          sw_printf("[%s:%u] - Error. Could not locate main\n", __FILE__, __LINE__);
273       }
274       for (i = funcs.begin(); i != funcs.end(); i++) {
275          Address start = (*i)->getOffset() + aout_libaddr.second;
276          Address end = start + (*i)->getSize();
277          sw_printf("[%s:%u] - Adding _start stack bottom [0x%lx, 0x%lx]\n",
278                    __FILE__, __LINE__, start, end);
279          ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
280       }
281    }
282    else {
283       sw_printf("[%s:%u] - Error. Could not locate a.out\n", __FILE__, __LINE__);
284    }
285
286    //Find pthread_body in 
287    LibAddrPair pthread_libaddr;
288    if (symtab_ls->getLibpthread(pthread_libaddr))
289    {
290       Symtab *libpthread = SymtabWrapper::getSymtab(aout_libaddr.first);
291       if (libpthread) {
292          result = libpthread->findFunctionsByName(funcs, "_pthread_body");
293          if (!result || !funcs.size()) {
294             sw_printf("[%s:%u] - Error. Could not locate main\n", __FILE__, __LINE__);
295          }
296          for (i = funcs.begin(); i != funcs.end(); i++) {
297             Address start = (*i)->getOffset() + aout_libaddr.second;
298             Address end = start + (*i)->getSize();
299             sw_printf("[%s:%u] - Adding _start stack bottom [0x%lx, 0x%lx]\n",
300                       __FILE__, __LINE__, start, end);
301             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
302          }
303       }
304    }
305 #endif
306 }