blob: f3c5295d1e0c9563e9f9f2803968f630b676adf8 [file] [log] [blame]
Juan Cespedes5e01f651998-03-08 22:31:44 +01001#define _GNU_SOURCE
2#include <stdio.h>
3#include <string.h>
Juan Cespedes1fe93d51998-03-13 00:29:21 +01004#include <stdlib.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +01005
6#include "ltrace.h"
7#include "output.h"
8#include "options.h"
Juan Cespedes81690ef1998-03-13 19:31:29 +01009#include "elf.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010010
11static void process_signal(struct event * event);
12static void process_exit(struct event * event);
13static void process_exit_signal(struct event * event);
14static void process_syscall(struct event * event);
15static void process_sysret(struct event * event);
16static void process_breakpoint(struct event * event);
17
18void process_event(struct event * event)
19{
20 switch (event->thing) {
21 case LT_EV_NONE:
22 return;
23 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010024 if (opt_d>0) {
25 output_line(0, "event: signal (%d)", event->e_un.signum);
26 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010027 process_signal(event);
28 return;
29 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010030 if (opt_d>0) {
31 output_line(0, "event: exit (%d)", event->e_un.ret_val);
32 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010033 process_exit(event);
34 return;
35 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010036 if (opt_d>0) {
37 output_line(0, "event: exit signal (%d)", event->e_un.signum);
38 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010039 process_exit_signal(event);
40 return;
41 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010042 if (opt_d>0) {
43 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
44 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010045 process_syscall(event);
46 return;
47 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010048 if (opt_d>0) {
49 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
50 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010051 process_sysret(event);
52 return;
53 case LT_EV_BREAKPOINT:
54 process_breakpoint(event);
55 return;
56 default:
57 fprintf(stderr, "Error! unknown event?\n");
58 exit(1);
59 }
60}
61
62static char * shortsignal(int signum)
63{
64 static char * signalent0[] = {
65 #include "signalent.h"
66 };
67 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
68
69 if (signum<0 || signum>nsignals0) {
70 return "UNKNOWN_SIGNAL";
71 } else {
72 return signalent0[signum];
73 }
74}
75
76static char * sysname(int sysnum)
77{
78 static char result[128];
79 static char * syscalent0[] = {
80 #include "syscallent.h"
81 };
82 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
83
84 if (sysnum<0 || sysnum>nsyscals0) {
85 sprintf(result, "SYS_%d", sysnum);
86 return result;
87 } else {
88 sprintf(result, "SYS_%s", syscalent0[sysnum]);
89 return result;
90 }
91}
92
93static void process_signal(struct event * event)
94{
95 output_line(event->proc, "--- %s (%s) ---",
96 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
97 continue_after_signal(event->proc->pid, event->e_un.signum);
98}
99
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100100static void remove_proc(struct process * proc);
101
Juan Cespedes5e01f651998-03-08 22:31:44 +0100102static void process_exit(struct event * event)
103{
104 output_line(event->proc, "+++ exited (status %d) +++",
105 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100106 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100107}
108
109static void process_exit_signal(struct event * event)
110{
111 output_line(event->proc, "+++ killed by %s +++",
112 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100113 remove_proc(event->proc);
114}
115
116static void remove_proc(struct process * proc)
117{
118 struct process *tmp, *tmp2;
119
120 if (list_of_processes == proc) {
121 tmp = list_of_processes;
122 list_of_processes = list_of_processes->next;
123 free(tmp);
124 return;
125 }
126 tmp = list_of_processes;
127 while(tmp->next) {
128 if (tmp->next==proc) {
129 tmp2 = tmp->next;
130 tmp->next = tmp->next->next;
131 free(tmp2);
132 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100133 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100134 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100135}
136
137static void process_syscall(struct event * event)
138{
139 event->proc->current_syscall = event->e_un.sysnum;
140 if (opt_S) {
141 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
142 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100143 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100144 disable_all_breakpoints(event->proc);
145 if (event->proc->current_symbol) {
146 delete_breakpoint(event->proc->pid, &event->proc->return_value);
147 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100148 } else if (!event->proc->breakpoints_enabled) {
149 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100150 }
151 continue_process(event->proc->pid);
152}
153
154static void process_sysret(struct event * event)
155{
156 if (opt_S) {
157 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
158 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100159 if (exec_p(event->e_un.sysnum)) {
160 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
161 event->proc->filename = pid2name(event->proc->pid);
162 event->proc->list_of_symbols = read_elf(event->proc->filename);
163 event->proc->breakpoints_enabled = -1;
164 } else {
165 enable_all_breakpoints(event->proc);
166 if (event->proc->current_symbol) {
167 insert_breakpoint(event->proc->pid, &event->proc->return_value);
168 }
169 }
170 }
171 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100172 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100173 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
174 if (child>0) {
175 open_pid(child, 0);
176 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100177 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100178 enable_all_breakpoints(event->proc);
179 if (event->proc->current_symbol) {
180 insert_breakpoint(event->proc->pid, &event->proc->return_value);
181 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100182 }
183 event->proc->current_syscall = -1;
184 continue_process(event->proc->pid);
185}
186
187static void process_breakpoint(struct event * event)
188{
189 struct library_symbol * tmp;
190
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100191 if (opt_d>1) {
192 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
193 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100194 if (event->proc->breakpoint_being_enabled) {
195 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
196 event->proc->breakpoint_being_enabled = NULL;
197 return;
198 }
199 if (event->proc->current_symbol && event->e_un.brk_addr == event->proc->return_value.addr) {
200 output_right(LT_TOF_FUNCTION, event->proc, event->proc->current_symbol->name);
201 continue_after_breakpoint(event->proc, &event->proc->return_value, 1);
202 event->proc->current_symbol = NULL;
203 return;
204 }
205
206 tmp = event->proc->list_of_symbols;
207 while(tmp) {
208 if (event->e_un.brk_addr == tmp->brk.addr) {
209 if (event->proc->current_symbol) {
210 delete_breakpoint(event->proc->pid, &event->proc->return_value);
211 }
212 event->proc->current_symbol = tmp;
213 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
214 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
215 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
216 event->proc->return_value.addr = event->proc->return_addr;
217 insert_breakpoint(event->proc->pid, &event->proc->return_value);
218 continue_after_breakpoint(event->proc, &tmp->brk, 0);
219 return;
220 }
221 tmp = tmp->next;
222 }
223 output_line(event->proc, "breakpointed at 0x%08x (?)",
224 (unsigned)event->e_un.brk_addr);
225 continue_process(event->proc->pid);
226}