~ubuntu-branches/ubuntu/karmic/psi/karmic

« back to all changes in this revision

Viewing changes to cutestuff/crash/crash_sigsegv.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2006-01-20 00:20:36 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060120002036-7nw6yo6totip0ee5
Tags: 0.10-2
* Added upstream changelog (Closes: Bug#327748)
* Mention --no-gpg and --no-gpg-agent in manpage (Closes: Bug#204416)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
51
 
namespace Crash {
52
 
 
53
 
static int (* print)(const char *format, ...) = NULL;
54
 
static int needs_cr = 1;
55
 
 
56
 
void *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
 
 */
70
 
static 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
 
 
133
 
static 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
 
 */
177
 
static 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
 
 
195
 
static 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
 
 
214
 
static 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
 
 
238
 
void sigsegv_handler_fnc(int signal)
239
 
{
240
 
        sigsegv_handler_generic(signal, 0);
241
 
}
242
 
 
243
 
void sigsegv_handler_bt_full_fnc(int signal)
244
 
{
245
 
        sigsegv_handler_generic(signal, 1);
246
 
}
247
 
 
248
 
}; // namespace Crash