blob: 9c95634f4f8c50e8858242b6487257a5b820cba5 [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 Cespedes7186e2a2003-01-31 19:56:34 +0100160 if (fork_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 (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100171 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100172 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
173 if (child>0) {
174 open_pid(child, 0);
175 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100176 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100177 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100178 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200179 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200180 if (opt_S) {
181 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
182 }
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100183 if (exec_p(event->e_un.sysnum)) {
184 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
185 event->proc->filename = pid2name(event->proc->pid);
186 breakpoints_init(event->proc);
187 }
188 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100189 continue_process(event->proc->pid);
190}
191
Juan Cespedes21c63a12001-07-07 20:56:56 +0200192static void
193process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100194 struct library_symbol * tmp;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100195 int i,j;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100196
Juan Cespedescac15c32003-01-31 18:58:58 +0100197 debug(2, "event: breakpoint (0x%08x)", event->e_un.brk_addr);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100198 if (event->proc->breakpoint_being_enabled) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100199 /* Reinsert breakpoint */
Juan Cespedes5e01f651998-03-08 22:31:44 +0100200 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
201 event->proc->breakpoint_being_enabled = NULL;
202 return;
203 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200204
Juan Cespedes5916fda2002-02-25 00:19:21 +0100205 for(i=event->proc->callstack_depth-1; i>=0; i--) {
206 if (event->e_un.brk_addr == event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200207#ifdef __powerpc__
208 unsigned long a;
209 unsigned long addr = event->proc->callstack[i].c_un.libfunc->enter_addr;
Juan Cespedescac15c32003-01-31 18:58:58 +0100210 struct breakpoint *sbp = address2bpstruct(event->proc, addr);
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200211 unsigned char break_insn[] = BREAKPOINT_VALUE;
212
213 /*
214 * PPC HACK! (XXX FIXME TODO)
215 * The PLT gets modified during the first call,
216 * so be sure to re-enable the breakpoint.
217 */
218 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, addr);
219
220 if (memcmp(&a, break_insn, 4)) {
221 sbp->enabled--;
222 insert_breakpoint(event->proc, addr);
223 }
224#endif
Juan Cespedes5916fda2002-02-25 00:19:21 +0100225 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}