blob: 0f0fac41a0e897b84ee1a2acea8b27ee41cbb2e5 [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Juan Cespedes5e01f651998-03-08 22:31:44 +01005#define _GNU_SOURCE
6#include <stdio.h>
7#include <string.h>
Juan Cespedes1fe93d51998-03-13 00:29:21 +01008#include <stdlib.h>
Juan Cespedes28f60191998-04-12 00:04:39 +02009#include <signal.h>
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020010#include <assert.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010011
12#include "ltrace.h"
13#include "output.h"
14#include "options.h"
Juan Cespedes81690ef1998-03-13 19:31:29 +010015#include "elf.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010016
17static void process_signal(struct event * event);
18static void process_exit(struct event * event);
19static void process_exit_signal(struct event * event);
20static void process_syscall(struct event * event);
21static void process_sysret(struct event * event);
22static void process_breakpoint(struct event * event);
Juan Cespedes21c63a12001-07-07 20:56:56 +020023static void remove_proc(struct process * proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010024
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020025static void callstack_push_syscall(struct process * proc, int sysnum);
26static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym);
27static void callstack_pop(struct process * proc);
28
Juan Cespedes21c63a12001-07-07 20:56:56 +020029void
30process_event(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010031 switch (event->thing) {
32 case LT_EV_NONE:
Juan Cespedes5916fda2002-02-25 00:19:21 +010033 if (opt_d>0) {
34 output_line(0, "event: none");
35 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010036 return;
37 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010038 if (opt_d>0) {
39 output_line(0, "event: signal (%d)", event->e_un.signum);
40 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010041 process_signal(event);
42 return;
43 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010044 if (opt_d>0) {
45 output_line(0, "event: exit (%d)", event->e_un.ret_val);
46 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010047 process_exit(event);
48 return;
49 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010050 if (opt_d>0) {
51 output_line(0, "event: exit signal (%d)", event->e_un.signum);
52 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010053 process_exit_signal(event);
54 return;
55 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010056 if (opt_d>0) {
57 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
58 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010059 process_syscall(event);
60 return;
61 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010062 if (opt_d>0) {
63 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
64 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010065 process_sysret(event);
66 return;
67 case LT_EV_BREAKPOINT:
Juan Cespedes5916fda2002-02-25 00:19:21 +010068 if (opt_d>0) {
69 output_line(0, "event: breakpoint");
70 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010071 process_breakpoint(event);
72 return;
73 default:
74 fprintf(stderr, "Error! unknown event?\n");
75 exit(1);
76 }
77}
78
Juan Cespedes21c63a12001-07-07 20:56:56 +020079static char *
80shortsignal(int signum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010081 static char * signalent0[] = {
82 #include "signalent.h"
83 };
84 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
85
86 if (signum<0 || signum>nsignals0) {
87 return "UNKNOWN_SIGNAL";
88 } else {
89 return signalent0[signum];
90 }
91}
92
Juan Cespedes21c63a12001-07-07 20:56:56 +020093static char *
94sysname(int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010095 static char result[128];
96 static char * syscalent0[] = {
97 #include "syscallent.h"
98 };
99 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
100
101 if (sysnum<0 || sysnum>nsyscals0) {
102 sprintf(result, "SYS_%d", sysnum);
103 return result;
104 } else {
105 sprintf(result, "SYS_%s", syscalent0[sysnum]);
106 return result;
107 }
108}
109
Juan Cespedes21c63a12001-07-07 20:56:56 +0200110static void
111process_signal(struct event * event) {
Juan Cespedes28f60191998-04-12 00:04:39 +0200112 if (exiting && event->e_un.signum == SIGSTOP) {
113 pid_t pid = event->proc->pid;
114 disable_all_breakpoints(event->proc);
115 untrace_pid(pid);
116 remove_proc(event->proc);
117 continue_after_signal(pid, event->e_un.signum);
118 return;
119 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100120 output_line(event->proc, "--- %s (%s) ---",
121 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
122 continue_after_signal(event->proc->pid, event->e_un.signum);
123}
124
Juan Cespedes21c63a12001-07-07 20:56:56 +0200125static void
126process_exit(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100127 output_line(event->proc, "+++ exited (status %d) +++",
128 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100129 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100130}
131
Juan Cespedes21c63a12001-07-07 20:56:56 +0200132static void
133process_exit_signal(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100134 output_line(event->proc, "+++ killed by %s +++",
135 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100136 remove_proc(event->proc);
137}
138
Juan Cespedes21c63a12001-07-07 20:56:56 +0200139static void
140remove_proc(struct process * proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100141 struct process *tmp, *tmp2;
142
Juan Cespedes28f60191998-04-12 00:04:39 +0200143 if (opt_d) {
144 output_line(0,"Removing pid %u\n", proc->pid);
145 }
146
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100147 if (list_of_processes == proc) {
148 tmp = list_of_processes;
149 list_of_processes = list_of_processes->next;
150 free(tmp);
151 return;
152 }
153 tmp = list_of_processes;
154 while(tmp->next) {
155 if (tmp->next==proc) {
156 tmp2 = tmp->next;
157 tmp->next = tmp->next->next;
158 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200159 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100160 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100161 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100162 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100163}
164
Juan Cespedes21c63a12001-07-07 20:56:56 +0200165static void
166process_syscall(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100167 if (opt_S) {
168 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
169 }
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200170 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100171 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100172 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100173 } else if (!event->proc->breakpoints_enabled) {
174 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100175 }
176 continue_process(event->proc->pid);
177}
178
Juan Cespedes21c63a12001-07-07 20:56:56 +0200179static void
180process_sysret(struct event * event) {
Juan Cespedes81690ef1998-03-13 19:31:29 +0100181 if (exec_p(event->e_un.sysnum)) {
182 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200183
Juan Cespedes81690ef1998-03-13 19:31:29 +0100184 event->proc->filename = pid2name(event->proc->pid);
185 event->proc->list_of_symbols = read_elf(event->proc->filename);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100186
187 /* The kernel will stop the process just after an execve()
188 * and we will be able to enable breakpoints again
189 */
Juan Cespedes53eabb12001-12-10 04:11:39 +0100190 event->proc->breakpoints_enabled = -1;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100191 }
192 }
193 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100194 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100195 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
196 if (child>0) {
197 open_pid(child, 0);
198 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100199 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100200 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100201 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200202 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200203 if (opt_S) {
204 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
205 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100206 continue_process(event->proc->pid);
207}
208
Juan Cespedes21c63a12001-07-07 20:56:56 +0200209static void
210process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100211 struct library_symbol * tmp;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100212 int i,j;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100213
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100214 if (opt_d>1) {
215 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
216 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100217 if (event->proc->breakpoint_being_enabled) {
218 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
219 event->proc->breakpoint_being_enabled = NULL;
220 return;
221 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200222
Juan Cespedes5916fda2002-02-25 00:19:21 +0100223 for(i=event->proc->callstack_depth-1; i>=0; i--) {
224 if (event->e_un.brk_addr == event->proc->callstack[i].return_addr) {
225 for(j=event->proc->callstack_depth-1; j>=i; j--) {
226 callstack_pop(event->proc);
227 }
228 event->proc->return_addr = event->e_un.brk_addr;
229 output_right(LT_TOF_FUNCTION, event->proc,
230 event->proc->callstack[i].c_un.libfunc->name);
231 continue_after_breakpoint(event->proc,
232 address2bpstruct(event->proc, event->e_un.brk_addr));
233 return;
234 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100235 }
236
237 tmp = event->proc->list_of_symbols;
238 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200239 if (event->e_un.brk_addr == tmp->enter_addr) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200240 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
241 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100242 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200243 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200244 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100245 return;
246 }
247 tmp = tmp->next;
248 }
249 output_line(event->proc, "breakpointed at 0x%08x (?)",
250 (unsigned)event->e_un.brk_addr);
251 continue_process(event->proc->pid);
252}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200253
Juan Cespedes21c63a12001-07-07 20:56:56 +0200254static void
255callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200256 struct callstack_element * elem;
257
258 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
259 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
260 fprintf(stderr, "Error: call nesting too deep!\n");
261 return;
262 }
263
264 elem = & proc->callstack[proc->callstack_depth];
265 elem->is_syscall = 1;
266 elem->c_un.syscall = sysnum;
267 elem->return_addr = NULL;
268
269 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200270}
271
Juan Cespedes21c63a12001-07-07 20:56:56 +0200272static void
273callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200274 struct callstack_element * elem;
275
276 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
277 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
278 fprintf(stderr, "Error: call nesting too deep!\n");
279 return;
280 }
281
282 elem = & proc->callstack[proc->callstack_depth];
283 elem->is_syscall = 0;
284 elem->c_un.libfunc = sym;
285
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200286 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200287 insert_breakpoint(proc, elem->return_addr);
288
289 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200290}
291
Juan Cespedes21c63a12001-07-07 20:56:56 +0200292static void
293callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200294 struct callstack_element * elem;
295 assert(proc->callstack_depth > 0);
296
297 elem = & proc->callstack[proc->callstack_depth-1];
298 if (!elem->is_syscall) {
299 delete_breakpoint(proc, elem->return_addr);
300 }
301 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200302}