blob: e5ca870463ea59bca2cad90fca3f6c02a00dd521 [file] [log] [blame]
Juan Cespedes5e01f651998-03-08 22:31:44 +01001#define _GNU_SOURCE
2#include <stdio.h>
3#include <string.h>
Juan Cespedes1fe93d51998-03-13 00:29:21 +01004#include <stdlib.h>
Juan Cespedes28f60191998-04-12 00:04:39 +02005#include <signal.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +01006
7#include "ltrace.h"
8#include "output.h"
9#include "options.h"
Juan Cespedes81690ef1998-03-13 19:31:29 +010010#include "elf.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010011
12static void process_signal(struct event * event);
13static void process_exit(struct event * event);
14static void process_exit_signal(struct event * event);
15static void process_syscall(struct event * event);
16static void process_sysret(struct event * event);
17static void process_breakpoint(struct event * event);
18
19void process_event(struct event * event)
20{
21 switch (event->thing) {
22 case LT_EV_NONE:
23 return;
24 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010025 if (opt_d>0) {
26 output_line(0, "event: signal (%d)", event->e_un.signum);
27 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010028 process_signal(event);
29 return;
30 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010031 if (opt_d>0) {
32 output_line(0, "event: exit (%d)", event->e_un.ret_val);
33 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010034 process_exit(event);
35 return;
36 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010037 if (opt_d>0) {
38 output_line(0, "event: exit signal (%d)", event->e_un.signum);
39 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010040 process_exit_signal(event);
41 return;
42 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010043 if (opt_d>0) {
44 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
45 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010046 process_syscall(event);
47 return;
48 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010049 if (opt_d>0) {
50 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
51 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010052 process_sysret(event);
53 return;
54 case LT_EV_BREAKPOINT:
55 process_breakpoint(event);
56 return;
57 default:
58 fprintf(stderr, "Error! unknown event?\n");
59 exit(1);
60 }
61}
62
63static char * shortsignal(int signum)
64{
65 static char * signalent0[] = {
66 #include "signalent.h"
67 };
68 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
69
70 if (signum<0 || signum>nsignals0) {
71 return "UNKNOWN_SIGNAL";
72 } else {
73 return signalent0[signum];
74 }
75}
76
77static char * sysname(int sysnum)
78{
79 static char result[128];
80 static char * syscalent0[] = {
81 #include "syscallent.h"
82 };
83 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
84
85 if (sysnum<0 || sysnum>nsyscals0) {
86 sprintf(result, "SYS_%d", sysnum);
87 return result;
88 } else {
89 sprintf(result, "SYS_%s", syscalent0[sysnum]);
90 return result;
91 }
92}
93
Juan Cespedes28f60191998-04-12 00:04:39 +020094static void remove_proc(struct process * proc);
95
Juan Cespedes5e01f651998-03-08 22:31:44 +010096static void process_signal(struct event * event)
97{
Juan Cespedes28f60191998-04-12 00:04:39 +020098 if (exiting && event->e_un.signum == SIGSTOP) {
99 pid_t pid = event->proc->pid;
100 disable_all_breakpoints(event->proc);
101 untrace_pid(pid);
102 remove_proc(event->proc);
103 continue_after_signal(pid, event->e_un.signum);
104 return;
105 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100106 output_line(event->proc, "--- %s (%s) ---",
107 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
108 continue_after_signal(event->proc->pid, event->e_un.signum);
109}
110
111static void process_exit(struct event * event)
112{
113 output_line(event->proc, "+++ exited (status %d) +++",
114 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100115 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100116}
117
118static void process_exit_signal(struct event * event)
119{
120 output_line(event->proc, "+++ killed by %s +++",
121 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100122 remove_proc(event->proc);
123}
124
125static void remove_proc(struct process * proc)
126{
127 struct process *tmp, *tmp2;
128
Juan Cespedes28f60191998-04-12 00:04:39 +0200129 if (opt_d) {
130 output_line(0,"Removing pid %u\n", proc->pid);
131 }
132
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100133 if (list_of_processes == proc) {
134 tmp = list_of_processes;
135 list_of_processes = list_of_processes->next;
136 free(tmp);
137 return;
138 }
139 tmp = list_of_processes;
140 while(tmp->next) {
141 if (tmp->next==proc) {
142 tmp2 = tmp->next;
143 tmp->next = tmp->next->next;
144 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200145 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100146 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100147 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100148 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100149}
150
151static void process_syscall(struct event * event)
152{
153 event->proc->current_syscall = event->e_un.sysnum;
154 if (opt_S) {
155 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
156 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100157 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100158 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100159 } else if (!event->proc->breakpoints_enabled) {
160 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100161 }
162 continue_process(event->proc->pid);
163}
164
165static void process_sysret(struct event * event)
166{
167 if (opt_S) {
168 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
169 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100170 if (exec_p(event->e_un.sysnum)) {
171 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
172 event->proc->filename = pid2name(event->proc->pid);
173 event->proc->list_of_symbols = read_elf(event->proc->filename);
174 event->proc->breakpoints_enabled = -1;
175 } else {
176 enable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100177 }
178 }
179 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100180 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100181 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
182 if (child>0) {
183 open_pid(child, 0);
184 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100185 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100186 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100187 }
188 event->proc->current_syscall = -1;
189 continue_process(event->proc->pid);
190}
191
192static void process_breakpoint(struct event * event)
193{
194 struct library_symbol * tmp;
195
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100196 if (opt_d>1) {
197 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
198 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100199 if (event->proc->breakpoint_being_enabled) {
200 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
201 event->proc->breakpoint_being_enabled = NULL;
202 return;
203 }
204 if (event->proc->current_symbol && event->e_un.brk_addr == event->proc->return_value.addr) {
205 output_right(LT_TOF_FUNCTION, event->proc, event->proc->current_symbol->name);
206 continue_after_breakpoint(event->proc, &event->proc->return_value, 1);
207 event->proc->current_symbol = NULL;
208 return;
209 }
210
211 tmp = event->proc->list_of_symbols;
212 while(tmp) {
213 if (event->e_un.brk_addr == tmp->brk.addr) {
214 if (event->proc->current_symbol) {
215 delete_breakpoint(event->proc->pid, &event->proc->return_value);
216 }
217 event->proc->current_symbol = tmp;
218 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
219 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
220 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
221 event->proc->return_value.addr = event->proc->return_addr;
222 insert_breakpoint(event->proc->pid, &event->proc->return_value);
223 continue_after_breakpoint(event->proc, &tmp->brk, 0);
224 return;
225 }
226 tmp = tmp->next;
227 }
228 output_line(event->proc, "breakpointed at 0x%08x (?)",
229 (unsigned)event->e_un.brk_addr);
230 continue_process(event->proc->pid);
231}