~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to src/tools/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