Clean compiler warnings
[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/h/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 static const Dyninst::Address START_HEURISTIC_LENGTH = 43;
284
285 void BottomOfStackStepperImpl::initialize()
286 {
287    ProcessState *proc = walker->getProcessState();
288    assert(proc);
289
290    sw_printf("[%s:%u] - Initializing BottomOfStackStepper\n", FILE__, __LINE__);
291    
292    LibraryState *libs = proc->getLibraryTracker();
293    if (!libs) {
294       sw_printf("[%s:%u] - Error initing StackBottom.  No library state for process.\n",
295                 FILE__, __LINE__);
296       return;
297    }
298    SymbolReaderFactory *fact = Walker::getSymbolReader();
299    if (!fact) {
300       sw_printf("[%s:%u] - Failed to get symbol reader\n");
301       return;
302    }
303
304    if (!aout_init)
305    {
306       LibAddrPair aout_addr;
307       SymReader *aout = NULL;
308       Symbol_t start_sym;
309       bool result = libs->getAOut(aout_addr);
310       if (result) {
311          aout = fact->openSymbolReader(aout_addr.first);
312          aout_init = true;
313       }
314       if (aout) {
315          start_sym = aout->getSymbolByName(START_FUNC_NAME);
316          if (aout->isValidSymbol(start_sym)) {
317             Dyninst::Address start = aout->getSymbolOffset(start_sym)+aout_addr.second;
318             Dyninst::Address end = aout->getSymbolSize(start_sym) + start;
319             if (start == end) {
320                sw_printf("[%s:%u] - %s symbol has 0 length, using length of %lu\n",
321                        FILE__, __LINE__, START_FUNC_NAME, START_HEURISTIC_LENGTH);
322                end = start + START_HEURISTIC_LENGTH;
323             }
324             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for start\n", 
325                       FILE__, __LINE__, start, end);
326             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
327          }
328       }
329    }
330
331    if (!libthread_init)
332    {
333       LibAddrPair libthread_addr;
334       SymReader *libthread = NULL;
335       Symbol_t clone_sym, startthread_sym;
336       bool result = libs->getLibthread(libthread_addr);
337       if (result) {
338          libthread = fact->openSymbolReader(libthread_addr.first);
339          libthread_init = true;
340       }
341       if (libthread) {
342          clone_sym = libthread->getSymbolByName(CLONE_FUNC_NAME);
343          if (libthread->isValidSymbol(clone_sym)) {
344             Dyninst::Address start = libthread->getSymbolOffset(clone_sym) + 
345                libthread_addr.second;
346             Dyninst::Address end = libthread->getSymbolSize(clone_sym) + start;
347             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for clone\n", 
348                       FILE__, __LINE__, start, end);
349             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
350          }
351          startthread_sym = libthread->getSymbolByName(START_THREAD_FUNC_NAME);
352          if (libthread->isValidSymbol(startthread_sym)) {
353             Dyninst::Address start = libthread->getSymbolOffset(startthread_sym) + 
354                libthread_addr.second;
355             Dyninst::Address end = libthread->getSymbolSize(startthread_sym) + start;
356             sw_printf("[%s:%u] - Bottom stepper taking %lx to %lx for start_thread\n", 
357                       FILE__, __LINE__, start, end);
358             ra_stack_tops.push_back(std::pair<Address, Address>(start, end));
359          }
360       }
361    }
362 }
363
364 SigHandlerStepperImpl::SigHandlerStepperImpl(Walker *w, SigHandlerStepper *parent) :
365    FrameStepper(w),
366    parent_stepper(parent),
367    init_libc(false),
368    init_libthread(false)
369 {
370 }
371
372 unsigned SigHandlerStepperImpl::getPriority() const
373 {
374    return sighandler_priority;
375 }
376
377 SigHandlerStepperImpl::~SigHandlerStepperImpl()
378 {
379 }
380
381 void SigHandlerStepperImpl::newLibraryNotification(LibAddrPair *, lib_change_t change)
382 {
383    if (change == library_unload)
384       return;
385    StepperGroup *group = getWalker()->getStepperGroup();
386    registerStepperGroup(group);
387 }