blob: 2827bc54548088c7ab2831aadad7c4a075b33e4d [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 }
133 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100134}
135
136static void process_syscall(struct event * event)
137{
138 event->proc->current_syscall = event->e_un.sysnum;
139 if (opt_S) {
140 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
141 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100142 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100143 disable_all_breakpoints(event->proc);
144 if (event->proc->current_symbol) {
145 delete_breakpoint(event->proc->pid, &event->proc->return_value);
146 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100147 } else if (!event->proc->breakpoints_enabled) {
148 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100149 }
150 continue_process(event->proc->pid);
151}
152
153static void process_sysret(struct event * event)
154{
155 if (opt_S) {
156 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
157 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100158 if (exec_p(event->e_un.sysnum)) {
159 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
160 event->proc->filename = pid2name(event->proc->pid);
161 event->proc->list_of_symbols = read_elf(event->proc->filename);
162 event->proc->breakpoints_enabled = -1;
163 } else {
164 enable_all_breakpoints(event->proc);
165 if (event->proc->current_symbol) {
166 insert_breakpoint(event->proc->pid, &event->proc->return_value);
167 }
168 }
169 }
170 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100171 enable_all_breakpoints(event->proc);
172 if (event->proc->current_symbol) {
173 insert_breakpoint(event->proc->pid, &event->proc->return_value);
174 }
175 if (opt_f) {
176 fprintf(stderr, "ERROR: Option `-f' doesn't work yet\n");
177 exit(1);
178 }
179 }
180 event->proc->current_syscall = -1;
181 continue_process(event->proc->pid);
182}
183
184static void process_breakpoint(struct event * event)
185{
186 struct library_symbol * tmp;
187
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100188 if (opt_d>1) {
189 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
190 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100191 if (event->proc->breakpoint_being_enabled) {
192 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
193 event->proc->breakpoint_being_enabled = NULL;
194 return;
195 }
196 if (event->proc->current_symbol && event->e_un.brk_addr == event->proc->return_value.addr) {
197 output_right(LT_TOF_FUNCTION, event->proc, event->proc->current_symbol->name);
198 continue_after_breakpoint(event->proc, &event->proc->return_value, 1);
199 event->proc->current_symbol = NULL;
200 return;
201 }
202
203 tmp = event->proc->list_of_symbols;
204 while(tmp) {
205 if (event->e_un.brk_addr == tmp->brk.addr) {
206 if (event->proc->current_symbol) {
207 delete_breakpoint(event->proc->pid, &event->proc->return_value);
208 }
209 event->proc->current_symbol = tmp;
210 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
211 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
212 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
213 event->proc->return_value.addr = event->proc->return_addr;
214 insert_breakpoint(event->proc->pid, &event->proc->return_value);
215 continue_after_breakpoint(event->proc, &tmp->brk, 0);
216 return;
217 }
218 tmp = tmp->next;
219 }
220 output_line(event->proc, "breakpointed at 0x%08x (?)",
221 (unsigned)event->e_un.brk_addr);
222 continue_process(event->proc->pid);
223}