libltrace.c revision e6c00ae8228be812c7361b5e193779a81aa00cd8
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2009 Juan Cespedes 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of the 9 * License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * 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., 51 Franklin St, Fifth Floor, Boston, MA 19 * 02110-1301 USA 20 */ 21 22#include "config.h" 23 24#include <limits.h> 25#include <sys/param.h> 26#include <sys/wait.h> 27#include <errno.h> 28#include <signal.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33 34#include "common.h" 35#include "proc.h" 36#include "read_config_file.h" 37#include "backend.h" 38#include "prototype.h" 39 40char *command = NULL; 41 42int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */ 43 44static enum callback_status 45stop_non_p_processes(struct process *proc, void *data) 46{ 47 int stop = 1; 48 49 struct opt_p_t *it; 50 for (it = opt_p; it != NULL; it = it->next) { 51 struct process *p_proc = pid2proc(it->pid); 52 if (p_proc == NULL) { 53 printf("stop_non_p_processes: %d terminated?\n", it->pid); 54 continue; 55 } 56 if (p_proc == proc || p_proc->leader == proc->leader) { 57 stop = 0; 58 break; 59 } 60 } 61 62 if (stop) { 63 debug(2, "Sending SIGSTOP to process %u", proc->pid); 64 kill(proc->pid, SIGSTOP); 65 } 66 67 return CBS_CONT; 68} 69 70static void 71signal_alarm(int sig) { 72 signal(SIGALRM, SIG_DFL); 73 each_process(NULL, &stop_non_p_processes, NULL); 74} 75 76static void 77signal_exit(int sig) 78{ 79 if (exiting != 0) 80 return; 81 82 exiting = 1 + !!os_ltrace_exiting_sighandler(); 83 84 signal(SIGINT, SIG_IGN); 85 signal(SIGTERM, SIG_IGN); 86 signal(SIGALRM, signal_alarm); 87 //alarm(1); 88} 89 90static void 91normal_exit(void) 92{ 93 if (options.summary) { 94 show_summary(); 95 destroy_global_config(); 96 } 97 if (options.output) { 98 fclose(options.output); 99 options.output = NULL; 100 } 101} 102 103void 104ltrace_init(int argc, char **argv) { 105 struct opt_p_t *opt_p_tmp; 106 107 atexit(normal_exit); 108 signal(SIGINT, signal_exit); /* Detach processes when interrupted */ 109 signal(SIGTERM, signal_exit); /* ... or killed */ 110 111 argv = process_options(argc, argv); 112 init_global_config(); 113 while (opt_F) { 114 /* If filename begins with ~, expand it to the user's home */ 115 /* directory. This does not correctly handle ~yoda, but that */ 116 /* isn't as bad as it seems because the shell will normally */ 117 /* be doing the expansion for us; only the hardcoded */ 118 /* ~/.ltrace.conf should ever use this code. */ 119 if (opt_F->filename[0] == '~') { 120 char path[PATH_MAX]; 121 char *home_dir = getenv("HOME"); 122 if (home_dir) { 123 strncpy(path, home_dir, PATH_MAX - 1); 124 path[PATH_MAX - 1] = '\0'; 125 strncat(path, opt_F->filename + 1, 126 PATH_MAX - strlen(path) - 1); 127 read_config_file(&g_prototypes, path); 128 } 129 } else { 130 read_config_file(&g_prototypes, opt_F->filename); 131 } 132 133 struct opt_F_t *next = opt_F->next; 134 if (opt_F->own_filename) 135 free(opt_F->filename); 136 free(opt_F); 137 opt_F = next; 138 } 139 if (command) { 140 /* Check that the binary ABI is supported before 141 * calling execute_program. */ 142 struct ltelf lte = {}; 143 open_elf(<e, command); 144 do_close_elf(<e); 145 146 pid_t pid = execute_program(command, argv); 147 struct process *proc = open_program(command, pid); 148 if (proc == NULL) { 149 fprintf(stderr, "couldn't open program '%s': %s\n", 150 command, strerror(errno)); 151 exit(EXIT_FAILURE); 152 } 153 154 trace_set_options(proc); 155 continue_process(pid); 156 } 157 opt_p_tmp = opt_p; 158 while (opt_p_tmp) { 159 open_pid(opt_p_tmp->pid); 160 opt_p_tmp = opt_p_tmp->next; 161 } 162} 163 164static int num_ltrace_callbacks[EVENT_MAX]; 165static callback_func * ltrace_callbacks[EVENT_MAX]; 166 167void 168ltrace_add_callback(callback_func func, Event_type type) { 169 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func)); 170 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func; 171} 172 173static void 174dispatch_callbacks(Event * ev) { 175 int i; 176 /* Ignoring case 1: signal into a dying tracer */ 177 if (ev->type==EVENT_SIGNAL && 178 exiting && ev->e_un.signum == SIGSTOP) { 179 return; 180 } 181 /* Ignoring case 2: process being born before a clone event */ 182 if (ev->proc && ev->proc->state == STATE_IGNORED) { 183 return; 184 } 185 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) { 186 ltrace_callbacks[ev->type][i](ev); 187 } 188} 189 190void 191ltrace_main(void) { 192 Event * ev; 193 while (1) { 194 ev = next_event(); 195 dispatch_callbacks(ev); 196 handle_event(ev); 197 } 198} 199