GCC 4.8 build fixes: ensure all extern template declarations are in fact extern'ed...
[dyninst.git] / stackwalk / src / linux-swk.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "stackwalk/h/swk_errors.h"
32 #include "stackwalk/h/symlookup.h"
33 #include "stackwalk/h/walker.h"
34 #include "stackwalk/h/steppergroup.h"
35 #include "stackwalk/h/procstate.h"
36 #include "stackwalk/h/frame.h"
37
38 #include "stackwalk/src/linuxbsd-swk.h"
39 #include "stackwalk/src/sw.h"
40 #include "stackwalk/src/symtab-swk.h"
41 #include "stackwalk/src/libstate.h"
42
43 #include "common/src/parseauxv.h"
44
45 #include <string>
46 #include <sstream>
47
48 #include <string.h>
49 #include <sys/syscall.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <assert.h>
53 #include <signal.h>
54 #include <sys/types.h>
55 #include <sys/wait.h>
56 #include <sys/mman.h>
57 #include <fcntl.h>
58 #include <poll.h>
59
60 #include "common/src/parseauxv.h"
61 #include "common/h/dyn_regs.h"
62
63 #include "symtabAPI/h/SymtabReader.h"
64
65 using namespace Dyninst;
66 using namespace Dyninst::Stackwalker;
67
68 #ifndef SYS_tkill
69 #define SYS_tkill 238
70 #endif
71
72 //These should be defined on all modern linux's, turn these off
73 // if porting to some linux-like platform that doesn't support 
74 // them.
75 #include <sys/ptrace.h>
76 typedef enum __ptrace_request pt_req;
77 #define cap_ptrace_traceclone
78 #define cap_ptrace_setoptions
79
80 int P_gettid()
81 {
82   static int gettid_not_valid = 0;
83   long int result;
84
85   if (gettid_not_valid)
86     return getpid();
87
88   result = syscall(SYS_gettid);
89   if (result == -1 && errno == ENOSYS)
90   {
91     gettid_not_valid = 1;
92     return getpid();
93   }
94   return (int) result;
95 }
96
97 vsys_info *Dyninst::Stackwalker::getVsysInfo(ProcessState *ps)
98 {
99 #if defined(arch_x86_64)
100    if (ps->getAddressWidth() == 8)
101       return NULL;
102 #endif
103
104    static std::map<ProcessState *, vsys_info *> vsysmap;
105    vsys_info *ret = NULL;
106    Address start, end;
107    char *buffer = NULL;
108    SymReader *reader = NULL;
109    SymbolReaderFactory *fact = NULL;
110    bool result;
111    std::stringstream ss;
112
113    std::map<ProcessState *, vsys_info *>::iterator i = vsysmap.find(ps);
114    if (i != vsysmap.end())
115       return i->second;
116    
117    AuxvParser *parser = AuxvParser::createAuxvParser(ps->getProcessId(),
118                                                      ps->getAddressWidth());
119    if (!parser) {
120       sw_printf("[%s:%u] - Unable to parse auxv for %d\n", FILE__, __LINE__,
121                 ps->getProcessId());
122       goto done;
123    }
124
125    start = parser->getVsyscallBase();
126    end = parser->getVsyscallEnd();
127    sw_printf("[%s:%u] - Found vsyscall over range %lx to %lx\n",
128              FILE__, __LINE__, start, end);   
129    parser->deleteAuxvParser();
130    
131    if (!start || !end || end == start)
132    {
133       sw_printf("[%s:%u] - Error collecting vsyscall base and end\n",
134                 FILE__, __LINE__);
135       goto done;
136    }
137
138    ret = new vsys_info();
139    assert(ret);
140    ret->start = start;
141    ret->end = end;
142
143    buffer = (char *) malloc(end - start);
144    assert(buffer);
145    result = ps->readMem(buffer, start, end - start);
146    if (!result) {
147       sw_printf("[%s:%u] - Error reading vsys memory\n", FILE__, __LINE__);
148       goto done;
149    }
150    ret->vsys_mem = buffer;
151
152    fact = Walker::getSymbolReader();
153    if (!fact) {
154       sw_printf("[%s:%u] - No symbol reading capability\n",
155                 FILE__, __LINE__);
156       goto done;
157    }   
158    reader = fact->openSymbolReader(buffer, end - start);
159    if (!reader) {
160       sw_printf("[%s:%u] - Error reading symbol info\n");
161       goto done;
162    }
163    ret->syms = reader;
164
165    ss << "[vsyscall-" << ps->getProcessId() << "]";
166    ret->name = ss.str();
167    LibraryWrapper::registerLibrary(reader, ret->name);
168
169   done:
170    vsysmap[ps] = ret;
171    return ret;
172 }
173
174 bool LibraryState::updateLibsArch(std::vector<std::pair<LibAddrPair, unsigned int> > &alibs)
175 {
176    if (arch_libs.size()) {
177       alibs = arch_libs;
178       return true;
179    }
180    vsys_info *vsys = getVsysInfo(procstate);
181    if (!vsys) {
182       return false;
183    }
184
185    LibAddrPair vsyscall_page;
186    vsyscall_page.first = vsys->name;
187    vsyscall_page.second = vsys->start;
188    std::pair<LibAddrPair, unsigned int> vsyscall_lib_pair;
189    vsyscall_lib_pair.first = vsyscall_page;
190    vsyscall_lib_pair.second = static_cast<unsigned int>(vsys->end - vsys->start);
191    arch_libs.push_back(vsyscall_lib_pair);
192    alibs = arch_libs;
193
194    return true;
195 }
196
197 #define NUM_VSYS_SIGRETURNS 3
198 static const char* vsys_sigreturns[] = {
199    "_sigreturn",
200    "__kernel_sigreturn",
201    "__kernel_rt_sigreturn"
202 };
203
204 void SigHandlerStepperImpl::registerStepperGroup(StepperGroup *group)
205 {
206   sw_printf("[%s:%u] - Begin SigHandlerStepperImpl::registerStepperGroup\n", FILE__, __LINE__);
207    ProcessState *ps = getProcessState();
208    assert(ps);
209
210    LibraryState *libs = getProcessState()->getLibraryTracker();
211    if (!libs) {
212       sw_printf("[%s:%u] - Custom library tracker.  Don't know how to"
213                 " to get libc\n", FILE__, __LINE__);
214       return;
215    }
216    SymbolReaderFactory *fact = Walker::getSymbolReader();
217    if (!fact) {
218       sw_printf("[%s:%u] - Failed to get symbol reader\n", FILE__, __LINE__);
219       return;
220    }
221   sw_printf("[%s:%u] - Got lib tracker and sym reader OK, checking for __restore_rt...\n", FILE__, __LINE__);
222
223    if (!init_libc) {
224       /**
225        * Get __restore_rt out of libc
226        **/
227       sw_printf("[%s:%u] - Getting __restore_rt from libc\n", FILE__, __LINE__);
228       LibAddrPair libc_addr;
229       Dyninst::SymReader *libc = NULL;
230       Symbol_t libc_restore;
231       bool result = libs->getLibc(libc_addr);
232       if (!result) {
233          sw_printf("[%s:%u] - Unable to find libc, not registering restore_rt"
234                    "tracker.\n", FILE__, __LINE__);
235       }
236       if (!init_libc) {
237          if (result) {
238             init_libc = true;
239             libc = fact->openSymbolReader(libc_addr.first);
240             if (!libc) {
241                sw_printf("[%s:%u] - Unable to open libc, not registering restore_rt\n",
242                          FILE__, __LINE__);
243             }   
244          }
245          if (result && libc) {
246             init_libc = true;
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) + libc_addr.second;
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
265    if (!init_libthread) {
266       /**
267        * Get __restore_rt out of libpthread
268        **/
269       sw_printf("[%s:%u] - Getting __restore_rt out of libpthread\n", FILE__, __LINE__);
270       LibAddrPair libpthread_addr;
271       Dyninst::SymReader *libpthread = NULL;
272       Symbol_t libpthread_restore;
273       bool result  = libs->getLibthread(libpthread_addr);
274       if (!result) {
275          sw_printf("[%s:%u] - Unable to find libpthread, not registering restore_rt"
276                    "pthread tracker.\n", FILE__, __LINE__);
277       }
278       if (result) {
279          libpthread = fact->openSymbolReader(libpthread_addr.first);
280          if (!libpthread) {
281             sw_printf("[%s:%u] - Unable to open libc, not registering restore_rt\n",
282                       FILE__, __LINE__);
283          }
284          init_libthread = true;
285       }
286       if (libpthread) {
287          libpthread_restore = libpthread->getSymbolByName("__restore_rt");
288          if (!libpthread->isValidSymbol(libpthread_restore)) {
289             sw_printf("[%s:%u] - Unable to find restore_rt in libpthread\n",
290                       FILE__, __LINE__);
291          }
292          else {
293             Dyninst::Address start = libpthread->getSymbolOffset(libpthread_restore) + libpthread_addr.second;
294             Dyninst::Address end = libpthread->getSymbolSize(libpthread_restore) + start;
295             if (start == end)
296                end = start + 16; //Estimate--annoying
297             sw_printf("[%s:%u] - Registering libpthread restore_rt as at %lx to %lx\n",
298                       FILE__, __LINE__, start, end);
299             group->addStepper(parent_stepper, start, end);
300          }
301       }   
302    }
303
304    /**
305     * Get symbols out of vsyscall page
306     **/
307    sw_printf("[%s:%u] - Getting vsyscall page symbols\n", FILE__, __LINE__);
308    vsys_info *vsyscall = getVsysInfo(ps);
309    if (!vsyscall)
310    {
311 #if !defined(arch_x86_64)
312       sw_printf("[%s:%u] - Odd.  Couldn't find vsyscall page. Signal handler"
313                 " stepping may not work\n", FILE__, __LINE__);
314 #endif
315    }
316    else
317    {
318       SymReader *vsys_syms = vsyscall->syms;
319       if (!vsys_syms) {
320          sw_printf("[%s:%u] - Vsyscall page wasn't parsed\n", FILE__, __LINE__);
321       }
322       else {
323          for (unsigned i=0; i<NUM_VSYS_SIGRETURNS; i++)
324          {
325             Symbol_t sym;
326             sym = vsys_syms->getSymbolByName(vsys_sigreturns[i]);
327             if (!vsys_syms->isValidSymbol(sym))
328                continue;
329             
330             Dyninst::Offset offset = vsys_syms->getSymbolOffset(sym);
331             Dyninst::Address addr;
332             if (offset < vsyscall->start)
333                addr = offset + vsyscall->start;
334             else
335                addr = offset;
336             unsigned long size = vsys_syms->getSymbolSize(sym);
337             if (!size) 
338                size = ps->getAddressWidth();
339             
340             group->addStepper(parent_stepper, addr, addr + size);
341          }
342       }
343    }
344 }