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