1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)signal_catch.c 1.14 09/05/26 SMI" 28 29 #include <siginfo.h> 30 #include <signal.h> 31 #include <ucontext.h> 32 #include <sys/time.h> /* for gettimeofday */ 33 #include <time.h> /* for strftime */ 34 #include <string.h> /* for strerror */ 35 #include <stdlib.h> 36 #include <unistd.h> /* for pause */ 37 #include <diskomizer/stack_trace.h> 38 #include "args.h" 39 #include <diskomizer/log.h> 40 #include "list.h" 41 #ident "@(#)signal_catch.c 1.9 03/12/02" 42 #define TIME_FORMAT "%T %d/%b/%Y" 43 44 struct sig_head { 45 struct sig_lists *head; 46 struct sig_lists *tail; 47 }; 48 struct sig_lists { 49 struct sig_lists *next; 50 struct sig_lists *prev; 51 char *str; 52 void *addr; 53 off_t len; 54 }; 55 struct expected { 56 int max_sig; 57 struct sig_head *signals; 58 }; 59 struct expected expected; 60 61 #include <stdarg.h> 62 /*PRINTFLIKE2*/ 63 static int 64 mprintf(void *XX, const char *fmt, ...) 65 { 66 va_list ap; 67 char buf[256]; 68 int x; 69 int written = 0; 70 va_start(ap, fmt); 71 72 x = vsnprintf(buf, sizeof (buf), fmt, ap); 73 74 while ((x - written) != 0) { 75 int r; 76 r = write(STDERR_FILENO, &buf[written], x - written); 77 if (r <= 0) { 78 break; 79 } 80 written += r; 81 } 82 83 return (written); 84 } 85 86 static void 87 mprint_fpeinfo(FILE *out, siginfo_t *info) 88 { 89 switch (info->si_code) { 90 case 0: 91 (void) mprintf(out, "FPE sent by UID %d PID %d,\n", 92 info->si_uid, info->si_pid); 93 break; 94 case FPE_INTDIV: 95 (void) mprintf(out, "integer divide by zero\n"); 96 break; 97 case FPE_INTOVF: 98 (void) mprintf(out, "integer overflow\n"); 99 break; 100 case FPE_FLTDIV: 101 (void) mprintf(out, "floating point divide by zero\n"); 102 break; 103 case FPE_FLTOVF: 104 (void) mprintf(out, "floating point overflow\n"); 105 break; 106 case FPE_FLTUND: 107 (void) mprintf(out, "floating point underflow\n"); 108 break; 109 case FPE_FLTRES: 110 (void) mprintf(out, "floating point inexact result\n"); 111 break; 112 case FPE_FLTINV: 113 (void) mprintf(out, 114 "invalid floating point operation\n"); 115 break; 116 case FPE_FLTSUB: 117 (void) mprintf(out, "subscript out of range\n"); 118 break; 119 } 120 } 121 static void 122 mprint_illinfo(FILE *out, siginfo_t *info) 123 { 124 switch (info->si_code) { 125 case 0: 126 (void) mprintf(out, 127 "ILL sent by UID %d PID %d,\n", 128 info->si_uid, info->si_pid); 129 break; 130 case ILL_ILLOPC: 131 (void) mprintf(out, "illegal opcode\n"); 132 break; 133 case ILL_ILLOPN: 134 (void) mprintf(out, "illegal operand\n"); 135 break; 136 case ILL_ILLADR: 137 (void) mprintf(out, "illegal addressing mode\n"); 138 break; 139 case ILL_ILLTRP: 140 (void) mprintf(out, "illegal trap\n"); 141 break; 142 case ILL_PRVOPC: 143 (void) mprintf(out, "privileged opcode\n"); 144 break; 145 case ILL_PRVREG: 146 (void) mprintf(out, "privileged register\n"); 147 break; 148 case ILL_COPROC: 149 (void) mprintf(out, "co-processor error\n"); 150 break; 151 case ILL_BADSTK: 152 (void) mprintf(out, "internal stack error\n"); 153 break; 154 } 155 (void) mprintf(out, "Illegal Instruction address %#lx value %#lx\n", 156 (ulong_t)info->si_addr, *(ulong_t *)info->si_addr); 157 } 158 static void 159 mprint_segvinfo(FILE *out, siginfo_t *info) 160 { 161 switch (info->si_code) { 162 case 0: 163 (void) mprintf(out, 164 "SEGV sent by UID %d PID %d,\n", 165 info->si_uid, info->si_pid); 166 break; 167 case SEGV_MAPERR: 168 (void) mprintf(out, 169 "SEGV_MAPERR: address not mapped to object\n"); 170 break; 171 case SEGV_ACCERR: 172 (void) mprintf(out, 173 "SEGV_ACCERR: invalid permissions for mapped " 174 "object\n"); 175 break; 176 177 } 178 (void) mprintf(out, "Fault address %#lx\n", (ulong_t)info->si_addr); 179 } 180 static void 181 mprint_businfo(FILE *out, siginfo_t *info) 182 { 183 switch (info->si_code) { 184 case 0: 185 (void) mprintf(out, "BUS sent by UID %d PID %d,\n", 186 info->si_uid, info->si_pid); 187 break; 188 case BUS_ADRALN: 189 (void) mprintf(out, 190 "BUS_ADRALN: invalid address alignment\n"); 191 break; 192 case BUS_ADRERR: 193 (void) mprintf(out, 194 "BUS_ADRERR: non-existent physical address\n"); 195 break; 196 case BUS_OBJERR: 197 (void) mprintf(out, 198 "BUS_OBJERR: object specific hardware error\n"); 199 break; 200 201 } 202 (void) mprintf(out, "Address %#lx\n", (ulong_t)info->si_addr); 203 } 204 205 static void 206 mprint_siginfo(FILE *out, int signo, siginfo_t *info) 207 { 208 switch (signo) { 209 case SIGSEGV: 210 mprint_segvinfo(out, info); 211 break; 212 case SIGBUS: 213 mprint_businfo(out, info); 214 break; 215 case SIGILL: 216 mprint_illinfo(out, info); 217 break; 218 case SIGFPE: 219 mprint_fpeinfo(out, info); 220 break; 221 } 222 } 223 /* 224 * Expect signal. 225 * 226 * Called to register that getting a particular signal is an 227 * expected error while accessing memory. The caller supplied 228 * the signal, an error string and the memory range. If the 229 * signal is delivered for that memory range then the message 230 * is output, with the error decoded. Then the program exits. 231 * 232 * The reason for this is that when allocating memory using mmap() 233 * and the file is in the file system as opposed to being /dev/zero 234 * if there is insufficient space in the file system then the first 235 * access to the memory will result in SIGBUS being sent to the 236 * process. Now a core file would normally result, or with 237 * the stack trace stuff a stack trace and an exit. Not very 238 * friendly and likely to make people think the probram is broken. 239 */ 240 void * 241 expect_signal(int signo, const char *str, void *addr, off_t len) 242 { 243 struct sig_lists *new; 244 if (expected.max_sig < signo) { 245 struct sig_head *temp; 246 int i; 247 248 temp = realloc(expected.signals, 249 (signo + 1) * sizeof (struct sig_head)); 250 if (temp == NULL) 251 return (NULL); 252 for (i = expected.max_sig; i <= signo; i++) { 253 (void) memset((void *)&temp[i], NULL, 254 sizeof (struct sig_head)); 255 } 256 expected.max_sig = signo; 257 expected.signals = temp; 258 assert(expected.signals[signo].head == NULL && 259 expected.signals[signo].tail == NULL); 260 } 261 262 new = (struct sig_lists *)calloc(1, sizeof (struct sig_lists)); 263 if (new == NULL) 264 return (NULL); 265 if (str != NULL) 266 new->str = strdup(str); 267 new->addr = addr; 268 new->len = len; 269 270 assert((expected.signals[signo].head == NULL && 271 expected.signals[signo].tail == NULL) || 272 (expected.signals[signo].head != NULL && 273 expected.signals[signo].tail != NULL)); 274 LIST_ADD(&expected.signals[signo], new); 275 return ((void *)new); 276 } 277 /* 278 * Cancel Expected Signal: 279 * Given the handle given out above cancel the expection. 280 * the signal reverts to it's standard behviour for that range. 281 */ 282 void 283 cancel_expected_signal(int signo, void *ptr) 284 { 285 struct sig_lists *old = (struct sig_lists *)ptr; 286 if (old == NULL) 287 return; 288 LIST_REMOVE(&expected.signals[signo], old); 289 if (old->str != NULL) 290 free(old->str); 291 free(old); 292 } 293 void 294 check_expected(int signo, void * vaddr, int error) 295 { 296 struct sig_lists *this; 297 ulong_t addr = (ulong_t)vaddr; 298 if (expected.max_sig < signo) 299 return; 300 301 for (this = expected.signals[signo].head; this != NULL; 302 this = this->next) { 303 if (addr >= (ulong_t)this->addr && 304 addr < (ulong_t)this->addr + this->len) { 305 (void) mprintf(NULL, "%s: %s\n", this->str, 306 strerror(error)); 307 exit(1); 308 } 309 } 310 } 311 312 313 void 314 handler(int signo, siginfo_t *info, void *v) 315 { 316 char signame[SIG2STR_MAX]; 317 ucontext_t *context = (ucontext_t *)v; 318 char buf[128]; 319 struct timeval now; 320 extern int errno; 321 struct sigaction action; 322 323 if (gettimeofday(&now, NULL) == -1) { 324 (void) mprintf(NULL, "gettimeofday: %s", strerror(errno)); 325 (void) sprintf(&buf[0], "unknown time"); 326 } else { 327 if (strftime(&buf[0], sizeof (buf), TIME_FORMAT, 328 localtime(&now.tv_sec)) == 0) { 329 if (strftime(&buf[0], sizeof (buf), "%D %T", 330 localtime(&now.tv_sec)) == 0) { 331 (void) sprintf(&buf[0], "Seconds %ld", 332 now.tv_sec); 333 } 334 } 335 } 336 check_expected(signo, info->si_addr, info->si_errno); 337 338 (void) sig2str(signo, &signame[0]); 339 340 (void) mprintf(NULL, "Caught Signal %d (%s) at %s\n", 341 signo, signame, buf); 342 mprint_siginfo(NULL, signo, info); 343 344 ftraceback(mprintf, NULL, context); 345 if (1 == opts.debug_pause_on_signal) 346 pause(); 347 if (0 == opts.debug_allow_coredump) 348 exit(1); 349 350 action.sa_handler = SIG_DFL; 351 action.sa_sigaction = NULL; 352 sigemptyset(&action.sa_mask); 353 action.sa_flags = 0; 354 355 if (sigaction(signo, &action, NULL) == -1) { 356 pperror("sigaction(%d (%s))", signo, signame); 357 } 358 } 359 void 360 setup_signal_catcher(int sig, 361 void (*func)(int signo, siginfo_t *info, void *v), 362 int flags) 363 { 364 char signame[SIG2STR_MAX]; 365 struct sigaction action; 366 367 (void) sig2str(sig, &signame[0]); 368 369 if (sigaction(sig, NULL, &action) == -1) { 370 pperror("sigaction(%d (%s))", sig, signame); 371 exit(1); 372 } 373 action.sa_handler = NULL; 374 action.sa_sigaction = func; 375 action.sa_flags = flags; 376 if (sigaction(sig, &action, NULL) == -1) { 377 pperror("sigaction(%d (%s))", sig, signame); 378 exit(1); 379 } 380 } 381 static void 382 do_signal(int sig) 383 { 384 setup_signal_catcher(sig, handler, SA_SIGINFO|SA_ONSTACK); 385 } 386 /*ARGSUSED*/ 387 void 388 setup_signal(int (*func)(void *, const char *fmt, ...), void * arg) 389 { 390 stack_t stack; 391 392 stack.ss_sp = (char *)calloc(1024*1024/sizeof (int), sizeof (int)); 393 stack.ss_size = 1024*1024; 394 stack.ss_flags = 0; 395 if (sigaltstack(&stack, NULL) == -1) 396 perror("sigaltstack"); 397 398 do_signal(SIGSEGV); 399 do_signal(SIGBUS); 400 do_signal(SIGILL); 401 do_signal(SIGFPE); 402 do_signal(SIGEMT); 403 do_signal(SIGSYS); 404 do_signal(SIGQUIT); 405 do_signal(SIGABRT); 406 } 407 #ifdef TEST_PROG 408 void 409 recurse(int x) 410 { 411 if (x == 0) { 412 int *y; 413 y = recurse; 414 (void) mprintf(stdout, "Addr %#lx %#lx\n", y, &y); 415 *y = 0; 416 } 417 recurse(--x); 418 } 419 main() 420 { 421 setup_signal(fprintf, stdout); 422 recurse(20); 423 } 424 #endif 425