update cin.po, goog xlat update xx.po
[goodguy/history.git] / cinelerra-5.1 / guicast / bcsignals.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "bcwindowbase.h"
24 #include "bccmodels.h"
25 #include "bckeyboard.h"
26 #include "bcresources.h"
27
28 #include <ctype.h>
29 #include <dirent.h>
30 #include <execinfo.h>
31 #include <fcntl.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <sys/ioctl.h>
39 #include <sys/prctl.h>
40 #include <sys/types.h>
41
42 BC_Signals* BC_Signals::global_signals = 0;
43 static int signal_done = 0;
44 static int table_id = 0;
45
46 static bc_locktrace_t* new_bc_locktrace(void *ptr,
47         const char *title,
48         const char *location)
49 {
50         bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
51         result->ptr = ptr;
52         result->title = title;
53         result->location = location;
54         result->is_owner = 0;
55         result->id = table_id++;
56         result->tid = pthread_self();
57         return result;
58 }
59
60
61 static struct sigaction old_segv = {0, }, old_intr = {0, };
62 static void handle_dump(int n, siginfo_t * info, void *sc);
63
64 const char *BC_Signals::trap_path = 0;
65 void *BC_Signals::trap_data = 0;
66 void (*BC_Signals::trap_hook)(FILE *fp, void *data) = 0;
67 bool BC_Signals::trap_sigsegv = false;
68 bool BC_Signals::trap_sigintr = false;
69
70 static void uncatch_sig(int sig, struct sigaction &old)
71 {
72         struct sigaction act;
73         sigaction(sig, &old, &act);
74         old.sa_handler = 0;
75 }
76
77 static void catch_sig(int sig, struct sigaction &old)
78 {
79         struct sigaction act;
80         memset(&act, 0, sizeof(act));
81         act.sa_sigaction = handle_dump;
82         act.sa_flags = SA_SIGINFO;
83         sigaction(sig, &act, (!old.sa_handler ? &old : 0));
84 }
85
86 static void uncatch_intr() { uncatch_sig(SIGINT, old_intr); }
87 static void catch_intr() { catch_sig(SIGINT, old_intr); }
88 static void uncatch_segv() { uncatch_sig(SIGSEGV, old_segv); }
89 static void catch_segv() { catch_sig(SIGSEGV, old_segv); }
90
91 void BC_Signals::set_trap_path(const char *path)
92 {
93         trap_path = path;
94 }
95
96 void BC_Signals::set_trap_hook(void (*hook)(FILE *fp, void *vp), void *data)
97 {
98         trap_data = data;
99         trap_hook = hook;
100 }
101
102 void BC_Signals::set_catch_segv(bool v) {
103         if( v == trap_sigsegv ) return;
104         if( v ) catch_segv();
105         else uncatch_segv();
106         v = trap_sigsegv;
107 }
108
109 void BC_Signals::set_catch_intr(bool v) {
110         if( v == trap_sigintr ) return;
111         if( v ) catch_intr();
112         else uncatch_intr();
113         v = trap_sigintr;
114 }
115
116 typedef struct
117 {
118         int size;
119         void *ptr;
120         const char *location;
121 } bc_buffertrace_t;
122
123 static bc_buffertrace_t* new_bc_buffertrace(int size, void *ptr, const char *location)
124 {
125         bc_buffertrace_t *result = (bc_buffertrace_t*)malloc(sizeof(bc_buffertrace_t));
126         result->size = size;
127         result->ptr = ptr;
128         result->location = location;
129         return result;
130 }
131
132 static void bc_copy_textfile(int lines, FILE *ofp, const char *fmt,...)
133 {
134         va_list ap;    va_start(ap, fmt);
135         char bfr[BCTEXTLEN];  vsnprintf(bfr, sizeof(bfr), fmt, ap);
136         va_end(ap);
137         FILE *ifp = fopen(bfr,"r");
138         if( !ifp ) return;
139         while( --lines >= 0 && fgets(bfr,sizeof(bfr),ifp) ) fputs(bfr,ofp);
140         fclose(ifp);
141 }
142
143
144 // Need our own table to avoid recursion with the memory manager
145 typedef struct
146 {
147         void **values;
148         int size;
149         int allocation;
150 // This points to the next value to replace if the table wraps around
151         int current_value;
152 } bc_table_t;
153
154 static void* append_table(bc_table_t *table, void *ptr)
155 {
156         if(table->allocation <= table->size)
157         {
158                 if(table->allocation)
159                 {
160                         int new_allocation = table->allocation * 2;
161                         void **new_values = (void**)calloc(new_allocation, sizeof(void*));
162                         memcpy(new_values, table->values, sizeof(void*) * table->size);
163                         free(table->values);
164                         table->values = new_values;
165                         table->allocation = new_allocation;
166                 }
167                 else
168                 {
169                         table->allocation = 4096;
170                         table->values = (void**)calloc(table->allocation, sizeof(void*));
171                 }
172         }
173
174         table->values[table->size++] = ptr;
175         return ptr;
176 }
177
178 // Replace item in table pointed to by current_value and advance
179 // current_value
180 static void* overwrite_table(bc_table_t *table, void *ptr)
181 {
182         free(table->values[table->current_value]);
183         table->values[table->current_value++] = ptr;
184         if(table->current_value >= table->size) table->current_value = 0;
185         return 0;
186 }
187
188 static void clear_table(bc_table_t *table, int delete_objects)
189 {
190         if(delete_objects)
191         {
192                 for(int i = 0; i < table->size; i++)
193                 {
194                         free(table->values[i]);
195                 }
196         }
197         table->size = 0;
198 }
199
200 static void clear_table_entry(bc_table_t *table, int number, int delete_object)
201 {
202         if(delete_object) free(table->values[number]);
203         for(int i = number; i < table->size - 1; i++)
204         {
205                 table->values[i] = table->values[i + 1];
206         }
207         table->size--;
208 }
209
210 // Table of functions currently running.
211 static bc_table_t execution_table = { 0, 0, 0, 0 };
212
213 // Table of locked positions
214 static bc_table_t lock_table = { 0, 0, 0, 0 };
215
216 // Table of buffers
217 static bc_table_t memory_table = { 0, 0, 0, 0 };
218
219 static bc_table_t temp_files = { 0, 0, 0, 0 };
220
221 // Can't use Mutex because it would be recursive
222 static pthread_mutex_t *lock = 0;
223 static pthread_mutex_t *handler_lock = 0;
224 // incase lock set after task ends
225 static pthread_t last_lock_thread = 0;
226 static const char *last_lock_title = 0;
227 static const char *last_lock_location = 0;
228 // Don't trace memory until this is true to avoid initialization
229 static int trace_memory = 0;
230
231
232 static const char* signal_titles[] =
233 {
234         "NULL",
235         "SIGHUP",
236         "SIGINT",
237         "SIGQUIT",
238         "SIGILL",
239         "SIGTRAP",
240         "SIGABRT",
241         "SIGBUS",
242         "SIGFPE",
243         "SIGKILL",
244         "SIGUSR1",
245         "SIGSEGV",
246         "SIGUSR2",
247         "SIGPIPE",
248         "SIGALRM",
249         "SIGTERM"
250 };
251
252 void BC_Signals::dump_stack(FILE *fp)
253 {
254         void *buffer[256];
255         int total = backtrace (buffer, 256);
256         char **result = backtrace_symbols (buffer, total);
257         fprintf(fp, "BC_Signals::dump_stack\n");
258         for(int i = 0; i < total; i++)
259         {
260                 fprintf(fp, "%s\n", result[i]);
261         }
262 }
263
264 // Kill subprocesses
265 void BC_Signals::kill_subs()
266 {
267 // List /proc directory
268         DIR *dirstream;
269         struct dirent64 *new_filename;
270         struct stat ostat;
271         char path[BCTEXTLEN];
272         char string[BCTEXTLEN];
273
274         dirstream = opendir("/proc");
275         if(!dirstream) return;
276
277         while( (new_filename = readdir64(dirstream)) != 0 )
278         {
279 // All digits are numbers
280                 char *ptr = new_filename->d_name;
281                 int got_alpha = 0;
282                 while(*ptr)
283                 {
284                         if(*ptr == '.' || isalpha(*ptr++))
285                         {
286                                 got_alpha = 1;
287                                 break;
288                         }
289                 }
290
291                 if(got_alpha) continue;
292
293 // Must be a directory
294                 sprintf(path, "/proc/%s", new_filename->d_name);
295                 if(!stat(path, &ostat))
296                 {
297                         if(S_ISDIR(ostat.st_mode))
298                         {
299 // Read process stat
300                                 strcat(path, "/stat");
301 //printf("kill_subs %d %s\n", __LINE__, path);
302                                 FILE *fd = fopen(path, "r");
303
304 // Must search forwards because the file is 0 length
305                                 if(fd)
306                                 {
307                                         while(!feof(fd))
308                                         {
309                                                 char c = fgetc(fd);
310 //printf("kill_subs %d %d\n", __LINE__, c);
311                                                 if(c == ')')
312                                                 {
313 // Search for 2 spaces
314                                                         int spaces = 0;
315                                                         while(!feof(fd) && spaces < 2)
316                                                         {
317                                                                 c = fgetc(fd);
318                                                                 if(c == ' ')
319                                                                         spaces++;
320                                                         }
321
322 // Read in parent process
323                                                         ptr = string;
324                                                         while(!feof(fd))
325                                                         {
326                                                                 *ptr = fgetc(fd);
327                                                                 if(*ptr == ' ')
328                                                                 {
329                                                                         *ptr = 0;
330                                                                         break;
331                                                                 }
332                                                                 ptr++;
333                                                         }
334
335 // printf("kill_subs %d process=%d getpid=%d parent_process=%d\n",
336 // __LINE__,
337 // atoi(new_filename->d_name),
338 // getpid(),
339 // atoi(string));
340                                                         int parent_process = atoi(string);
341                                                         int child_process = atoi(new_filename->d_name);
342
343 // Kill if we're the parent
344                                                         if(getpid() == parent_process)
345                                                         {
346 //printf("kill_subs %d: process=%d\n", __LINE__, atoi(new_filename->d_name));
347                                                                 kill(child_process, SIGKILL);
348                                                         }
349                                                 }
350                                         }
351
352                                         fclose(fd);
353                                 }
354                         }
355                 }
356         }
357 }
358
359 static void signal_entry(int signum)
360 {
361         signal(signum, SIG_DFL);
362
363         pthread_mutex_lock(handler_lock);
364         if(signal_done)
365         {
366                 pthread_mutex_unlock(handler_lock);
367                 exit(0);
368         }
369
370         signal_done = 1;
371         pthread_mutex_unlock(handler_lock);
372
373
374         printf("signal_entry: got %s my pid=%d execution table size=%d:\n",
375                 signal_titles[signum],
376                 getpid(),
377                 execution_table.size);
378
379         BC_Signals::kill_subs();
380         BC_Signals::dump_traces();
381         BC_Signals::dump_locks();
382         BC_Signals::dump_buffers();
383         BC_Signals::delete_temps();
384
385 // Call user defined signal handler
386         BC_Signals::global_signals->signal_handler(signum);
387
388         abort();
389 }
390
391 static void signal_entry_recoverable(int signum)
392 {
393         printf("signal_entry_recoverable: got %s my pid=%d\n",
394                 signal_titles[signum],
395                 getpid());
396 }
397
398 // used to terminate child processes when program terminates
399 static void handle_exit(int signum)
400 {
401 //printf("child %d exit\n", getpid());
402         exit(0);
403 }
404
405 void BC_Signals::set_sighup_exit(int enable)
406 {
407         if( enable ) {
408 // causes SIGHUP to be generated when parent dies
409                 signal(SIGHUP, handle_exit);
410                 prctl(PR_SET_PDEATHSIG, SIGHUP, 0,0,0);
411 // prevents ^C from signalling child when attached to gdb
412                 setpgid(0, 0);
413                 if( isatty(0) ) ioctl(0, TIOCNOTTY, 0);
414         }
415         else {
416                 signal(SIGHUP, signal_entry);
417                 prctl(PR_SET_PDEATHSIG, 0,0,0,0);
418         }
419 }
420
421 BC_Signals::BC_Signals()
422 {
423 }
424 BC_Signals::~BC_Signals()
425 {
426   BC_CModels::bcxfer_stop_slicers();
427 }
428
429 void BC_Signals::dump_traces(FILE *fp)
430 {
431 // Dump trace table
432         if(execution_table.size)
433         {
434                 for(int i = execution_table.current_value; i < execution_table.size; i++)
435                         fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
436                 for(int i = 0; i < execution_table.current_value; i++)
437                         fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
438         }
439
440 }
441
442 void BC_Signals::dump_locks(FILE *fp)
443 {
444 // Dump lock table
445 #ifdef TRACE_LOCKS
446         fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
447         for(int i = 0; i < lock_table.size; i++)
448         {
449                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
450                 fprintf(fp,"    %p %s %s %p%s\n", table->ptr,
451                         table->title, table->location, (void*)table->tid,
452                         table->is_owner ? " *" : "");
453         }
454 #endif
455 }
456
457 void BC_Signals::dump_buffers(FILE *fp)
458 {
459 #ifdef TRACE_MEMORY
460         pthread_mutex_lock(lock);
461 // Dump buffer table
462         fprintf(fp,"BC_Signals::dump_buffers: buffer table size=%d\n", memory_table.size);
463         for(int i = 0; i < memory_table.size; i++)
464         {
465                 bc_buffertrace_t *entry = (bc_buffertrace_t*)memory_table.values[i];
466                 fprintf(fp,"    %d %p %s\n", entry->size, entry->ptr, entry->location);
467         }
468         pthread_mutex_unlock(lock);
469 #endif
470 }
471
472 void BC_Signals::delete_temps()
473 {
474         pthread_mutex_lock(lock);
475         if(temp_files.size) printf("BC_Signals::delete_temps: deleting %d temp files\n", temp_files.size);
476         for(int i = 0; i < temp_files.size; i++)
477         {
478                 printf("    %s\n", (char*)temp_files.values[i]);
479                 remove((char*)temp_files.values[i]);
480         }
481         pthread_mutex_unlock(lock);
482 }
483
484 void BC_Signals::reset_locks()
485 {
486         pthread_mutex_unlock(lock);
487 }
488
489 void BC_Signals::set_temp(char *string)
490 {
491         char *new_string = strdup(string);
492         append_table(&temp_files, new_string);
493 }
494
495 void BC_Signals::unset_temp(char *string)
496 {
497         for(int i = 0; i < temp_files.size; i++)
498         {
499                 if(!strcmp((char*)temp_files.values[i], string))
500                 {
501                         clear_table_entry(&temp_files, i, 1);
502                         break;
503                 }
504         }
505 }
506
507
508 int BC_Signals::x_error_handler(Display *display, XErrorEvent *event)
509 {
510         char string[1024];
511         XGetErrorText(event->display, event->error_code, string, 1024);
512         fprintf(stderr, "BC_Signals::x_error_handler: error_code=%d opcode=%d,%d id=0x%jx %s\n",
513                 event->error_code, event->request_code, event->minor_code,
514                 (int64_t)event->resourceid, string);
515         return 0;
516 }
517
518
519 void BC_Signals::initialize()
520 {
521         BC_Signals::global_signals = this;
522         lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
523         handler_lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
524         pthread_mutex_init(lock, 0);
525         pthread_mutex_init(handler_lock, 0);
526         old_err_handler = XSetErrorHandler(x_error_handler);
527         initialize2();
528 }
529
530 void BC_Signals::terminate()
531 {
532         BC_Signals::global_signals = 0;
533         uncatch_segv();  uncatch_intr();
534         signal(SIGHUP, SIG_DFL);
535         signal(SIGINT, SIG_DFL);
536         signal(SIGQUIT, SIG_DFL);
537         signal(SIGTERM, SIG_DFL);
538         signal(SIGFPE, SIG_DFL);
539         signal(SIGPIPE, SIG_DFL);
540         signal(SIGUSR2, SIG_DFL);
541         XSetErrorHandler(old_err_handler);
542 }
543
544 // callable from debugger
545 extern "C"
546 void dump()
547 {
548         BC_Signals::dump_traces();
549         BC_Signals::dump_locks();
550         BC_Signals::dump_buffers();
551 }
552
553 // kill SIGUSR2
554 void BC_Signals::signal_dump(int signum)
555 {
556         BC_KeyboardHandler::kill_grabs();
557         dump();
558         signal(SIGUSR2, signal_dump);
559 }
560
561
562
563
564
565
566 void BC_Signals::initialize2()
567 {
568         signal(SIGHUP, signal_entry);
569         signal(SIGINT, signal_entry);
570         signal(SIGQUIT, signal_entry);
571         // SIGKILL cannot be stopped
572         // signal(SIGKILL, signal_entry);
573         catch_segv();
574         signal(SIGTERM, signal_entry);
575         signal(SIGFPE, signal_entry);
576         signal(SIGPIPE, signal_entry_recoverable);
577         signal(SIGUSR2, signal_dump);
578 }
579
580
581 void BC_Signals::signal_handler(int signum)
582 {
583 printf("BC_Signals::signal_handler\n");
584 //      exit(0);
585 }
586
587 const char* BC_Signals::sig_to_str(int number)
588 {
589         return signal_titles[number];
590 }
591
592 #define TOTAL_TRACES 16
593
594 void BC_Signals::new_trace(const char *text)
595 {
596         if(!global_signals) return;
597         pthread_mutex_lock(lock);
598
599 // Wrap around
600         if(execution_table.size >= TOTAL_TRACES)
601         {
602                 overwrite_table(&execution_table, strdup(text));
603 //              clear_table(&execution_table, 1);
604         }
605         else
606         {
607                 append_table(&execution_table, strdup(text));
608         }
609         pthread_mutex_unlock(lock);
610 }
611
612 void BC_Signals::new_trace(const char *file, const char *function, int line)
613 {
614         char string[BCTEXTLEN];
615         snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
616         new_trace(string);
617 }
618
619 void BC_Signals::delete_traces()
620 {
621         if(!global_signals) return;
622         pthread_mutex_lock(lock);
623         clear_table(&execution_table, 0);
624         pthread_mutex_unlock(lock);
625 }
626
627 // no canceling with lock held
628 void BC_Signals::lock_locks(const char *s)
629 {
630         pthread_mutex_lock(lock);
631         last_lock_thread = pthread_self();
632         last_lock_title = s;
633         last_lock_location = 0;
634 }
635
636 void BC_Signals::unlock_locks()
637 {
638         pthread_mutex_unlock(lock);
639 }
640
641 #define TOTAL_LOCKS 256
642
643 int BC_Signals::set_lock(void *ptr,
644         const char *title,
645         const char *location)
646 {
647         if(!global_signals) return 0;
648         bc_locktrace_t *table = 0;
649         int id_return = 0;
650
651         pthread_mutex_lock(lock);
652         last_lock_thread = pthread_self();
653         last_lock_title = title;
654         last_lock_location = location;
655         if(lock_table.size >= TOTAL_LOCKS)
656                 clear_table(&lock_table, 0);
657
658 // Put new lock entry
659         table = new_bc_locktrace(ptr, title, location);
660         append_table(&lock_table, table);
661         id_return = table->id;
662
663         pthread_mutex_unlock(lock);
664         return id_return;
665 }
666
667 void BC_Signals::set_lock2(int table_id)
668 {
669         if(!global_signals) return;
670
671         bc_locktrace_t *table = 0;
672         pthread_mutex_lock(lock);
673         for(int i = lock_table.size - 1; i >= 0; i--)
674         {
675                 table = (bc_locktrace_t*)lock_table.values[i];
676 // Got it.  Hasn't been unlocked/deleted yet.
677                 if(table->id == table_id)
678                 {
679                         table->is_owner = 1;
680                         table->tid = pthread_self();
681                         pthread_mutex_unlock(lock);
682                         return;
683                 }
684         }
685         pthread_mutex_unlock(lock);
686 }
687
688 void BC_Signals::unset_lock2(int table_id)
689 {
690         if(!global_signals) return;
691
692         bc_locktrace_t *table = 0;
693         pthread_mutex_lock(lock);
694         for(int i = lock_table.size - 1; i >= 0; i--)
695         {
696                 table = (bc_locktrace_t*)lock_table.values[i];
697                 if(table->id == table_id)
698                 {
699                         clear_table_entry(&lock_table, i, 1);
700                         break;
701                 }
702         }
703         pthread_mutex_unlock(lock);
704 }
705
706 void BC_Signals::unset_lock(void *ptr)
707 {
708         if(!global_signals) return;
709
710         bc_locktrace_t *table = 0;
711         pthread_mutex_lock(lock);
712
713 // Take off currently held entry
714         for(int i = 0; i < lock_table.size; i++)
715         {
716                 table = (bc_locktrace_t*)lock_table.values[i];
717                 if(table->ptr == ptr)
718                 {
719                         if(table->is_owner)
720                         {
721                                 clear_table_entry(&lock_table, i, 1);
722                                 break;
723                         }
724                 }
725         }
726
727         pthread_mutex_unlock(lock);
728 }
729
730
731 void BC_Signals::unset_all_locks(void *ptr)
732 {
733         if(!global_signals) return;
734         pthread_mutex_lock(lock);
735 // Take off previous lock entry
736         for(int i = 0; i < lock_table.size; )
737         {
738                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
739                 if(table->ptr == ptr)
740                 {
741                         clear_table_entry(&lock_table, i, 1);
742                         continue;
743                 }
744                 ++i;
745         }
746         pthread_mutex_unlock(lock);
747 }
748
749 void BC_Signals::clear_locks_tid(pthread_t tid)
750 {
751         if(!global_signals) return;
752         pthread_mutex_lock(lock);
753 // Take off previous lock entry
754         for(int i = 0; i < lock_table.size; )
755         {
756                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
757                 if(table->tid == tid)
758                 {
759                         clear_table_entry(&lock_table, i, 1);
760                         continue;
761                 }
762                 ++i;
763         }
764         pthread_mutex_unlock(lock);
765 }
766
767
768 void BC_Signals::enable_memory()
769 {
770         trace_memory = 1;
771 }
772
773 void BC_Signals::disable_memory()
774 {
775         trace_memory = 0;
776 }
777
778
779 void BC_Signals::set_buffer(int size, void *ptr, const char* location)
780 {
781         if(!global_signals) return;
782         if(!trace_memory) return;
783
784 //printf("BC_Signals::set_buffer %p %s\n", ptr, location);
785         pthread_mutex_lock(lock);
786         append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
787         pthread_mutex_unlock(lock);
788 }
789
790 int BC_Signals::unset_buffer(void *ptr)
791 {
792         if(!global_signals) return 0;
793         if(!trace_memory) return 0;
794
795         int ret = 1;
796         pthread_mutex_lock(lock);
797         for(int i = 0; i < memory_table.size; i++)
798         {
799                 if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
800                 {
801 //printf("BC_Signals::unset_buffer %p\n", ptr);
802                         clear_table_entry(&memory_table, i, 1);
803                         ret = 0;
804                         break;
805                 }
806         }
807
808         pthread_mutex_unlock(lock);
809 //      fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
810         return ret;
811 }
812
813
814 #include <ucontext.h>
815 #include <sys/wait.h>
816 #include "thread.h"
817
818 #if __i386__
819 #define IP eip
820 #endif
821 #if __x86_64__
822 #define IP rip
823 #endif
824 #ifndef IP
825 #error gotta have IP
826 #endif
827
828
829 static void handle_dump(int n, siginfo_t * info, void *sc)
830 {
831         uncatch_segv();  uncatch_intr();
832         signal(SIGSEGV, SIG_DFL);
833         signal(SIGINT, SIG_DFL);
834         // gotta be root, or the dump is worthless
835         int uid = getuid();
836         if( uid != 0 ) return;
837         ucontext_t *uc = (ucontext_t *)sc;
838         int pid = getpid(), tid = gettid();
839         struct sigcontext *c = (struct sigcontext *)&uc->uc_mcontext;
840         uint8_t *ip = (uint8_t *)c->IP;
841         fprintf(stderr,"** %s at %p in pid %d, tid %d\n",
842                 n==SIGSEGV? "segv" : n==SIGINT? "intr" : "trap",
843                 (void*)ip, pid, tid);
844         FILE *fp = 0;
845         char fn[PATH_MAX];
846         if( BC_Signals::trap_path ) {
847                 snprintf(fn, sizeof(fn), BC_Signals::trap_path, pid);
848                 fp = fopen(fn,"w");
849         }
850         if( fp ) {
851                 fprintf(stderr,"writing debug data to %s\n", fn);
852                 fprintf(fp,"** %s at %p in pid %d, tid %d\n",
853                         n==SIGSEGV? "segv" : n==SIGINT? "intr" : "trap",
854                         (void*)c->IP, pid, tid);
855         }
856         else {
857                 strcpy(fn, "stdout");
858                 fp = stdout;
859         }
860         time_t t;  time(&t);
861         fprintf(fp,"created on %s", ctime(&t));
862         struct passwd *pw = getpwuid(uid);
863         if( pw ) {
864                 fprintf(fp,"        by %d:%d %s(%s)\n",
865                         pw->pw_uid, pw->pw_gid, pw->pw_name, pw->pw_gecos);
866         }
867         fprintf(fp,"\nCPUS: %d\n",   BC_Resources::get_machine_cpus());
868         fprintf(fp,"\nCPUINFO:\n");  bc_copy_textfile(32, fp,"/proc/cpuinfo");
869         fprintf(fp,"\nTHREADS:\n");  Thread::dump_threads(fp);
870         fprintf(fp,"\nTRACES:\n");   BC_Signals::dump_traces(fp);
871         fprintf(fp,"\nLOCKS:\n");    BC_Signals::dump_locks(fp);
872         fprintf(fp,"\nBUFFERS:\n");  BC_Signals::dump_buffers(fp);
873         if( BC_Signals::trap_hook ) {
874                 fprintf(fp,"\nMAIN HOOK:\n");
875                 BC_Signals::trap_hook(fp, BC_Signals::trap_data);
876         }
877         fprintf(fp,"\nVERSION:\n");  bc_copy_textfile(INT_MAX, fp,"/proc/version");
878         fprintf(fp,"\nMEMINFO:\n");  bc_copy_textfile(INT_MAX, fp,"/proc/meminfo");
879         fprintf(fp,"\nMAPS:\n");     bc_copy_textfile(INT_MAX, fp,"/proc/%d/maps",pid);
880         char proc_mem[64];
881         if( tid > 0 && tid != pid )
882                 sprintf(proc_mem,"/proc/%d/task/%d/mem",pid,tid);
883         else
884                 sprintf(proc_mem,"/proc/%d/mem",pid);
885         int pfd = open(proc_mem,O_RDONLY);
886         if( pfd >= 0 ) {
887                 fprintf(fp,"\nCODE:\n");
888                 for( int i=-32; i<32; ) {
889                         uint8_t v;  void *vp = (void *)(ip + i);
890                         if( !(i & 7) ) fprintf(fp,"%p:  ", vp);
891                         if( pread(pfd,&v,sizeof(v),(off_t)vp) != sizeof(v) ) break;
892                         fprintf(fp,"%c%02x", !i ? '>' : ' ', v);
893                         if( !(++i & 7) ) fprintf(fp,"\n");
894                 }
895                 fprintf(fp,"\n");
896                 close(pfd);
897         }
898         else
899                 fprintf(fp,"err opening: %s, %m\n", proc_mem);
900
901         fprintf(fp,"\n\n");
902         if( fp != stdout ) fclose(fp);
903         char cmd[1024], *cp = cmd;
904         cp += sprintf(cp, "exec gdb /proc/%d/exe -p %d --batch --quiet "
905                 "-ex \"thread apply all info registers\" "
906                 "-ex \"thread apply all bt full\" "
907                 "-ex \"quit\"", pid, pid);
908         if( fp != stdout )
909                 cp += sprintf(cp," >> \"%s\"", fn);
910         cp += sprintf(cp," 2>&1");
911 //printf("handle_dump:: pid=%d, cmd='%s'  fn='%s'\n",pid,cmd,fn);
912         pid = vfork();
913         if( pid < 0 ) {
914                 fprintf(stderr,"** can't start gdb, dump abondoned\n");
915                 return;
916         }
917         if( pid > 0 ) {
918                 waitpid(pid,0,0);
919                 fprintf(stderr,"** dump complete\n");
920                 return;
921         }
922         char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
923         execvp(argv[0], &argv[0]);
924 }
925
926
927
928
929
930 #ifdef TRACE_MEMORY
931
932 // void* operator new(size_t size)
933 // {
934 // //printf("new 1 %d\n", size);
935 //     void *result = malloc(size);
936 //      BUFFER(size, result, "new");
937 // //printf("new 2 %d\n", size);
938 //      return result;
939 // }
940 //
941 // void* operator new[](size_t size)
942 // {
943 // //printf("new [] 1 %d\n", size);
944 //     void *result = malloc(size);
945 //      BUFFER(size, result, "new []");
946 // //printf("new [] 2 %d\n", size);
947 //      return result;
948 // }
949 //
950 // void operator delete(void *ptr)
951 // {
952 // //printf("delete 1 %p\n", ptr);
953 //      UNBUFFER(ptr);
954 // //printf("delete 2 %p\n", ptr);
955 //     free(ptr);
956 // }
957 //
958 // void operator delete[](void *ptr)
959 // {
960 // //printf("delete [] 1 %p\n", ptr);
961 //      UNBUFFER(ptr);
962 //     free(ptr);
963 // //printf("delete [] 2 %p\n", ptr);
964 // }
965
966
967 #endif