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