blob: 5dfad00f849aea299e35fa9e5f8305e4664a9dd9 [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 Cespedes5e01f651998-03-08 22:31:44 +0100161 if (opt_S) {
162 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
163 }
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200164 callstack_push_syscall(event->proc, event->e_un.sysnum);
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) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200232 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
233 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100234 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200235 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200236 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100237 return;
238 }
239 tmp = tmp->next;
240 }
241 output_line(event->proc, "breakpointed at 0x%08x (?)",
242 (unsigned)event->e_un.brk_addr);
243 continue_process(event->proc->pid);
244}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200245
Juan Cespedes21c63a12001-07-07 20:56:56 +0200246static void
247callstack_push_syscall(struct process * proc, int sysnum) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200248 struct callstack_element * elem;
249
250 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
251 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
252 fprintf(stderr, "Error: call nesting too deep!\n");
253 return;
254 }
255
256 elem = & proc->callstack[proc->callstack_depth];
257 elem->is_syscall = 1;
258 elem->c_un.syscall = sysnum;
259 elem->return_addr = NULL;
260
261 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200262}
263
Juan Cespedes21c63a12001-07-07 20:56:56 +0200264static void
265callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200266 struct callstack_element * elem;
267
268 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
269 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
270 fprintf(stderr, "Error: call nesting too deep!\n");
271 return;
272 }
273
274 elem = & proc->callstack[proc->callstack_depth];
275 elem->is_syscall = 0;
276 elem->c_un.libfunc = sym;
277
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200278 elem->return_addr = proc->return_addr;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200279 insert_breakpoint(proc, elem->return_addr);
280
281 proc->callstack_depth++;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200282}
283
Juan Cespedes21c63a12001-07-07 20:56:56 +0200284static void
285callstack_pop(struct process * proc) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200286 struct callstack_element * elem;
287 assert(proc->callstack_depth > 0);
288
289 elem = & proc->callstack[proc->callstack_depth-1];
290 if (!elem->is_syscall) {
291 delete_breakpoint(proc, elem->return_addr);
292 }
293 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200294}