blob: e314c259c5ce78e562286fc5dd944ef38b4b44d0 [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 Cespedescac15c32003-01-31 18:58:58 +010016#include "debug.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010017
Juan Cespedesf1bfe202002-03-27 00:22:23 +010018#ifdef __powerpc__
19#include <sys/ptrace.h>
20#endif
21
Juan Cespedes5e01f651998-03-08 22:31:44 +010022static void process_signal(struct event * event);
23static void process_exit(struct event * event);
24static void process_exit_signal(struct event * event);
25static void process_syscall(struct event * event);
26static void process_sysret(struct event * event);
27static void process_breakpoint(struct event * event);
Juan Cespedes21c63a12001-07-07 20:56:56 +020028static void remove_proc(struct process * proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010029
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020030static void callstack_push_syscall(struct process * proc, int sysnum);
31static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym);
32static void callstack_pop(struct process * proc);
33
Juan Cespedes21c63a12001-07-07 20:56:56 +020034void
35process_event(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010036 switch (event->thing) {
37 case LT_EV_NONE:
Juan Cespedescac15c32003-01-31 18:58:58 +010038 debug(1, "event: none");
Juan Cespedes5e01f651998-03-08 22:31:44 +010039 return;
40 case LT_EV_SIGNAL:
Juan Cespedescac15c32003-01-31 18:58:58 +010041 debug(1, "event: signal (%d)", event->e_un.signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +010042 process_signal(event);
43 return;
44 case LT_EV_EXIT:
Juan Cespedescac15c32003-01-31 18:58:58 +010045 debug(1, "event: exit (%d)", event->e_un.ret_val);
Juan Cespedes5e01f651998-03-08 22:31:44 +010046 process_exit(event);
47 return;
48 case LT_EV_EXIT_SIGNAL:
Juan Cespedescac15c32003-01-31 18:58:58 +010049 debug(1, "event: exit signal (%d)", event->e_un.signum);
Juan Cespedes5e01f651998-03-08 22:31:44 +010050 process_exit_signal(event);
51 return;
52 case LT_EV_SYSCALL:
Juan Cespedescac15c32003-01-31 18:58:58 +010053 debug(1, "event: syscall (%d)", event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +010054 process_syscall(event);
55 return;
56 case LT_EV_SYSRET:
Juan Cespedescac15c32003-01-31 18:58:58 +010057 debug(1, "event: sysret (%d)", event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +010058 process_sysret(event);
59 return;
60 case LT_EV_BREAKPOINT:
Juan Cespedescac15c32003-01-31 18:58:58 +010061 debug(1, "event: breakpoint");
Juan Cespedes5e01f651998-03-08 22:31:44 +010062 process_breakpoint(event);
63 return;
64 default:
65 fprintf(stderr, "Error! unknown event?\n");
66 exit(1);
67 }
68}
69
Juan Cespedes21c63a12001-07-07 20:56:56 +020070static char *
71shortsignal(int signum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010072 static char * signalent0[] = {
73 #include "signalent.h"
74 };
75 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
76
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010077 if (signum<0 || signum>=nsignals0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010078 return "UNKNOWN_SIGNAL";
79 } else {
80 return signalent0[signum];
81 }
82}
83
Juan Cespedes21c63a12001-07-07 20:56:56 +020084static char *
85sysname(int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010086 static char result[128];
87 static char * syscalent0[] = {
88 #include "syscallent.h"
89 };
90 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
91
92 if (sysnum<0 || sysnum>nsyscals0) {
93 sprintf(result, "SYS_%d", sysnum);
94 return result;
95 } else {
96 sprintf(result, "SYS_%s", syscalent0[sysnum]);
97 return result;
98 }
99}
100
Juan Cespedes21c63a12001-07-07 20:56:56 +0200101static void
102process_signal(struct event * event) {
Juan Cespedes28f60191998-04-12 00:04:39 +0200103 if (exiting && event->e_un.signum == SIGSTOP) {
104 pid_t pid = event->proc->pid;
105 disable_all_breakpoints(event->proc);
106 untrace_pid(pid);
107 remove_proc(event->proc);
108 continue_after_signal(pid, event->e_un.signum);
109 return;
110 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100111 output_line(event->proc, "--- %s (%s) ---",
112 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
113 continue_after_signal(event->proc->pid, event->e_un.signum);
114}
115
Juan Cespedes21c63a12001-07-07 20:56:56 +0200116static void
117process_exit(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100118 output_line(event->proc, "+++ exited (status %d) +++",
119 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100120 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100121}
122
Juan Cespedes21c63a12001-07-07 20:56:56 +0200123static void
124process_exit_signal(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100125 output_line(event->proc, "+++ killed by %s +++",
126 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100127 remove_proc(event->proc);
128}
129
Juan Cespedes21c63a12001-07-07 20:56:56 +0200130static void
131remove_proc(struct process * proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100132 struct process *tmp, *tmp2;
133
Juan Cespedescac15c32003-01-31 18:58:58 +0100134 debug(1, "Removing pid %u\n", proc->pid);
Juan Cespedes28f60191998-04-12 00:04:39 +0200135
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100136 if (list_of_processes == proc) {
137 tmp = list_of_processes;
138 list_of_processes = list_of_processes->next;
139 free(tmp);
140 return;
141 }
142 tmp = list_of_processes;
143 while(tmp->next) {
144 if (tmp->next==proc) {
145 tmp2 = tmp->next;
146 tmp->next = tmp->next->next;
147 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200148 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100149 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100150 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100151 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100152}
153
Juan Cespedes21c63a12001-07-07 20:56:56 +0200154static void
155process_syscall(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100156 if (opt_S) {
157 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
158 }
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200159 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100160 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100161 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100162 } else if (!event->proc->breakpoints_enabled) {
163 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100164 }
165 continue_process(event->proc->pid);
166}
167
Juan Cespedes21c63a12001-07-07 20:56:56 +0200168static void
169process_sysret(struct event * event) {
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) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200172
Juan Cespedes81690ef1998-03-13 19:31:29 +0100173 event->proc->filename = pid2name(event->proc->pid);
174 event->proc->list_of_symbols = read_elf(event->proc->filename);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100175
176 /* The kernel will stop the process just after an execve()
177 * and we will be able to enable breakpoints again
178 */
Juan Cespedes53eabb12001-12-10 04:11:39 +0100179 event->proc->breakpoints_enabled = -1;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100180 }
181 }
182 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100183 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100184 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
185 if (child>0) {
186 open_pid(child, 0);
187 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100188 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100189 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100190 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200191 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200192 if (opt_S) {
193 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
194 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100195 continue_process(event->proc->pid);
196}
197
Juan Cespedes21c63a12001-07-07 20:56:56 +0200198static void
199process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100200 struct library_symbol * tmp;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100201 int i,j;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100202
Juan Cespedescac15c32003-01-31 18:58:58 +0100203 debug(2, "event: breakpoint (0x%08x)", event->e_un.brk_addr);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100204 if (event->proc->breakpoint_being_enabled) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100205 /* Reinsert breakpoint */
Juan Cespedes5e01f651998-03-08 22:31:44 +0100206 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
207 event->proc->breakpoint_being_enabled = NULL;
208 return;
209 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200210
Juan Cespedes5916fda2002-02-25 00:19:21 +0100211 for(i=event->proc->callstack_depth-1; i>=0; i--) {
212 if (event->e_un.brk_addr == event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200213#ifdef __powerpc__
214 unsigned long a;
215 unsigned long addr = event->proc->callstack[i].c_un.libfunc->enter_addr;
Juan Cespedescac15c32003-01-31 18:58:58 +0100216 struct breakpoint *sbp = address2bpstruct(event->proc, addr);
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200217 unsigned char break_insn[] = BREAKPOINT_VALUE;
218
219 /*
220 * PPC HACK! (XXX FIXME TODO)
221 * The PLT gets modified during the first call,
222 * so be sure to re-enable the breakpoint.
223 */
224 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, addr);
225
226 if (memcmp(&a, break_insn, 4)) {
227 sbp->enabled--;
228 insert_breakpoint(event->proc, addr);
229 }
230#endif
Juan Cespedes5916fda2002-02-25 00:19:21 +0100231 for(j=event->proc->callstack_depth-1; j>=i; j--) {
232 callstack_pop(event->proc);
233 }
234 event->proc->return_addr = event->e_un.brk_addr;
235 output_right(LT_TOF_FUNCTION, event->proc,
236 event->proc->callstack[i].c_un.libfunc->name);
237 continue_after_breakpoint(event->proc,
238 address2bpstruct(event->proc, event->e_un.brk_addr));
239 return;
240 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100241 }
242
243 tmp = event->proc->list_of_symbols;
244 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200245 if (event->e_un.brk_addr == tmp->enter_addr) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200246 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
247 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100248 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200249 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200250 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100251 return;
252 }
253 tmp = tmp->next;
254 }
255 output_line(event->proc, "breakpointed at 0x%08x (?)",
256 (unsigned)event->e_un.brk_addr);
257 continue_process(event->proc->pid);
258}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200259
Juan Cespedes21c63a12001-07-07 20:56:56 +0200260static void
261callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200262 struct callstack_element * elem;
263
264 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
265 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
266 fprintf(stderr, "Error: call nesting too deep!\n");
267 return;
268 }
269
270 elem = & proc->callstack[proc->callstack_depth];
271 elem->is_syscall = 1;
272 elem->c_un.syscall = sysnum;
273 elem->return_addr = NULL;
274
275 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200276}
277
Juan Cespedes21c63a12001-07-07 20:56:56 +0200278static void
279callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200280 struct callstack_element * elem;
281
282 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
283 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
284 fprintf(stderr, "Error: call nesting too deep!\n");
285 return;
286 }
287
288 elem = & proc->callstack[proc->callstack_depth];
289 elem->is_syscall = 0;
290 elem->c_un.libfunc = sym;
291
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200292 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200293 insert_breakpoint(proc, elem->return_addr);
294
295 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200296}
297
Juan Cespedes21c63a12001-07-07 20:56:56 +0200298static void
299callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200300 struct callstack_element * elem;
301 assert(proc->callstack_depth > 0);
302
303 elem = & proc->callstack[proc->callstack_depth-1];
304 if (!elem->is_syscall) {
305 delete_breakpoint(proc, elem->return_addr);
306 }
307 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200308}