third party sw is good, not well tested
[dyninst.git] / stackwalk / src / linuxbsd-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/sw.h"
39 #include "stackwalk/src/symtab-swk.h"
40 #include "stackwalk/src/libstate.h"
41 #include "stackwalk/src/get_trap_instruction.h"
42
43 #include <cerrno>
44 #include <cstring>
45
46 #include <sys/mman.h>
47 #include <sys/types.h>
48 #include <unistd.h>
49 #include <signal.h>
50
51 #include "Elf_X.h"
52
53 using namespace Dyninst;
54 using namespace Dyninst::Stackwalker;
55
56 #if defined(WITH_SYMLITE)
57 #include "symlite/h/SymLite-elf.h"
58 #elif defined(WITH_SYMTAB_API)
59 #include "symtabAPI/h/SymtabReader.h"
60 #else
61 #error "No defined symbol reader"
62 #endif
63
64 #include "linuxbsd-swk.h"
65
66
67 extern int P_gettid();
68
69 SymbolReaderFactory *Dyninst::Stackwalker::getDefaultSymbolReader()
70 {
71 #if defined(WITH_SYMLITE)
72    static SymElfFactory symelffact;
73    return &symelffact;
74 #elif defined(WITH_SYMTAB_API)
75    return SymtabAPI::getSymtabReaderFactory();
76 #else
77 #error "No defined symbol reader"
78 #endif
79 }
80
81 static void registerLibSpotterSelf(ProcSelf *pself);
82
83 ProcSelf::ProcSelf(std::string exe_path) :
84     ProcessState(getpid(), exe_path)
85 {
86 }
87
88 void ProcSelf::initialize()
89 {
90     setDefaultLibraryTracker();
91     assert(library_tracker);
92     registerLibSpotterSelf(this);
93 }
94
95 #if defined(cap_sw_catchfaults)
96
97 #include <setjmp.h>
98
99 static bool registered_handler = false;
100 static bool reading_memory = false;
101 sigjmp_buf readmem_jmp;
102
103 void handle_fault(int /*sig*/) {
104     if( !reading_memory ) {
105       //The instruction that caused this fault was not from
106       // ProcSelf::readMem.  Restore the SIGSEGV handler, and
107       // the faulting instruction should restart after we return.
108       fprintf(stderr, "[%s:%u] - Caught segfault that didn't come " \
109               "from stackwalker memory read!", FILE__, __LINE__);
110       signal(SIGSEGV, SIG_DFL);
111       return;
112    }
113    siglongjmp(readmem_jmp, 1);
114 }
115
116 bool ProcSelf::readMem(void *dest, Address source, size_t size) {
117     if( !registered_handler ) {
118         signal(SIGSEGV, handle_fault);
119         registered_handler = true;
120     }
121     reading_memory = true;
122     if( sigsetjmp(readmem_jmp, 1) ) {
123         sw_printf("[%s:%u] - Caught fault while reading from %lx to %lx\n",
124                 FILE__, __LINE__, source, source + size);
125         setLastError(err_procread, "Could not read from process");
126         return false;
127     }
128
129     memcpy(dest, (const void *) source, size);
130     reading_memory = false;
131     return true;
132 }
133 #else
134 bool ProcSelf::readMem(void *dest, Address source, size_t size)
135 {
136     memcpy(dest, (const void *) source, size);
137     return true;
138 }
139 #endif
140
141 bool ProcSelf::getThreadIds(std::vector<THR_ID> &threads) {
142     bool result;
143     THR_ID tid;
144
145     result = getDefaultThread(tid);
146
147     if( !result ) {
148         sw_printf("[%s:%u] - Could not read default thread\n",
149                 FILE__, __LINE__);
150         return false;
151     }
152
153     threads.clear();
154     threads.push_back(tid);
155     return true;
156 }
157
158 bool ProcSelf::getDefaultThread(THR_ID &default_tid)
159 {
160     THR_ID tid = P_gettid();
161     if( tid <= 0 ) {
162         const char *sys_err_msg = strerror(errno);
163         sw_printf("[%s:%u] - gettid syscall failed with %s\n",
164                 FILE__, __LINE__, sys_err_msg);
165         // Note, it's illegal to use a string temp for setLastError, so this
166         // just sets a non-specific const message instead.  But P_gettid
167         // should never fail anyway, as even ENOSYS is retried with getpid.
168         setLastError(err_internal, "gettid syscall failed");
169         return false;
170     }
171
172     default_tid = tid;
173     return true;
174 }
175
176 #if !defined(os_bgq)
177 static LibraryState *local_lib_state = NULL;
178 extern "C" {
179    static void lib_trap_handler(int sig);
180 }
181 static void lib_trap_handler(int /*sig*/)
182 {
183    local_lib_state->notifyOfUpdate();
184 }
185
186 static Address lib_trap_addr_self = 0x0;
187 static bool lib_trap_addr_self_err = false;
188 static void registerLibSpotterSelf(ProcSelf *pself)
189 {
190    if (lib_trap_addr_self)
191       return;
192    if (lib_trap_addr_self_err)
193       return;
194
195    //Get the address to install a trap to
196    LibraryState *libs = pself->getLibraryTracker();
197    if (!libs) {
198       sw_printf("[%s:%u] - Not using lib tracker, don't know how "
199                 "to get library load address\n", FILE__, __LINE__);
200       lib_trap_addr_self_err = true;
201       return;
202    }
203    lib_trap_addr_self = libs->getLibTrapAddress();
204    if (!lib_trap_addr_self) {
205       sw_printf("[%s:%u] - Error getting trap address, can't install lib tracker",
206                 FILE__, __LINE__);
207       lib_trap_addr_self_err = true;
208       return;
209    }
210
211    //Use /proc/PID/maps to make sure that this address is valid and writable
212    unsigned maps_size;
213    map_entries *maps = getVMMaps(getpid(), maps_size);
214    if (!maps) {
215       sw_printf("[%s:%u] - Error reading proc/%d/maps.  Can't install lib tracker",
216                 FILE__, __LINE__, getpid());
217       lib_trap_addr_self_err = true;
218       return;
219    }
220
221    bool found = false;
222    for (unsigned i=0; i<maps_size; i++) {
223       if (maps[i].start <= lib_trap_addr_self &&
224           maps[i].end > lib_trap_addr_self)
225       {
226          found = true;
227          if (maps[i].prems & PREMS_WRITE) {
228             break;
229          }
230          int pgsize = getpagesize();
231          Address first_page = (lib_trap_addr_self / pgsize) * pgsize;
232          unsigned size = pgsize;
233          if (first_page + size < lib_trap_addr_self+MAX_TRAP_LEN)
234             size += pgsize;
235          int result = mprotect((void*) first_page,
236                                size,
237                                PROT_READ|PROT_WRITE|PROT_EXEC);
238          if (result == -1) {
239             int errnum = errno;
240             sw_printf("[%s:%u] - Error setting premissions for page containing %lx. "
241                       "Can't install lib tracker: %s\n", FILE__, __LINE__,
242                       lib_trap_addr_self, strerror(errnum));
243             free(maps);
244             lib_trap_addr_self_err = true;
245             return;
246          }
247       }
248    }
249    free(maps);
250    if (!found) {
251       sw_printf("[%s:%u] - Couldn't find page containing %lx.  Can't install lib "
252                 "tracker.", FILE__, __LINE__, lib_trap_addr_self);
253       lib_trap_addr_self_err = true;
254       return;
255    }
256
257    char trap_buffer[MAX_TRAP_LEN];
258    unsigned actual_len;
259    getTrapInstruction(trap_buffer, MAX_TRAP_LEN, actual_len, true);
260
261    local_lib_state = libs;
262    signal(SIGTRAP, lib_trap_handler);
263
264    memcpy((void*) lib_trap_addr_self, trap_buffer, actual_len);
265    sw_printf("[%s:%u] - Successfully install lib tracker at 0x%lx\n",
266             FILE__, __LINE__, lib_trap_addr_self);
267 }
268 #else
269 static void registerLibSpotterSelf(ProcSelf *)
270 {
271 }
272 #endif
273
274 void BottomOfStackStepperImpl::newLibraryNotification(LibAddrPair *, lib_change_t change)
275 {
276    if (change == library_unload)
277       return;
278    if (!libthread_init || !aout_init) {
279       initialize();
280    }
281 }
282
283 #if defined(arch_aarch64)
284 static const Dyninst::Address START_HEURISTIC_LENGTH = 44;
285 #else
286 static const Dyninst::Address START_HEURISTIC_LENGTH = 43;
287 #endif
288
289 void BottomOfStackStepperImpl::initialize()
290 {
291    ProcessState *proc = walker->getProcessState();
292    assert(proc);
293
294    sw_printf("[%s:%u] - Initializing BottomOfStackStepper\n", FILE__, __LINE__);
295
296    LibraryState *libs = proc->getLibraryTracker();
297    if (!libs) {
298       sw_printf("[%s:%u] - Error initing StackBottom.  No library state for process.\n",
299                 FILE__, __LINE__);
300       return;
301    }
302    SymbolReaderFactory *fact = Walker::getSymbolReader();
303    if (!fact) {
304       sw_printf("[%s:%u] - Failed to get symbol reader\n");
305       return;
306    }
307
308    if (!aout_init)
309    {
310       LibAddrPair aout_addr;
311       SymReader *aout = NULL;
312       Symbol_t start_sym;
313       bool result = libs->getAOut(aout_addr);
314       if (result) {
315          aout = fact->openSymbolReader(aout_addr.first);
316          aout_init = true;
317       }
318       if (aout) {
319          start_sym = aout->getSymbolByName(START_FUNC_NAME);
320          if (aout->isValidSymbol(start_sym)) {
321             Dyninst::Address start = aout->getSymbolOffset(start_sym)+aout_addr.second;
322             Dyninst::Address end = aout->getSymbolSize(start_sym) + start;
323             if (start == end) {
324                sw_printf("[%s:%u] - %s symbol has 0 length, using length of %lu\n",
325                        FILE__, __LINE__, START_FUNC_NAME, START_HEURISTIC_LENGTH);
326                end = start + START_HEURISTIC_LENGTH;
327             }
328             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for start\n",
329                       FILE__, __LINE__, start, end);
330             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
331          }
332       }
333    }
334
335    if (!libthread_init)
336    {
337       LibAddrPair libthread_addr;
338       SymReader *libthread = NULL;
339       Symbol_t clone_sym, startthread_sym;
340       bool result = libs->getLibthread(libthread_addr);
341       if (result) {
342          libthread = fact->openSymbolReader(libthread_addr.first);
343          libthread_init = true;
344       }
345       if (libthread) {
346          clone_sym = libthread->getSymbolByName(CLONE_FUNC_NAME);
347          if (libthread->isValidSymbol(clone_sym)) {
348             Dyninst::Address start = libthread->getSymbolOffset(clone_sym) +
349                libthread_addr.second;
350             Dyninst::Address end = libthread->getSymbolSize(clone_sym) + start;
351             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for clone\n",
352                       FILE__, __LINE__, start, end);
353             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
354          }
355          startthread_sym = libthread->getSymbolByName(START_THREAD_FUNC_NAME);
356          if (libthread->isValidSymbol(startthread_sym)) {
357             Dyninst::Address start = libthread->getSymbolOffset(startthread_sym) +
358                libthread_addr.second;
359             Dyninst::Address end = libthread->getSymbolSize(startthread_sym) + start;
360             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for start_thread\n",
361                       FILE__, __LINE__, start, end);
362             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
363          }
364       }
365    }
366 }
367
368 SigHandlerStepperImpl::SigHandlerStepperImpl(Walker *w, SigHandlerStepper *parent) :
369    FrameStepper(w),
370    parent_stepper(parent),
371    init_libc(false),
372    init_libthread(false)
373 {
374 }
375
376 unsigned SigHandlerStepperImpl::getPriority() const
377 {
378    return sighandler_priority;
379 }
380
381 SigHandlerStepperImpl::~SigHandlerStepperImpl()
382 {
383 }
384
385 void SigHandlerStepperImpl::newLibraryNotification(LibAddrPair *, lib_change_t change)
386 {
387    if (change == library_unload)
388       return;
389    StepperGroup *group = getWalker()->getStepperGroup();
390    registerStepperGroup(group);
391 }