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 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #pragma weak __fex_get_log = fex_get_log
31 #pragma weak __fex_set_log = fex_set_log
32 #pragma weak __fex_get_log_depth = fex_get_log_depth
33 #pragma weak __fex_set_log_depth = fex_set_log_depth
34 #pragma weak __fex_log_entry = fex_log_entry
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <signal.h>
41 #include <ucontext.h>
42 #include <sys/frame.h>
43 #include <fenv.h>
44 #include <sys/ieeefp.h>
45 #include <thread.h>
46 #include "fex_handler.h"
47
48 #if !defined(PC)
49 #if defined(REG_PC)
50 #define PC REG_PC
51 #else
52 #error Neither PC nor REG_PC is defined!
53 #endif
54 #endif
55
56 static FILE *log_fp = NULL;
57 static mutex_t log_lock = DEFAULTMUTEX;
58 static int log_depth = 100;
59
60 FILE *fex_get_log(void)
61 {
62 FILE *fp;
63
64 mutex_lock(&log_lock);
65 fp = log_fp;
66 mutex_unlock(&log_lock);
67 return fp;
68 }
69
70 int fex_set_log(FILE *fp)
71 {
72 mutex_lock(&log_lock);
73 log_fp = fp;
74 mutex_unlock(&log_lock);
75 __fex_update_te();
76 return 1;
77 }
78
79 int fex_get_log_depth(void)
80 {
81 int d;
82
83 mutex_lock(&log_lock);
84 d = log_depth;
85 mutex_unlock(&log_lock);
86 return d;
87 }
88
89 int fex_set_log_depth(int d)
90 {
91 if (d < 0)
92 return 0;
93 mutex_lock(&log_lock);
94 log_depth = d;
95 mutex_unlock(&log_lock);
96 return 1;
97 }
98
99 static struct exc_list {
100 struct exc_list *next;
101 char *addr;
102 unsigned long code;
103 int nstack;
104 char *stack[1]; /* actual length is max(1,nstack) */
105 } *list = NULL;
106
107 #ifdef __sparcv9
108 #define FRAMEP(X) (struct frame *)((char*)(X)+(((long)(X)&1)?2047:0))
109 #else
110 #define FRAMEP(X) (struct frame *)(X)
111 #endif
112
113 #ifdef _LP64
114 #define PDIG "16"
115 #else
116 #define PDIG "8"
117 #endif
118
119 /* look for a matching exc_list; return 1 if one is found,
120 otherwise add this one to the list and return 0 */
121 static int check_exc_list(char *addr, unsigned long code, char *stk,
122 struct frame *fp)
123 {
124 struct exc_list *l, *ll = NULL;
125 struct frame *f;
126 int i, n;
127
128 if (list) {
129 for (l = list; l; ll = l, l = l->next) {
130 if (l->addr != addr || l->code != code)
131 continue;
132 if (log_depth < 1 || l->nstack < 1)
133 return 1;
134 if (l->stack[0] != stk)
135 continue;
136 n = 1;
137 for (i = 1, f = fp; i < log_depth && i < l->nstack &&
138 f && f->fr_savpc; i++, f = FRAMEP(f->fr_savfp))
139 if (l->stack[i] != (char *)f->fr_savpc) {
140 n = 0;
141 break;
142 }
143 if (n)
144 return 1;
145 }
146 }
147
148 /* create a new exc_list structure and tack it on the list */
149 for (n = 1, f = fp; n < log_depth && f && f->fr_savpc;
150 n++, f = FRAMEP(f->fr_savfp)) ;
151 if ((l = (struct exc_list *)malloc(sizeof(struct exc_list) +
152 (n - 1) * sizeof(char *))) != NULL) {
153 l->next = NULL;
154 l->addr = addr;
155 l->code = code;
156 l->nstack = ((log_depth < 1)? 0 : n);
157 l->stack[0] = stk;
158 for (i = 1; i < n; i++) {
159 l->stack[i] = (char *)fp->fr_savpc;
160 fp = FRAMEP(fp->fr_savfp);
161 }
162 if (list)
163 ll->next = l;
164 else
165 list = l;
166 }
167 return 0;
168 }
169
170 /*
171 * Warning: cleverness ahead
172 *
173 * In the following code, the use of sprintf+write rather than fprintf
174 * to send output to the log file is intentional. The reason is that
175 * fprintf is not async-signal-safe. "But," you protest, "SIGFPE is
176 * not an asynchronous signal! It's always handled by the same thread
177 * that executed the fpop that provoked it." That's true, but a prob-
178 * lem arises because (i) base conversion in fprintf can cause a fp
179 * exception and (ii) my signal handler acquires a mutex lock before
180 * sending output to the log file (so that outputs for entries from
181 * different threads aren't interspersed). Therefore, if the code
182 * were to use fprintf, a deadlock could occur as follows:
183 *
184 * Thread A Thread B
185 *
186 * Incurs a fp exception, Calls fprintf,
187 * acquires log_lock acquires file rmutex lock
188 *
189 * Calls fprintf, Incurs a fp exception,
190 * waits for file rmutex lock waits for log_lock
191 *
192 * (I could just verify that fprintf doesn't hold the rmutex lock while
193 * it's doing the base conversion, but since efficiency is of little
194 * concern here, I opted for the safe and dumb route.)
195 */
196
197 static void print_stack(int fd, char *addr, struct frame *fp)
198 {
199 int i;
200 char *name, buf[30];
201
202 for (i = 0; i < log_depth && addr != NULL; i++) {
203 if (__fex_sym(addr, &name) != NULL) {
204 write(fd, buf, sprintf(buf, " 0x%0" PDIG "lx ",
205 (long)addr));
206 write(fd, name, strlen(name));
207 write(fd, "\n", 1);
208 if (!strcmp(name, "main"))
209 break;
210 } else {
211 write(fd, buf, sprintf(buf, " 0x%0" PDIG "lx\n",
212 (long)addr));
213 }
214 if (fp == NULL)
215 break;
216 addr = (char *)fp->fr_savpc;
217 fp = FRAMEP(fp->fr_savfp);
218 }
219 }
220
221 void fex_log_entry(const char *msg)
222 {
223 ucontext_t uc;
224 struct frame *fp;
225 char *stk;
226 int fd;
227
228 /* if logging is disabled, just return */
229 mutex_lock(&log_lock);
230 if (log_fp == NULL) {
231 mutex_unlock(&log_lock);
232 return;
233 }
234
235 /* get the frame pointer from the current context and
236 pop our own frame */
237 getcontext(&uc);
238 #if defined(__sparc) || defined(__amd64)
239 fp = FRAMEP(uc.uc_mcontext.gregs[REG_SP]);
240 #elif defined(__i386) /* !defined(__amd64) */
241 fp = FRAMEP(uc.uc_mcontext.gregs[EBP]);
242 #else
243 #error Unknown architecture
244 #endif
245 if (fp == NULL) {
246 mutex_unlock(&log_lock);
247 return;
248 }
249 stk = (char *)fp->fr_savpc;
250 fp = FRAMEP(fp->fr_savfp);
251
252 /* if we've already logged this message here, don't make an entry */
253 if (check_exc_list(stk, (unsigned long)msg, stk, fp)) {
254 mutex_unlock(&log_lock);
255 return;
256 }
257
258 /* make an entry */
259 fd = fileno(log_fp);
260 write(fd, "fex_log_entry: ", 15);
261 write(fd, msg, strlen(msg));
262 write(fd, "\n", 1);
263 __fex_sym_init();
264 print_stack(fd, stk, fp);
265 mutex_unlock(&log_lock);
266 }
267
268 static const char *exception[FEX_NUM_EXC] = {
269 "inexact result",
270 "division by zero",
271 "underflow",
272 "overflow",
273 "invalid operation (0/0)",
274 "invalid operation (inf/inf)",
275 "invalid operation (inf-inf)",
276 "invalid operation (0*inf)",
277 "invalid operation (sqrt)",
278 "invalid operation (snan)",
279 "invalid operation (int)",
280 "invalid operation (cmp)"
281 };
282
283 void
284 __fex_mklog(ucontext_t *uap, char *addr, int f, enum fex_exception e,
285 int m, void *p)
286 {
287 struct frame *fp;
288 char *stk, *name, buf[30];
289 int fd;
290
291 /* if logging is disabled, just return */
292 mutex_lock(&log_lock);
293 if (log_fp == NULL) {
294 mutex_unlock(&log_lock);
295 return;
296 }
297
298 /* get stack info */
299 #if defined(__sparc)
300 stk = (char*)uap->uc_mcontext.gregs[REG_PC];
301 fp = FRAMEP(uap->uc_mcontext.gregs[REG_SP]);
302 #elif defined(__amd64)
303 stk = (char*)uap->uc_mcontext.gregs[REG_PC];
304 fp = FRAMEP(uap->uc_mcontext.gregs[REG_RBP]);
305 #elif defined(__i386) /* !defined(__amd64) */
306 stk = (char*)uap->uc_mcontext.gregs[PC];
307 fp = FRAMEP(uap->uc_mcontext.gregs[EBP]);
308 #else
309 #error Unknown architecture
310 #endif
311
312 /* if the handling mode is the default and this exception's
313 flag is already raised, don't make an entry */
314 if (m == FEX_NONSTOP) {
315 switch (e) {
316 case fex_inexact:
317 if (f & FE_INEXACT) {
318 mutex_unlock(&log_lock);
319 return;
320 }
321 break;
322 case fex_underflow:
323 if (f & FE_UNDERFLOW) {
324 mutex_unlock(&log_lock);
325 return;
326 }
327 break;
328 case fex_overflow:
329 if (f & FE_OVERFLOW) {
330 mutex_unlock(&log_lock);
331 return;
332 }
333 break;
334 case fex_division:
335 if (f & FE_DIVBYZERO) {
336 mutex_unlock(&log_lock);
337 return;
338 }
339 break;
340 default:
341 if (f & FE_INVALID) {
342 mutex_unlock(&log_lock);
343 return;
344 }
345 break;
346 }
347 }
348
349 /* if we've already logged this exception at this address,
350 don't make an entry */
351 if (check_exc_list(addr, (unsigned long)e, stk, fp)) {
352 mutex_unlock(&log_lock);
353 return;
354 }
355
356 /* make an entry */
357 fd = fileno(log_fp);
358 write(fd, "Floating point ", 15);
359 write(fd, exception[e], strlen(exception[e]));
360 write(fd, buf, sprintf(buf, " at 0x%0" PDIG "lx", (long)addr));
361 __fex_sym_init();
362 if (__fex_sym(addr, &name) != NULL) {
363 write(fd, " ", 1);
364 write(fd, name, strlen(name));
365 }
366 switch (m) {
367 case FEX_NONSTOP:
368 write(fd, ", nonstop mode\n", 15);
369 break;
370
371 case FEX_ABORT:
372 write(fd, ", abort\n", 8);
373 break;
374
375 case FEX_NOHANDLER:
376 if (p == (void *)SIG_DFL) {
377 write(fd, ", handler: SIG_DFL\n", 19);
378 break;
379 }
380 else if (p == (void *)SIG_IGN) {
381 write(fd, ", handler: SIG_IGN\n", 19);
382 break;
383 }
384 /* fall through*/
385 default:
386 write(fd, ", handler: ", 11);
387 if (__fex_sym((char *)p, &name) != NULL) {
388 write(fd, name, strlen(name));
389 write(fd, "\n", 1);
390 } else {
391 write(fd, buf, sprintf(buf, "0x%0" PDIG "lx\n",
392 (long)p));
393 }
394 break;
395 }
396 print_stack(fd, stk, fp);
397 mutex_unlock(&log_lock);
398 }
|
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 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #pragma weak __fex_get_log = fex_get_log
32 #pragma weak __fex_set_log = fex_set_log
33 #pragma weak __fex_get_log_depth = fex_get_log_depth
34 #pragma weak __fex_set_log_depth = fex_set_log_depth
35 #pragma weak __fex_log_entry = fex_log_entry
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <signal.h>
42 #include <ucontext.h>
43 #include <sys/frame.h>
44 #include <fenv.h>
45 #include <sys/ieeefp.h>
46 #include <thread.h>
47 #include "fex_handler.h"
48
49 #if !defined(PC)
50 #if defined(REG_PC)
51 #define PC REG_PC
52 #else
53 #error Neither PC nor REG_PC is defined!
54 #endif
55 #endif
56
57 static FILE *log_fp = NULL;
58 static mutex_t log_lock = DEFAULTMUTEX;
59 static int log_depth = 100;
60 FILE *
61 fex_get_log(void)
62 {
63 FILE *fp;
64
65 mutex_lock(&log_lock);
66 fp = log_fp;
67 mutex_unlock(&log_lock);
68 return (fp);
69 }
70
71 int
72 fex_set_log(FILE *fp)
73 {
74 mutex_lock(&log_lock);
75 log_fp = fp;
76 mutex_unlock(&log_lock);
77 __fex_update_te();
78 return (1);
79 }
80
81 int
82 fex_get_log_depth(void)
83 {
84 int d;
85
86 mutex_lock(&log_lock);
87 d = log_depth;
88 mutex_unlock(&log_lock);
89 return (d);
90 }
91
92 int
93 fex_set_log_depth(int d)
94 {
95 if (d < 0)
96 return (0);
97
98 mutex_lock(&log_lock);
99 log_depth = d;
100 mutex_unlock(&log_lock);
101 return (1);
102 }
103
104 static struct exc_list {
105 struct exc_list *next;
106 char *addr;
107 unsigned long code;
108 int nstack;
109 char *stack[1]; /* actual length is max(1,nstack) */
110 } *list = NULL;
111
112 #ifdef __sparcv9
113 #define FRAMEP(X) (struct frame *)((char *)(X) + (((long)(X) & \
114 1) ? 2047 : 0))
115 #else
116 #define FRAMEP(X) (struct frame *)(X)
117 #endif
118
119 #ifdef _LP64
120 #define PDIG "16"
121 #else
122 #define PDIG "8"
123 #endif
124
125 /*
126 * look for a matching exc_list; return 1 if one is found,
127 * otherwise add this one to the list and return 0
128 */
129 static int
130 check_exc_list(char *addr, unsigned long code, char *stk, struct frame *fp)
131 {
132 struct exc_list *l, *ll = NULL;
133 struct frame *f;
134 int i, n;
135
136 if (list) {
137 for (l = list; l; ll = l, l = l->next) {
138 if (l->addr != addr || l->code != code)
139 continue;
140
141 if (log_depth < 1 || l->nstack < 1)
142 return (1);
143
144 if (l->stack[0] != stk)
145 continue;
146
147 n = 1;
148
149 for (i = 1, f = fp; i < log_depth && i < l->nstack &&
150 f && f->fr_savpc; i++, f = FRAMEP(f->fr_savfp))
151 if (l->stack[i] != (char *)f->fr_savpc) {
152 n = 0;
153 break;
154 }
155
156 if (n)
157 return (1);
158 }
159 }
160
161 /* create a new exc_list structure and tack it on the list */
162 for (n = 1, f = fp; n < log_depth && f && f->fr_savpc;
163 n++, f = FRAMEP(f->fr_savfp))
164 ;
165
166 if ((l = (struct exc_list *)malloc(sizeof (struct exc_list) + (n - 1) *
167 sizeof (char *))) != NULL) {
168 l->next = NULL;
169 l->addr = addr;
170 l->code = code;
171 l->nstack = ((log_depth < 1) ? 0 : n);
172 l->stack[0] = stk;
173
174 for (i = 1; i < n; i++) {
175 l->stack[i] = (char *)fp->fr_savpc;
176 fp = FRAMEP(fp->fr_savfp);
177 }
178
179 if (list)
180 ll->next = l;
181 else
182 list = l;
183 }
184
185 return (0);
186 }
187
188 /*
189 * Warning: cleverness ahead
190 *
191 * In the following code, the use of sprintf+write rather than fprintf
192 * to send output to the log file is intentional. The reason is that
193 * fprintf is not async-signal-safe. "But," you protest, "SIGFPE is
194 * not an asynchronous signal! It's always handled by the same thread
195 * that executed the fpop that provoked it." That's true, but a prob-
196 * lem arises because (i) base conversion in fprintf can cause a fp
197 * exception and (ii) my signal handler acquires a mutex lock before
198 * sending output to the log file (so that outputs for entries from
199 * different threads aren't interspersed). Therefore, if the code
200 * were to use fprintf, a deadlock could occur as follows:
201 *
202 * Thread A Thread B
203 *
204 * Incurs a fp exception, Calls fprintf,
205 * acquires log_lock acquires file rmutex lock
206 *
207 * Calls fprintf, Incurs a fp exception,
208 * waits for file rmutex lock waits for log_lock
209 *
210 * (I could just verify that fprintf doesn't hold the rmutex lock while
211 * it's doing the base conversion, but since efficiency is of little
212 * concern here, I opted for the safe and dumb route.)
213 */
214 static void
215 print_stack(int fd, char *addr, struct frame *fp)
216 {
217 int i;
218 char *name, buf[30];
219
220 for (i = 0; i < log_depth && addr != NULL; i++) {
221 if (__fex_sym(addr, &name) != NULL) {
222 write(fd, buf, sprintf(buf, " 0x%0" PDIG "lx ",
223 (long)addr));
224 write(fd, name, strlen(name));
225 write(fd, "\n", 1);
226
227 if (strcmp(name, "main") == 0)
228 break;
229 } else {
230 write(fd, buf, sprintf(buf, " 0x%0" PDIG "lx\n",
231 (long)addr));
232 }
233
234 if (fp == NULL)
235 break;
236
237 addr = (char *)fp->fr_savpc;
238 fp = FRAMEP(fp->fr_savfp);
239 }
240 }
241
242 void
243 fex_log_entry(const char *msg)
244 {
245 ucontext_t uc;
246 struct frame *fp;
247 char *stk;
248 int fd;
249
250 /* if logging is disabled, just return */
251 mutex_lock(&log_lock);
252
253 if (log_fp == NULL) {
254 mutex_unlock(&log_lock);
255 return;
256 }
257
258 /*
259 * get the frame pointer from the current context and
260 * pop our own frame
261 */
262 getcontext(&uc);
263 #if defined(__sparc) || defined(__amd64)
264 fp = FRAMEP(uc.uc_mcontext.gregs[REG_SP]);
265 #elif defined(__i386) /* !defined(__amd64) */
266 fp = FRAMEP(uc.uc_mcontext.gregs[EBP]);
267 #else
268 #error Unknown architecture
269 #endif
270
271 if (fp == NULL) {
272 mutex_unlock(&log_lock);
273 return;
274 }
275
276 stk = (char *)fp->fr_savpc;
277 fp = FRAMEP(fp->fr_savfp);
278
279 /* if we've already logged this message here, don't make an entry */
280 if (check_exc_list(stk, (unsigned long)msg, stk, fp)) {
281 mutex_unlock(&log_lock);
282 return;
283 }
284
285 /* make an entry */
286 fd = fileno(log_fp);
287 write(fd, "fex_log_entry: ", 15);
288 write(fd, msg, strlen(msg));
289 write(fd, "\n", 1);
290 __fex_sym_init();
291 print_stack(fd, stk, fp);
292 mutex_unlock(&log_lock);
293 }
294
295 static const char *exception[FEX_NUM_EXC] = {
296 "inexact result", "division by zero", "underflow", "overflow",
297 "invalid operation (0/0)", "invalid operation (inf/inf)",
298 "invalid operation (inf-inf)", "invalid operation (0*inf)",
299 "invalid operation (sqrt)", "invalid operation (snan)",
300 "invalid operation (int)", "invalid operation (cmp)"
301 };
302
303 void
304 __fex_mklog(ucontext_t *uap, char *addr, int f, enum fex_exception e, int m,
305 void *p)
306 {
307 struct frame *fp;
308 char *stk, *name, buf[30];
309 int fd;
310
311 /* if logging is disabled, just return */
312 mutex_lock(&log_lock);
313
314 if (log_fp == NULL) {
315 mutex_unlock(&log_lock);
316 return;
317 }
318
319 /* get stack info */
320 #if defined(__sparc)
321 stk = (char *)uap->uc_mcontext.gregs[REG_PC];
322 fp = FRAMEP(uap->uc_mcontext.gregs[REG_SP]);
323 #elif defined(__amd64)
324 stk = (char *)uap->uc_mcontext.gregs[REG_PC];
325 fp = FRAMEP(uap->uc_mcontext.gregs[REG_RBP]);
326 #elif defined(__i386) /* !defined(__amd64) */
327 stk = (char *)uap->uc_mcontext.gregs[PC];
328 fp = FRAMEP(uap->uc_mcontext.gregs[EBP]);
329 #else
330 #error Unknown architecture
331 #endif
332
333 /*
334 * if the handling mode is the default and this exception's
335 * flag is already raised, don't make an entry
336 */
337 if (m == FEX_NONSTOP) {
338 switch (e) {
339 case fex_inexact:
340
341 if (f & FE_INEXACT) {
342 mutex_unlock(&log_lock);
343 return;
344 }
345
346 break;
347 case fex_underflow:
348
349 if (f & FE_UNDERFLOW) {
350 mutex_unlock(&log_lock);
351 return;
352 }
353
354 break;
355 case fex_overflow:
356
357 if (f & FE_OVERFLOW) {
358 mutex_unlock(&log_lock);
359 return;
360 }
361
362 break;
363 case fex_division:
364
365 if (f & FE_DIVBYZERO) {
366 mutex_unlock(&log_lock);
367 return;
368 }
369
370 break;
371 default:
372
373 if (f & FE_INVALID) {
374 mutex_unlock(&log_lock);
375 return;
376 }
377
378 break;
379 }
380 }
381
382 /*
383 * if we've already logged this exception at this address,
384 * don't make an entry
385 */
386 if (check_exc_list(addr, (unsigned long)e, stk, fp)) {
387 mutex_unlock(&log_lock);
388 return;
389 }
390
391 /* make an entry */
392 fd = fileno(log_fp);
393 write(fd, "Floating point ", 15);
394 write(fd, exception[e], strlen(exception[e]));
395 write(fd, buf, sprintf(buf, " at 0x%0" PDIG "lx", (long)addr));
396 __fex_sym_init();
397
398 if (__fex_sym(addr, &name) != NULL) {
399 write(fd, " ", 1);
400 write(fd, name, strlen(name));
401 }
402
403 switch (m) {
404 case FEX_NONSTOP:
405 write(fd, ", nonstop mode\n", 15);
406 break;
407
408 case FEX_ABORT:
409 write(fd, ", abort\n", 8);
410 break;
411
412 case FEX_NOHANDLER:
413
414 if (p == (void *)SIG_DFL) {
415 write(fd, ", handler: SIG_DFL\n", 19);
416 break;
417 } else if (p == (void *)SIG_IGN) {
418 write(fd, ", handler: SIG_IGN\n", 19);
419 break;
420 }
421
422 /* FALLTHROUGH */
423 default:
424 write(fd, ", handler: ", 11);
425
426 if (__fex_sym((char *)p, &name) != NULL) {
427 write(fd, name, strlen(name));
428 write(fd, "\n", 1);
429 } else {
430 write(fd, buf, sprintf(buf, "0x%0" PDIG "lx\n",
431 (long)p));
432 }
433
434 break;
435 }
436
437 print_stack(fd, stk, fp);
438 mutex_unlock(&log_lock);
439 }
|