blob: 079bb615f90105820447d50ee36bfb970896243e [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 Cespedes5b3ffdf2001-07-02 00:52:45 +0200161 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100162 if (opt_S) {
163 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
164 }
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 Cespedes5b3ffdf2001-07-02 00:52:45 +0200181 sym = event->proc->list_of_symbols;
182 while (sym) {
183 insert_breakpoint(event->proc, sym->enter_addr);
184 sym = sym->next;
185 }
186 event->proc->breakpoints_enabled = 1;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100187 }
188 }
189 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100190 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100191 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
192 if (child>0) {
193 open_pid(child, 0);
194 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100195 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100196 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100197 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200198 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200199 if (opt_S) {
200 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
201 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100202 continue_process(event->proc->pid);
203}
204
Juan Cespedes21c63a12001-07-07 20:56:56 +0200205static void
206process_breakpoint(struct event * event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100207 struct library_symbol * tmp;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200208 void * return_addr;
209 struct callstack_element * current_call = event->proc->callstack_depth>0 ?
210 &(event->proc->callstack[event->proc->callstack_depth-1]) : NULL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100211
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100212 if (opt_d>1) {
213 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
214 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100215 if (event->proc->breakpoint_being_enabled) {
216 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
217 event->proc->breakpoint_being_enabled = NULL;
218 return;
219 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200220
221 if (current_call && !current_call->is_syscall && event->e_un.brk_addr == current_call->return_addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200222 return_addr = current_call->return_addr;
223 callstack_pop(event->proc);
Juan Cespedes21c63a12001-07-07 20:56:56 +0200224 output_right(LT_TOF_FUNCTION, event->proc, current_call->c_un.libfunc->name);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200225 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, return_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100226 return;
227 }
228
229 tmp = event->proc->list_of_symbols;
230 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200231 if (event->e_un.brk_addr == tmp->enter_addr) {
232 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100233 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200234 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100235 return;
236 }
237 tmp = tmp->next;
238 }
239 output_line(event->proc, "breakpointed at 0x%08x (?)",
240 (unsigned)event->e_un.brk_addr);
241 continue_process(event->proc->pid);
242}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200243
Juan Cespedes21c63a12001-07-07 20:56:56 +0200244static void
245callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200246 struct callstack_element * elem;
247
248 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
249 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
250 fprintf(stderr, "Error: call nesting too deep!\n");
251 return;
252 }
253
254 elem = & proc->callstack[proc->callstack_depth];
255 elem->is_syscall = 1;
256 elem->c_un.syscall = sysnum;
257 elem->return_addr = NULL;
258
259 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200260}
261
Juan Cespedes21c63a12001-07-07 20:56:56 +0200262static void
263callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200264 struct callstack_element * elem;
265
266 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
267 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
268 fprintf(stderr, "Error: call nesting too deep!\n");
269 return;
270 }
271
272 elem = & proc->callstack[proc->callstack_depth];
273 elem->is_syscall = 0;
274 elem->c_un.libfunc = sym;
275
276 proc->stack_pointer = get_stack_pointer(proc->pid);
Juan Cespedes76040ed2001-07-03 18:37:37 +0200277 proc->return_addr = elem->return_addr = get_return_addr(proc->pid, proc->stack_pointer);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200278 insert_breakpoint(proc, elem->return_addr);
279
280 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200281}
282
Juan Cespedes21c63a12001-07-07 20:56:56 +0200283static void
284callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200285 struct callstack_element * elem;
286 assert(proc->callstack_depth > 0);
287
288 elem = & proc->callstack[proc->callstack_depth-1];
289 if (!elem->is_syscall) {
290 delete_breakpoint(proc, elem->return_addr);
291 }
292 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200293}