HPCToolkit
segv_handler.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 // system include files
49 //***************************************************************************
50 
51 #include <sys/types.h>
52 #include <stddef.h>
53 #include <ucontext.h>
54 #include <signal.h>
55 #include <dlfcn.h>
56 #include <setjmp.h>
57 #include <signal.h>
58 
59 
60 //***************************************************************************
61 // libmonitor include files
62 //***************************************************************************
63 
64 #include <monitor.h>
65 
66 
67 //***************************************************************************
68 // user include files
69 //***************************************************************************
70 
71 #include "include/queue.h" // Singly-linkled list macros
72 
73 #include "main.h"
74 #include "thread_data.h"
75 #include "handling_sample.h"
76 #include "hpcrun_stats.h"
77 
78 #include "memchk.h"
79 
80 #include <messages/messages.h>
82 
83 #include "segv_handler.h"
84 
85 //*************************** MACROS **************************
86 
87 
88 
89 //*************************** type data structure **************************
90 
91 // list of callbacks
92 typedef struct segv_list_s {
94  SLIST_ENTRY(segv_list_s) entries;
95 } segv_list_t;
96 
97 
98 //*************************** Local variables **************************
99 
100 static SLIST_HEAD(segv_list_head, segv_list_s) list_cb_head =
101  SLIST_HEAD_INITIALIZER(segv_list_head);
102 
103 //***************************************************************************
104 // catch SIGSEGVs
105 //***************************************************************************
106 
107 // FIXME: tallent: should this be together with hpcrun_drop_sample?
108 
109 int
110 hpcrun_sigsegv_handler(int sig, siginfo_t* siginfo, void* context)
111 {
114 
116 
117  // -----------------------------------------------------
118  // print context
119  // -----------------------------------------------------
120  void* ctxt_pc = hpcrun_context_pc(context);
121  if (ENABLED(UNW_SEGV_STOP)){
122  EMSG("Unwind segv abort enabled ... Aborting!!, context pc = %p", ctxt_pc);
124  }
125 
126  EMSG("error: segv: context-pc=%p", ctxt_pc);
127  // TODO: print more context details
128 
129  // -----------------------------------------------------
130  // longjump, if possible
131  // -----------------------------------------------------
132  sigjmp_buf_t *it = NULL;
133 
134  if (td->current_jmp_buf == &(td->bad_interval)) {
135  it = &(td->bad_interval);
136 
137  } else if (td->current_jmp_buf == &(td->bad_unwind)) {
138  it = &(td->bad_unwind);
139  if (memchk((void *)it, '\0', sizeof(*it))) {
140  EMSG("error: segv handler: invalid jmpbuf");
141  // N.B. to handle this we need an 'outer' jump buffer that captures
142  // the context right as we enter the sampling-trigger signal handler.
144  }
145  }
146 
147  hpcrun_bt_dump(td->btbuf_cur, "SEGV");
148 
149  // call clean-up callback functions
150  segv_list_t *item;
151  SLIST_FOREACH(item, &list_cb_head, entries) {
152  if (item->callback != NULL)
153  (*item->callback)();
154  }
155 
156  (*hpcrun_get_real_siglongjmp())(it->jb, 9);
157  return 0;
158  }
159  else {
160  // pass segv to another handler
161  TMSG(SEGV, "NON unwind segv encountered");
162  return 1; // monitor_real_abort(); // TEST
163  }
164 }
165 
166 
167 int
169 {
170  int ret = monitor_sigaction(SIGBUS, &hpcrun_sigsegv_handler, 0, NULL);
171  if (ret != 0) {
172  EMSG("Unable to install SIGBUS handler", __FILE__, __LINE__);
173  }
174 
175  ret = monitor_sigaction(SIGSEGV, &hpcrun_sigsegv_handler, 0, NULL);
176  if (ret != 0) {
177  EMSG("Unable to install SIGSEGV handler", __FILE__, __LINE__);
178  }
179 
180  return ret;
181 }
182 
183 // ------------------------------------------------------------
184 // ------------------------------------------------------------
185 
186 // Interface for callback registerations when a segv occurs.
187 // The callback function will be called when a segv happens.
188 // Returns: 0 if the function is already registered,
189 // 1 if the function is now added to the list
190 // -1 if there's something wrong
191 // Warnning: this function is not thread safe.
192 
193 int
195 {
196  segv_list_t *list_item = NULL;
197 
198  // searching if the callback is already registered
199  SLIST_FOREACH(list_item, &list_cb_head, entries) {
200  if (list_item->callback == cb)
201  return 0;
202  }
203 
204  list_item = (segv_list_t*) hpcrun_malloc(sizeof(segv_list_t));
205  if (list_item == NULL)
206  return -1;
207  list_item->callback = cb;
208 
209  // add the callback into the list
210  SLIST_INSERT_HEAD(&list_cb_head, list_item, entries);
211  return 1;
212 }
213 
214 
struct segv_list_s segv_list_t
#define SLIST_HEAD_INITIALIZER(head)
Definition: queue.h:190
int hpcrun_is_handling_sample(void)
hpcrun_sig_callback_t callback
Definition: segv_handler.c:93
int hpcrun_setup_segv()
Definition: segv_handler.c:168
frame_t * btbuf_cur
Definition: thread_data.h:184
static bool memchk(const char *buf, char v, size_t len)
Definition: memchk.h:53
sigjmp_buf_t bad_unwind
Definition: thread_data.h:213
void hpcrun_stats_num_samples_segv_inc(void)
Definition: hpcrun_stats.c:219
sigjmp_buf_t bad_interval
Definition: thread_data.h:212
#define EMSG
Definition: messages.h:70
static SLIST_HEAD(segv_list_head, segv_list_s)
Definition: segv_handler.c:100
sigjmp_buf_t * current_jmp_buf
Definition: thread_data.h:211
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
#define TMSG(f,...)
Definition: messages.h:93
#define NULL
Definition: ElfHelper.cpp:85
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:233
void(* hpcrun_sig_callback_t)(void)
Definition: segv_handler.h:50
int hpcrun_segv_register_cb(hpcrun_sig_callback_t cb)
Definition: segv_handler.c:194
void hpcrun_bt_dump(frame_t *unwind, const char *tag)
Definition: backtrace.c:90
siglongjmp_fcn * hpcrun_get_real_siglongjmp(void)
Definition: main.c:1142
void monitor_real_abort(void)
void * hpcrun_context_pc(void *context)
sigjmp_buf jb
Definition: thread_data.h:74
#define SLIST_ENTRY(type)
Definition: queue.h:193
#define ENABLED(f)
Definition: debug-flag.h:76
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:267