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