source: psi/trunk/src/tools/crash/crash_sigsegv.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 5.5 KB
Line 
1/* sigsegv.c -- sigsegv handlers
2 *
3 * Copyright (c) 2003 Juan F. Codagnone <juam@users.sourceforge.net>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H_
25 #include <config.h>
26#endif
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <assert.h>
32#include <errno.h>
33
34#include <unistd.h>
35
36#ifdef HAVE_PTHREADS_H
37# include <pthread.h>
38#endif
39
40/*
41 * http://www.gnu.org/manual/glibc-2.2.3/html_chapter/libc_33.html
42 */
43#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
44# define HAVE_BACKTRACE
45# include <execinfo.h>
46#endif
47#include <sys/wait.h>
48
49#include "crash_sigsegv.h"
50
51namespace Crash {
52
53static int (* print)(const char *format, ...) = NULL;
54static int needs_cr = 1;
55
56void *sigsegv_set_print( int (* fnc)(const char *format, ...), int _needs_cr)
57{
58 void *ret;
59
60 ret = &print;
61 print = fnc;
62 needs_cr = _needs_cr;
63
64 return ret;
65}
66
67/**
68 * launchs gdb, and feeds myprint with the backtrace
69 */
70static int dump_pid_son(pid_t pid, const char *binary, int full_bt,
71 int (* myprint)(const char *format, ...))
72{
73 char tmp[]="/tmp/mrbug-crash-XXXXXX";
74 int ret = 0;
75 int fd;
76
77 fd = mkstemp(tmp);
78 if( fd == -1 )
79 {
80 (*myprint)("opening gdb command (tempory) file `%s'%s", tmp,
81 needs_cr ? "\n" : "");
82 ret = -1;
83 }
84 else
85 {
86 char gdb_cmd[]="bt\nquit";
87 char gdb_cmd_full[]="bt full\nquit";
88 char cmd[128];
89 FILE *fp;
90
91 if( full_bt )
92 write(fd, gdb_cmd_full, strlen(gdb_cmd_full));
93 else
94 write(fd, gdb_cmd, strlen(gdb_cmd));
95 close(fd);
96
97 sprintf(cmd, "gdb -nw -n -batch -x \"%s\" %s %d", tmp, binary,
98 pid);
99 (*myprint)("trying to dump pid: %d (%s)...%s", pid, binary,
100 needs_cr ? "\n" : "");
101
102 fflush(NULL);
103 fp = popen(cmd, "r");
104 if( fp == NULL )
105 {
106 (*myprint)("err. couldn't exec `%s'%s", cmd,
107 needs_cr ? "\n" : "");
108 ret = -1;
109 }
110 else
111 {
112 char buff[4096];
113 size_t len;
114
115 while(fgets(buff, sizeof(buff), fp))
116 {
117 len = strlen(buff);
118 if( buff[len-1] == '\n')
119 buff[len-1]=0;
120
121 (*myprint)("%s%s", buff,needs_cr ? "\n" : "");
122 }
123 fclose(fp);
124 }
125 if( remove(tmp) == -1 )
126 (*myprint)("removing `%s` (@;@)%s", tmp,
127 needs_cr ? "\n" : "");
128 }
129
130 return ret;
131}
132
133static int dump_pid(pid_t pid, const char *binary, int full_bt )
134{
135 pid_t mpid;
136 int (* myprint)(const char *format, ...);
137
138 myprint = print ? (int(*)(const char *format, ...))print : (int(*)(const char *format, ...))printf;
139
140 /*
141 * clone the process, so we don't make the bt bigger.
142 */
143 mpid = fork();
144 if( mpid == 0 )
145 {
146 dump_pid_son(pid, binary, full_bt, myprint);
147 exit(0);
148 }
149 else if( mpid == -1 )
150 (*myprint)("lunching son: `%s' %s", strerror(errno),
151 needs_cr ? "\n" : "");
152 else
153 {
154 /* father */
155 int status;
156
157 alarm(0);
158 waitpid(0, &status, 0);
159 if( WIFEXITED(status) && WEXITSTATUS(status)==0 )
160 ;
161 }
162
163 return 0;
164}
165
166/**
167 * get `pid`'s real path
168 *
169 * \param buff buffer for the output
170 * \param nbuff size of the buffer
171 * \param pid pid processes id to use
172 *
173 * \note this function works only in linux
174 *
175 * \return the buffer
176 */
177static char *get_path_from_pid(char *buff, size_t nbuff, pid_t pid)
178{
179 char proc[256];
180 char *ret = NULL;
181 int n;
182
183 sprintf(proc, "/proc/%d/exe", pid);
184 if( (n=readlink(proc, buff, nbuff)) == -1 )
185 ret = NULL;
186 else
187 {
188 buff[n]=0;
189 ret = buff;
190 }
191
192 return ret;
193}
194
195static void sigsegv_libc_dump( int (* myprint)(const char *format, ...) )
196{
197 void *array[48] = {0};
198 unsigned short i;
199 int n;
200 char **res;
201
202#ifdef HAVE_BACKTRACE
203 (*myprint)("Backtrace:%c", needs_cr ? "\n" : "");
204 n = backtrace(array, sizeof(array)/(sizeof(*array)));
205 res = backtrace_symbols(array, n);
206 for (i = 0; i < n; i++)
207 (*myprint)("%s%s", res[i], needs_cr ? "\n" : "");
208
209 (*myprint)("Attempting to generate core file%s",
210 needs_cr ? "" : "");
211#endif
212}
213
214static void sigsegv_handler_generic(int signal, int full_bt)
215{
216 char binary[2048];
217 int pid = getpid();
218 int (* myprint)(const char *format, ...);
219
220 myprint = print ? print : printf;
221 if( get_path_from_pid(binary, sizeof(binary), pid) == NULL)
222 (*myprint)("pid %d does not seems to exist", pid);
223 else
224 {
225 (*myprint)("Segmentation Violation Detected.%s",
226 needs_cr ? "\n" : "");
227 dump_pid(pid, binary, full_bt);
228 sigsegv_libc_dump(myprint);
229 }
230
231#ifdef HAVE_PTHREAD_H
232 pthread_kill_other_threads_np();
233#endif
234 fflush(NULL);
235 abort();
236}
237
238void sigsegv_handler_fnc(int signal)
239{
240 sigsegv_handler_generic(signal, 0);
241}
242
243void sigsegv_handler_bt_full_fnc(int signal)
244{
245 sigsegv_handler_generic(signal, 1);
246}
247
248}; // namespace Crash
Note: See TracBrowser for help on using the repository browser.