blob: 8b718661ba03d61e0310858701b9f835ffd59dbc [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);
23
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020024static void callstack_push_syscall(struct process * proc, int sysnum);
25static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym);
26static void callstack_pop(struct process * proc);
27
Juan Cespedes5e01f651998-03-08 22:31:44 +010028void process_event(struct event * event)
29{
30 switch (event->thing) {
31 case LT_EV_NONE:
32 return;
33 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010034 if (opt_d>0) {
35 output_line(0, "event: signal (%d)", event->e_un.signum);
36 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010037 process_signal(event);
38 return;
39 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010040 if (opt_d>0) {
41 output_line(0, "event: exit (%d)", event->e_un.ret_val);
42 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010043 process_exit(event);
44 return;
45 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010046 if (opt_d>0) {
47 output_line(0, "event: exit signal (%d)", event->e_un.signum);
48 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010049 process_exit_signal(event);
50 return;
51 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010052 if (opt_d>0) {
53 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
54 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010055 process_syscall(event);
56 return;
57 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010058 if (opt_d>0) {
59 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
60 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010061 process_sysret(event);
62 return;
63 case LT_EV_BREAKPOINT:
64 process_breakpoint(event);
65 return;
66 default:
67 fprintf(stderr, "Error! unknown event?\n");
68 exit(1);
69 }
70}
71
72static char * shortsignal(int signum)
73{
74 static char * signalent0[] = {
75 #include "signalent.h"
76 };
77 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
78
79 if (signum<0 || signum>nsignals0) {
80 return "UNKNOWN_SIGNAL";
81 } else {
82 return signalent0[signum];
83 }
84}
85
86static char * sysname(int sysnum)
87{
88 static char result[128];
89 static char * syscalent0[] = {
90 #include "syscallent.h"
91 };
92 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
93
94 if (sysnum<0 || sysnum>nsyscals0) {
95 sprintf(result, "SYS_%d", sysnum);
96 return result;
97 } else {
98 sprintf(result, "SYS_%s", syscalent0[sysnum]);
99 return result;
100 }
101}
102
Juan Cespedes28f60191998-04-12 00:04:39 +0200103static void remove_proc(struct process * proc);
104
Juan Cespedes5e01f651998-03-08 22:31:44 +0100105static void process_signal(struct event * event)
106{
Juan Cespedes28f60191998-04-12 00:04:39 +0200107 if (exiting && event->e_un.signum == SIGSTOP) {
108 pid_t pid = event->proc->pid;
109 disable_all_breakpoints(event->proc);
110 untrace_pid(pid);
111 remove_proc(event->proc);
112 continue_after_signal(pid, event->e_un.signum);
113 return;
114 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100115 output_line(event->proc, "--- %s (%s) ---",
116 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
117 continue_after_signal(event->proc->pid, event->e_un.signum);
118}
119
120static void process_exit(struct event * event)
121{
122 output_line(event->proc, "+++ exited (status %d) +++",
123 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100124 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100125}
126
127static void process_exit_signal(struct event * event)
128{
129 output_line(event->proc, "+++ killed by %s +++",
130 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100131 remove_proc(event->proc);
132}
133
134static void remove_proc(struct process * proc)
135{
136 struct process *tmp, *tmp2;
137
Juan Cespedes28f60191998-04-12 00:04:39 +0200138 if (opt_d) {
139 output_line(0,"Removing pid %u\n", proc->pid);
140 }
141
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100142 if (list_of_processes == proc) {
143 tmp = list_of_processes;
144 list_of_processes = list_of_processes->next;
145 free(tmp);
146 return;
147 }
148 tmp = list_of_processes;
149 while(tmp->next) {
150 if (tmp->next==proc) {
151 tmp2 = tmp->next;
152 tmp->next = tmp->next->next;
153 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200154 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100155 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100156 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100157 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100158}
159
160static void process_syscall(struct event * event)
161{
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200162 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100163 if (opt_S) {
164 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
165 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100166 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100167 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100168 } else if (!event->proc->breakpoints_enabled) {
169 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100170 }
171 continue_process(event->proc->pid);
172}
173
174static void process_sysret(struct event * event)
175{
176 if (opt_S) {
177 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
178 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100179 if (exec_p(event->e_un.sysnum)) {
180 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200181 struct library_symbol * sym;
182
Juan Cespedes81690ef1998-03-13 19:31:29 +0100183 event->proc->filename = pid2name(event->proc->pid);
184 event->proc->list_of_symbols = read_elf(event->proc->filename);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200185 sym = event->proc->list_of_symbols;
186 while (sym) {
187 insert_breakpoint(event->proc, sym->enter_addr);
188 sym = sym->next;
189 }
190 event->proc->breakpoints_enabled = 1;
Juan Cespedes81690ef1998-03-13 19:31:29 +0100191 }
192 }
193 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100194 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100195 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
196 if (child>0) {
197 open_pid(child, 0);
198 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100199 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100200 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100201 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200202 callstack_pop(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100203 continue_process(event->proc->pid);
204}
205
206static void process_breakpoint(struct event * event)
207{
208 struct library_symbol * tmp;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200209 void * return_addr;
210 struct callstack_element * current_call = event->proc->callstack_depth>0 ?
211 &(event->proc->callstack[event->proc->callstack_depth-1]) : NULL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100212
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100213 if (opt_d>1) {
214 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
215 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100216 if (event->proc->breakpoint_being_enabled) {
217 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
218 event->proc->breakpoint_being_enabled = NULL;
219 return;
220 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200221
222 if (current_call && !current_call->is_syscall && event->e_un.brk_addr == current_call->return_addr) {
223 output_right(LT_TOF_FUNCTION, event->proc, current_call->c_un.libfunc->name);
224 return_addr = current_call->return_addr;
225 callstack_pop(event->proc);
226 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, return_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100227 return;
228 }
229
230 tmp = event->proc->list_of_symbols;
231 while(tmp) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200232 if (event->e_un.brk_addr == tmp->enter_addr) {
233 callstack_push_symfunc(event->proc, tmp);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100234 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200235 continue_after_breakpoint(event->proc, address2bpstruct(event->proc, tmp->enter_addr));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100236 return;
237 }
238 tmp = tmp->next;
239 }
240 output_line(event->proc, "breakpointed at 0x%08x (?)",
241 (unsigned)event->e_un.brk_addr);
242 continue_process(event->proc->pid);
243}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200244
245static void callstack_push_syscall(struct process * proc, int sysnum)
246{
247 struct callstack_element * elem;
248
249 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
250 if (proc->callstack_depth == MAX_CALLDEPTH-1) {
251 fprintf(stderr, "Error: call nesting too deep!\n");
252 return;
253 }
254
255 elem = & proc->callstack[proc->callstack_depth];
256 elem->is_syscall = 1;
257 elem->c_un.syscall = sysnum;
258 elem->return_addr = NULL;
259
260 proc->callstack_depth++;
261 output_increase_indent();
262}
263
264static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym)
265{
266 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
278 proc->stack_pointer = get_stack_pointer(proc->pid);
279 elem->return_addr = get_return_addr(proc->pid, proc->stack_pointer);
280 insert_breakpoint(proc, elem->return_addr);
281
282 proc->callstack_depth++;
283 output_increase_indent();
284}
285
286static void callstack_pop(struct process * proc)
287{
288 struct callstack_element * elem;
289 assert(proc->callstack_depth > 0);
290
291 elem = & proc->callstack[proc->callstack_depth-1];
292 if (!elem->is_syscall) {
293 delete_breakpoint(proc, elem->return_addr);
294 }
295 proc->callstack_depth--;
296 output_decrease_indent();
297}