blob: 53012f4965f3888bee1a2bf03dec9ec8fb60fc7b [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
Juan Cespedesf1bfe202002-03-27 00:22:23 +010017#ifdef __powerpc__
18#include <sys/ptrace.h>
19#endif
20
Juan Cespedes5e01f651998-03-08 22:31:44 +010021static void process_signal(struct event * event);
22static void process_exit(struct event * event);
23static void process_exit_signal(struct event * event);
24static void process_syscall(struct event * event);
25static void process_sysret(struct event * event);
26static void process_breakpoint(struct event * event);
Juan Cespedes21c63a12001-07-07 20:56:56 +020027static void remove_proc(struct process * proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010028
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020029static void callstack_push_syscall(struct process * proc, int sysnum);
30static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym);
31static void callstack_pop(struct process * proc);
32
Juan Cespedes21c63a12001-07-07 20:56:56 +020033void
34process_event(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010035 switch (event->thing) {
36 case LT_EV_NONE:
Juan Cespedes5916fda2002-02-25 00:19:21 +010037 if (opt_d>0) {
38 output_line(0, "event: none");
39 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010040 return;
41 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010042 if (opt_d>0) {
43 output_line(0, "event: signal (%d)", event->e_un.signum);
44 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010045 process_signal(event);
46 return;
47 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010048 if (opt_d>0) {
49 output_line(0, "event: exit (%d)", event->e_un.ret_val);
50 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010051 process_exit(event);
52 return;
53 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010054 if (opt_d>0) {
55 output_line(0, "event: exit signal (%d)", event->e_un.signum);
56 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010057 process_exit_signal(event);
58 return;
59 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010060 if (opt_d>0) {
61 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
62 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010063 process_syscall(event);
64 return;
65 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010066 if (opt_d>0) {
67 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
68 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010069 process_sysret(event);
70 return;
71 case LT_EV_BREAKPOINT:
Juan Cespedes5916fda2002-02-25 00:19:21 +010072 if (opt_d>0) {
73 output_line(0, "event: breakpoint");
74 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010075 process_breakpoint(event);
76 return;
77 default:
78 fprintf(stderr, "Error! unknown event?\n");
79 exit(1);
80 }
81}
82
Juan Cespedes21c63a12001-07-07 20:56:56 +020083static char *
84shortsignal(int signum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010085 static char * signalent0[] = {
86 #include "signalent.h"
87 };
88 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
89
Juan Cespedes8cc1b9d2002-03-01 19:54:23 +010090 if (signum<0 || signum>=nsignals0) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010091 return "UNKNOWN_SIGNAL";
92 } else {
93 return signalent0[signum];
94 }
95}
96
Juan Cespedes21c63a12001-07-07 20:56:56 +020097static char *
98sysname(int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010099 static char result[128];
100 static char * syscalent0[] = {
101 #include "syscallent.h"
102 };
103 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
104
105 if (sysnum<0 || sysnum>nsyscals0) {
106 sprintf(result, "SYS_%d", sysnum);
107 return result;
108 } else {
109 sprintf(result, "SYS_%s", syscalent0[sysnum]);
110 return result;
111 }
112}
113
Juan Cespedes21c63a12001-07-07 20:56:56 +0200114static void
115process_signal(struct event * event) {
Juan Cespedes28f60191998-04-12 00:04:39 +0200116 if (exiting && event->e_un.signum == SIGSTOP) {
117 pid_t pid = event->proc->pid;
118 disable_all_breakpoints(event->proc);
119 untrace_pid(pid);
120 remove_proc(event->proc);
121 continue_after_signal(pid, event->e_un.signum);
122 return;
123 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100124 output_line(event->proc, "--- %s (%s) ---",
125 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
126 continue_after_signal(event->proc->pid, event->e_un.signum);
127}
128
Juan Cespedes21c63a12001-07-07 20:56:56 +0200129static void
130process_exit(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100131 output_line(event->proc, "+++ exited (status %d) +++",
132 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100133 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100134}
135
Juan Cespedes21c63a12001-07-07 20:56:56 +0200136static void
137process_exit_signal(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100138 output_line(event->proc, "+++ killed by %s +++",
139 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100140 remove_proc(event->proc);
141}
142
Juan Cespedes21c63a12001-07-07 20:56:56 +0200143static void
144remove_proc(struct process * proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100145 struct process *tmp, *tmp2;
146
Juan Cespedes28f60191998-04-12 00:04:39 +0200147 if (opt_d) {
148 output_line(0,"Removing pid %u\n", proc->pid);
149 }
150
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100151 if (list_of_processes == proc) {
152 tmp = list_of_processes;
153 list_of_processes = list_of_processes->next;
154 free(tmp);
155 return;
156 }
157 tmp = list_of_processes;
158 while(tmp->next) {
159 if (tmp->next==proc) {
160 tmp2 = tmp->next;
161 tmp->next = tmp->next->next;
162 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200163 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100164 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100165 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100166 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100167}
168
Juan Cespedes21c63a12001-07-07 20:56:56 +0200169static void
170process_syscall(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100171 if (opt_S) {
172 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
173 }
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200174 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100175 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100176 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100177 } else if (!event->proc->breakpoints_enabled) {
178 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100179 }
180 continue_process(event->proc->pid);
181}
182
Juan Cespedes21c63a12001-07-07 20:56:56 +0200183static void
184process_sysret(struct event * event) {
Juan Cespedes81690ef1998-03-13 19:31:29 +0100185 if (exec_p(event->e_un.sysnum)) {
186 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200187
Juan Cespedes81690ef1998-03-13 19:31:29 +0100188 event->proc->filename = pid2name(event->proc->pid);
189 event->proc->list_of_symbols = read_elf(event->proc->filename);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100190
191 /* The kernel will stop the process just after an execve()
192 * and we will be able to enable breakpoints again
193 */
Juan Cespedes53eabb12001-12-10 04:11:39 +0100194 event->proc->breakpoints_enabled = -1;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100195 }
196 }
197 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100198 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100199 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
200 if (child>0) {
201 open_pid(child, 0);
202 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100203 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100204 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100205 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200206 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200207 if (opt_S) {
208 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
209 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100210 continue_process(event->proc->pid);
211}
212
Juan Cespedes21c63a12001-07-07 20:56:56 +0200213static void
214process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100215 struct library_symbol * tmp;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100216 int i,j;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100217
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100218 if (opt_d>1) {
219 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
220 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100221 if (event->proc->breakpoint_being_enabled) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100222 /* Reinsert breakpoint */
Juan Cespedes5e01f651998-03-08 22:31:44 +0100223 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
224 event->proc->breakpoint_being_enabled = NULL;
225 return;
226 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200227
Juan Cespedes5916fda2002-02-25 00:19:21 +0100228 for(i=event->proc->callstack_depth-1; i>=0; i--) {
229 if (event->e_un.brk_addr == event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200230#ifdef __powerpc__
231 unsigned long a;
232 unsigned long addr = event->proc->callstack[i].c_un.libfunc->enter_addr;
233 struct breakpoint *sbp = dict_find_entry(event->proc, addr);
234 unsigned char break_insn[] = BREAKPOINT_VALUE;
235
236 /*
237 * PPC HACK! (XXX FIXME TODO)
238 * The PLT gets modified during the first call,
239 * so be sure to re-enable the breakpoint.
240 */
241 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, addr);
242
243 if (memcmp(&a, break_insn, 4)) {
244 sbp->enabled--;
245 insert_breakpoint(event->proc, addr);
246 }
247#endif
Juan Cespedes5916fda2002-02-25 00:19:21 +0100248 for(j=event->proc->callstack_depth-1; j>=i; j--) {
249 callstack_pop(event->proc);
250 }
251 event->proc->return_addr = event->e_un.brk_addr;
252 output_right(LT_TOF_FUNCTION, event->proc,
253 event->proc->callstack[i].c_un.libfunc->name);
254 continue_after_breakpoint(event->proc,
255 address2bpstruct(event->proc, event->e_un.brk_addr));
256 return;
257 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100258 }
259
260 tmp = event->proc->list_of_symbols;
261 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200262 if (event->e_un.brk_addr == tmp->enter_addr) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200263 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
264 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100265 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200266 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200267 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100268 return;
269 }
270 tmp = tmp->next;
271 }
272 output_line(event->proc, "breakpointed at 0x%08x (?)",
273 (unsigned)event->e_un.brk_addr);
274 continue_process(event->proc->pid);
275}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200276
Juan Cespedes21c63a12001-07-07 20:56:56 +0200277static void
278callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200279 struct callstack_element * elem;
280
281 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
282 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
283 fprintf(stderr, "Error: call nesting too deep!\n");
284 return;
285 }
286
287 elem = & proc->callstack[proc->callstack_depth];
288 elem->is_syscall = 1;
289 elem->c_un.syscall = sysnum;
290 elem->return_addr = NULL;
291
292 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200293}
294
Juan Cespedes21c63a12001-07-07 20:56:56 +0200295static void
296callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200297 struct callstack_element * elem;
298
299 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
300 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
301 fprintf(stderr, "Error: call nesting too deep!\n");
302 return;
303 }
304
305 elem = & proc->callstack[proc->callstack_depth];
306 elem->is_syscall = 0;
307 elem->c_un.libfunc = sym;
308
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200309 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200310 insert_breakpoint(proc, elem->return_addr);
311
312 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200313}
314
Juan Cespedes21c63a12001-07-07 20:56:56 +0200315static void
316callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200317 struct callstack_element * elem;
318 assert(proc->callstack_depth > 0);
319
320 elem = & proc->callstack[proc->callstack_depth-1];
321 if (!elem->is_syscall) {
322 delete_breakpoint(proc, elem->return_addr);
323 }
324 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200325}