Infrastructure for SW CallTrees and group operations
[dyninst.git] / stackwalk / src / linux-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/linuxbsd-swk.h"
40 #include "stackwalk/src/sw.h"
41 #include "stackwalk/src/symtab-swk.h"
42 #include "stackwalk/src/libstate.h"
43
44 #include "common/h/parseauxv.h"
45
46 #include <string>
47 #include <sstream>
48
49 #include <string.h>
50 #include <sys/syscall.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #include <assert.h>
54 #include <signal.h>
55 #include <sys/types.h>
56 #include <sys/wait.h>
57 #include <sys/mman.h>
58 #include <fcntl.h>
59 #include <poll.h>
60
61 #include "common/h/parseauxv.h"
62 #include "dynutil/h/dyn_regs.h"
63
64 #include "symtabAPI/h/SymtabReader.h"
65
66 using namespace Dyninst;
67 using namespace Dyninst::Stackwalker;
68
69 #ifndef SYS_tkill
70 #define SYS_tkill 238
71 #endif
72
73 //These should be defined on all modern linux's, turn these off
74 // if porting to some linux-like platform that doesn't support 
75 // them.
76 #include <sys/ptrace.h>
77 #include <linux/ptrace.h>
78 typedef enum __ptrace_request pt_req;
79 #define cap_ptrace_traceclone
80 #define cap_ptrace_setoptions
81
82 int P_gettid()
83 {
84   static int gettid_not_valid = 0;
85   long int result;
86
87   if (gettid_not_valid)
88     return getpid();
89
90   result = syscall(SYS_gettid);
91   if (result == -1 && errno == ENOSYS)
92   {
93     gettid_not_valid = 1;
94     return getpid();
95   }
96   return (int) result;
97 }
98
99 vsys_info *Dyninst::Stackwalker::getVsysInfo(ProcessState *ps)
100 {
101 #if defined(arch_x86_64)
102    if (ps->getAddressWidth() == 8)
103       return NULL;
104 #endif
105
106    static std::map<ProcessState *, vsys_info *> vsysmap;
107    vsys_info *ret = NULL;
108    Address start, end;
109    char *buffer = NULL;
110    SymReader *reader = NULL;
111    SymbolReaderFactory *fact = NULL;
112    bool result;
113
114    std::map<ProcessState *, vsys_info *>::iterator i = vsysmap.find(ps);
115    if (i != vsysmap.end())
116       return i->second;
117    
118    AuxvParser *parser = AuxvParser::createAuxvParser(ps->getProcessId(),
119                                                      ps->getAddressWidth());
120    if (!parser) {
121       sw_printf("[%s:%u] - Unable to parse auxv for %d\n", __FILE__, __LINE__,
122                 ps->getProcessId());
123       goto done;
124    }
125
126    start = parser->getVsyscallBase();
127    end = parser->getVsyscallEnd();
128    sw_printf("[%s:%u] - Found vsyscall over range %lx to %lx\n",
129              __FILE__, __LINE__, start, end);   
130    parser->deleteAuxvParser();
131    
132    if (!start || !end || end == start)
133    {
134       sw_printf("[%s:%u] - Error collecting vsyscall base and end\n",
135                 __FILE__, __LINE__);
136       goto done;
137    }
138
139    ret = new vsys_info();
140    assert(ret);
141    ret->start = start;
142    ret->end = end;
143
144    buffer = (char *) malloc(end - start);
145    assert(buffer);
146    result = ps->readMem(buffer, start, end - start);
147    if (!result) {
148       sw_printf("[%s:%u] - Error reading vsys memory\n", __FILE__, __LINE__);
149       goto done;
150    }
151    ret->vsys_mem = buffer;
152
153    fact = getDefaultSymbolReader();
154    if (!fact) {
155       sw_printf("[%s:%u] - No symbol reading capability\n",
156                 __FILE__, __LINE__);
157       goto done;
158    }   
159    reader = fact->openSymbolReader(buffer, end - start);
160    if (!reader) {
161       sw_printf("[%s:%u] - Error reading symbol info\n");
162       goto done;
163    }
164    ret->syms = reader;
165
166   done:
167    vsysmap[ps] = ret;
168    return ret;
169 }
170
171 bool LibraryState::updateLibsArch(std::vector<std::pair<LibAddrPair, unsigned int> > &alibs)
172 {
173    if (arch_libs.size()) {
174       alibs = arch_libs;
175       return true;
176    }
177    vsys_info *vsys = getVsysInfo(procstate);
178    if (!vsys) {
179       return false;
180    }
181    std::stringstream ss;
182    ss << "[vsyscall-" << procstate->getProcessId() << "]";
183    LibAddrPair vsyscall_page;
184    vsyscall_page.first = ss.str();
185    vsyscall_page.second = vsys->start;
186    
187    SymbolReaderFactory *fact = getDefaultSymbolReader();
188    SymReader *reader = fact->openSymbolReader((char *) vsys->vsys_mem,
189                                               vsys->end - vsys->start);
190    if (reader)
191       LibraryWrapper::registerLibrary(reader, vsyscall_page.first);
192
193    std::pair<LibAddrPair, unsigned int> vsyscall_lib_pair;
194    vsyscall_lib_pair.first = vsyscall_page;
195    vsyscall_lib_pair.second = static_cast<unsigned int>(vsys->end - vsys->start);
196    arch_libs.push_back(vsyscall_lib_pair);
197    alibs = arch_libs;
198
199    return true;
200 }
201
202 #define NUM_VSYS_SIGRETURNS 3
203 static const char* vsys_sigreturns[] = {
204    "_sigreturn",
205    "__kernel_sigreturn",
206    "__kernel_rt_sigreturn"
207 };
208
209 void SigHandlerStepperImpl::registerStepperGroup(StepperGroup *group)
210 {
211    ProcessState *ps = getProcessState();
212    assert(ps);
213
214    LibraryState *libs = getProcessState()->getLibraryTracker();
215    if (!libs) {
216       sw_printf("[%s:%u] - Custom library tracker.  Don't know how to"
217                 " to get libc\n", __FILE__, __LINE__);
218       return;
219    }
220    SymbolReaderFactory *fact = getDefaultSymbolReader();
221    if (!fact) {
222       sw_printf("[%s:%u] - Failed to get symbol reader\n", __FILE__, __LINE__);
223       return;
224    }
225
226    if (!init_libc) {
227       /**
228        * Get __restore_rt out of libc
229        **/
230       LibAddrPair libc_addr;
231       Dyninst::SymReader *libc = NULL;
232       Symbol_t libc_restore;
233       bool result = libs->getLibc(libc_addr);
234       if (!result) {
235          sw_printf("[%s:%u] - Unable to find libc, not registering restore_rt"
236                    "tracker.\n", __FILE__, __LINE__);
237       }
238       if (result) {
239          init_libc = true;
240          libc = fact->openSymbolReader(libc_addr.first);
241          if (!libc) {
242             sw_printf("[%s:%u] - Unable to open libc, not registering restore_rt\n",
243                       __FILE__, __LINE__);
244          }   
245       }
246       if (libc) {
247          libc_restore = libc->getSymbolByName("__restore_rt");
248          if (!libc->isValidSymbol(libc_restore)) {
249             sw_printf("[%s:%u] - Unable to find restore_rt in libc\n",
250                       __FILE__, __LINE__);
251          }
252          else {
253             Dyninst::Address start = libc->getSymbolOffset(libc_restore);
254             Dyninst::Address end = libc->getSymbolSize(libc_restore) + start;
255             if (start == end)
256                end = start + 16; //Estimate--annoying
257             sw_printf("[%s:%u] - Registering libc restore_rt as at %lx to %lx\n",
258                       __FILE__, __LINE__, start, end);
259             group->addStepper(parent_stepper, start, end);
260          }
261       }
262    }
263
264    if (!init_libthread) {
265       /**
266        * Get __restore_rt out of libpthread
267        **/
268       LibAddrPair libpthread_addr;
269       Dyninst::SymReader *libpthread = NULL;
270       Symbol_t libpthread_restore;
271       bool result  = libs->getLibthread(libpthread_addr);
272       if (!result) {
273          sw_printf("[%s:%u] - Unable to find libpthread, not registering restore_rt"
274                    "pthread tracker.\n", __FILE__, __LINE__);
275       }
276       if (result) {
277          libpthread = fact->openSymbolReader(libpthread_addr.first);
278          if (!libpthread) {
279             sw_printf("[%s:%u] - Unable to open libc, not registering restore_rt\n",
280                       __FILE__, __LINE__);
281          }
282          init_libthread = true;
283       }
284       if (libpthread) {
285          libpthread_restore = libpthread->getSymbolByName("__restore_rt");
286          if (!libpthread->isValidSymbol(libpthread_restore)) {
287             sw_printf("[%s:%u] - Unable to find restore_rt in libpthread\n",
288                       __FILE__, __LINE__);
289          }
290          else {
291             Dyninst::Address start = libpthread->getSymbolOffset(libpthread_restore);
292             Dyninst::Address end = libpthread->getSymbolSize(libpthread_restore) + start;
293             if (start == end)
294                end = start + 16; //Estimate--annoying
295             sw_printf("[%s:%u] - Registering libpthread restore_rt as at %lx to %lx\n",
296                       __FILE__, __LINE__, start, end);
297             group->addStepper(parent_stepper, start, end);
298          }
299       }   
300    }
301
302    /**
303     * Get symbols out of vsyscall page
304     **/
305    vsys_info *vsyscall = getVsysInfo(ps);
306    if (!vsyscall)
307    {
308 #if !defined(arch_x86_64)
309       sw_printf("[%s:%u] - Odd.  Couldn't find vsyscall page. Signal handler"
310                 " stepping may not work\n", __FILE__, __LINE__);
311 #endif
312    }
313    else
314    {
315       SymReader *vsys_syms = vsyscall->syms;
316       if (!vsys_syms) {
317          sw_printf("[%s:%u] - Vsyscall page wasn't parsed\n", __FILE__, __LINE__);
318       }
319       else {
320          for (unsigned i=0; i<NUM_VSYS_SIGRETURNS; i++)
321          {
322             Symbol_t sym;
323             sym = vsys_syms->getSymbolByName(vsys_sigreturns[i]);
324             if (!vsys_syms->isValidSymbol(sym))
325                continue;
326             
327             Dyninst::Offset offset = vsys_syms->getSymbolOffset(sym);
328             Dyninst::Address addr;
329             if (offset < vsyscall->start)
330                addr = offset + vsyscall->start;
331             else
332                addr = offset;
333             unsigned long size = vsys_syms->getSymbolSize(sym);
334             if (!size) 
335                size = ps->getAddressWidth();
336             
337             group->addStepper(parent_stepper, addr, addr + size);
338          }
339       }
340    }
341 }