blob: a4ee35b03c134b9ac20ab8ca98cec8b32817c059 [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:
33 return;
34 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010035 if (opt_d>0) {
36 output_line(0, "event: signal (%d)", event->e_un.signum);
37 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010038 process_signal(event);
39 return;
40 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010041 if (opt_d>0) {
42 output_line(0, "event: exit (%d)", event->e_un.ret_val);
43 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010044 process_exit(event);
45 return;
46 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010047 if (opt_d>0) {
48 output_line(0, "event: exit signal (%d)", event->e_un.signum);
49 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010050 process_exit_signal(event);
51 return;
52 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010053 if (opt_d>0) {
54 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
55 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010056 process_syscall(event);
57 return;
58 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010059 if (opt_d>0) {
60 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
61 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010062 process_sysret(event);
63 return;
64 case LT_EV_BREAKPOINT:
65 process_breakpoint(event);
66 return;
67 default:
68 fprintf(stderr, "Error! unknown event?\n");
69 exit(1);
70 }
71}
72
Juan Cespedes21c63a12001-07-07 20:56:56 +020073static char *
74shortsignal(int signum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010075 static char * signalent0[] = {
76 #include "signalent.h"
77 };
78 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
79
80 if (signum<0 || signum>nsignals0) {
81 return "UNKNOWN_SIGNAL";
82 } else {
83 return signalent0[signum];
84 }
85}
86
Juan Cespedes21c63a12001-07-07 20:56:56 +020087static char *
88sysname(int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010089 static char result[128];
90 static char * syscalent0[] = {
91 #include "syscallent.h"
92 };
93 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
94
95 if (sysnum<0 || sysnum>nsyscals0) {
96 sprintf(result, "SYS_%d", sysnum);
97 return result;
98 } else {
99 sprintf(result, "SYS_%s", syscalent0[sysnum]);
100 return result;
101 }
102}
103
Juan Cespedes21c63a12001-07-07 20:56:56 +0200104static void
105process_signal(struct event * event) {
Juan Cespedes28f60191998-04-12 00:04:39 +0200106 if (exiting && event->e_un.signum == SIGSTOP) {
107 pid_t pid = event->proc->pid;
108 disable_all_breakpoints(event->proc);
109 untrace_pid(pid);
110 remove_proc(event->proc);
111 continue_after_signal(pid, event->e_un.signum);
112 return;
113 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100114 output_line(event->proc, "--- %s (%s) ---",
115 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
116 continue_after_signal(event->proc->pid, event->e_un.signum);
117}
118
Juan Cespedes21c63a12001-07-07 20:56:56 +0200119static void
120process_exit(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100121 output_line(event->proc, "+++ exited (status %d) +++",
122 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100123 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100124}
125
Juan Cespedes21c63a12001-07-07 20:56:56 +0200126static void
127process_exit_signal(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100128 output_line(event->proc, "+++ killed by %s +++",
129 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100130 remove_proc(event->proc);
131}
132
Juan Cespedes21c63a12001-07-07 20:56:56 +0200133static void
134remove_proc(struct process * proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100135 struct process *tmp, *tmp2;
136
Juan Cespedes28f60191998-04-12 00:04:39 +0200137 if (opt_d) {
138 output_line(0,"Removing pid %u\n", proc->pid);
139 }
140
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100141 if (list_of_processes == proc) {
142 tmp = list_of_processes;
143 list_of_processes = list_of_processes->next;
144 free(tmp);
145 return;
146 }
147 tmp = list_of_processes;
148 while(tmp->next) {
149 if (tmp->next==proc) {
150 tmp2 = tmp->next;
151 tmp->next = tmp->next->next;
152 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200153 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100154 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100155 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100156 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100157}
158
Juan Cespedes21c63a12001-07-07 20:56:56 +0200159static void
160process_syscall(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100161 if (opt_S) {
162 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
163 }
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200164 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100165 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100166 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100167 } else if (!event->proc->breakpoints_enabled) {
168 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100169 }
170 continue_process(event->proc->pid);
171}
172
Juan Cespedes21c63a12001-07-07 20:56:56 +0200173static void
174process_sysret(struct event * event) {
Juan Cespedes81690ef1998-03-13 19:31:29 +0100175 if (exec_p(event->e_un.sysnum)) {
176 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200177 struct library_symbol * sym;
178
Juan Cespedes81690ef1998-03-13 19:31:29 +0100179 event->proc->filename = pid2name(event->proc->pid);
180 event->proc->list_of_symbols = read_elf(event->proc->filename);
Juan Cespedes53eabb12001-12-10 04:11:39 +0100181 /* This should fix Bug#108835 : */
182#if 0
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200183 sym = event->proc->list_of_symbols;
184 while (sym) {
185 insert_breakpoint(event->proc, sym->enter_addr);
186 sym = sym->next;
187 }
188 event->proc->breakpoints_enabled = 1;
Juan Cespedes53eabb12001-12-10 04:11:39 +0100189#else
190 event->proc->breakpoints_enabled = -1;
191#endif
Juan Cespedes81690ef1998-03-13 19:31:29 +0100192 }
193 }
194 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100195 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100196 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
197 if (child>0) {
198 open_pid(child, 0);
199 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100200 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100201 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100202 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200203 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200204 if (opt_S) {
205 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
206 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100207 continue_process(event->proc->pid);
208}
209
Juan Cespedes21c63a12001-07-07 20:56:56 +0200210static void
211process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100212 struct library_symbol * tmp;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200213 void * return_addr;
214 struct callstack_element * current_call = event->proc->callstack_depth>0 ?
215 &(event->proc->callstack[event->proc->callstack_depth-1]) : NULL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100216
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100217 if (opt_d>1) {
218 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
219 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100220 if (event->proc->breakpoint_being_enabled) {
221 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
222 event->proc->breakpoint_being_enabled = NULL;
223 return;
224 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200225
226 if (current_call && !current_call->is_syscall && event->e_un.brk_addr == current_call->return_addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200227 return_addr = current_call->return_addr;
228 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200229 output_right(LT_TOF_FUNCTION, event->proc, current_call->c_un.libfunc->name);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200230 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, return_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100231 return;
232 }
233
234 tmp = event->proc->list_of_symbols;
235 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200236 if (event->e_un.brk_addr == tmp->enter_addr) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200237 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
238 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100239 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200240 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200241 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100242 return;
243 }
244 tmp = tmp->next;
245 }
246 output_line(event->proc, "breakpointed at 0x%08x (?)",
247 (unsigned)event->e_un.brk_addr);
248 continue_process(event->proc->pid);
249}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200250
Juan Cespedes21c63a12001-07-07 20:56:56 +0200251static void
252callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200253 struct callstack_element * elem;
254
255 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
256 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
257 fprintf(stderr, "Error: call nesting too deep!\n");
258 return;
259 }
260
261 elem = & proc->callstack[proc->callstack_depth];
262 elem->is_syscall = 1;
263 elem->c_un.syscall = sysnum;
264 elem->return_addr = NULL;
265
266 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200267}
268
Juan Cespedes21c63a12001-07-07 20:56:56 +0200269static void
270callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200271 struct callstack_element * elem;
272
273 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
274 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
275 fprintf(stderr, "Error: call nesting too deep!\n");
276 return;
277 }
278
279 elem = & proc->callstack[proc->callstack_depth];
280 elem->is_syscall = 0;
281 elem->c_un.libfunc = sym;
282
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200283 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200284 insert_breakpoint(proc, elem->return_addr);
285
286 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200287}
288
Juan Cespedes21c63a12001-07-07 20:56:56 +0200289static void
290callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200291 struct callstack_element * elem;
292 assert(proc->callstack_depth > 0);
293
294 elem = & proc->callstack[proc->callstack_depth-1];
295 if (!elem->is_syscall) {
296 delete_breakpoint(proc, elem->return_addr);
297 }
298 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200299}