blob: 084724140b7ac1588e5c4e4ebf79c8448f683c4e [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) {
230 for(j=event->proc->callstack_depth-1; j>=i; j--) {
231 callstack_pop(event->proc);
232 }
233 event->proc->return_addr = event->e_un.brk_addr;
234 output_right(LT_TOF_FUNCTION, event->proc,
235 event->proc->callstack[i].c_un.libfunc->name);
236 continue_after_breakpoint(event->proc,
237 address2bpstruct(event->proc, event->e_un.brk_addr));
238 return;
239 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100240 }
241
242 tmp = event->proc->list_of_symbols;
243 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200244 if (event->e_un.brk_addr == tmp->enter_addr) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200245 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
246 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100247 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200248 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200249 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100250 return;
251 }
252 tmp = tmp->next;
253 }
254 output_line(event->proc, "breakpointed at 0x%08x (?)",
255 (unsigned)event->e_un.brk_addr);
256 continue_process(event->proc->pid);
257}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200258
Juan Cespedes21c63a12001-07-07 20:56:56 +0200259static void
260callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200261 struct callstack_element * elem;
262
263 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
264 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
265 fprintf(stderr, "Error: call nesting too deep!\n");
266 return;
267 }
268
269 elem = & proc->callstack[proc->callstack_depth];
270 elem->is_syscall = 1;
271 elem->c_un.syscall = sysnum;
272 elem->return_addr = NULL;
273
274 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200275}
276
Juan Cespedes21c63a12001-07-07 20:56:56 +0200277static void
278callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
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 = 0;
289 elem->c_un.libfunc = sym;
290
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200291 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200292 insert_breakpoint(proc, elem->return_addr);
293
294 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200295}
296
Juan Cespedes21c63a12001-07-07 20:56:56 +0200297static void
298callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200299 struct callstack_element * elem;
300 assert(proc->callstack_depth > 0);
301
302 elem = & proc->callstack[proc->callstack_depth-1];
303 if (!elem->is_syscall) {
304 delete_breakpoint(proc, elem->return_addr);
305 }
306 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200307}