blob: 91f64a1b71643c7abdbc8b59adf6cf1aae3c54f1 [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 Cespedes5e01f651998-03-08 22:31:44 +010010
11#include "ltrace.h"
12#include "output.h"
13#include "options.h"
Juan Cespedes81690ef1998-03-13 19:31:29 +010014#include "elf.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010015
16static void process_signal(struct event * event);
17static void process_exit(struct event * event);
18static void process_exit_signal(struct event * event);
19static void process_syscall(struct event * event);
20static void process_sysret(struct event * event);
21static void process_breakpoint(struct event * event);
22
23void process_event(struct event * event)
24{
25 switch (event->thing) {
26 case LT_EV_NONE:
27 return;
28 case LT_EV_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010029 if (opt_d>0) {
30 output_line(0, "event: signal (%d)", event->e_un.signum);
31 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010032 process_signal(event);
33 return;
34 case LT_EV_EXIT:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010035 if (opt_d>0) {
36 output_line(0, "event: exit (%d)", event->e_un.ret_val);
37 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010038 process_exit(event);
39 return;
40 case LT_EV_EXIT_SIGNAL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010041 if (opt_d>0) {
42 output_line(0, "event: exit signal (%d)", event->e_un.signum);
43 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010044 process_exit_signal(event);
45 return;
46 case LT_EV_SYSCALL:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010047 if (opt_d>0) {
48 output_line(0, "event: syscall (%d)", event->e_un.sysnum);
49 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010050 process_syscall(event);
51 return;
52 case LT_EV_SYSRET:
Juan Cespedesf0fdae91998-03-11 00:03:00 +010053 if (opt_d>0) {
54 output_line(0, "event: sysret (%d)", event->e_un.sysnum);
55 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010056 process_sysret(event);
57 return;
58 case LT_EV_BREAKPOINT:
59 process_breakpoint(event);
60 return;
61 default:
62 fprintf(stderr, "Error! unknown event?\n");
63 exit(1);
64 }
65}
66
67static char * shortsignal(int signum)
68{
69 static char * signalent0[] = {
70 #include "signalent.h"
71 };
72 int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
73
74 if (signum<0 || signum>nsignals0) {
75 return "UNKNOWN_SIGNAL";
76 } else {
77 return signalent0[signum];
78 }
79}
80
81static char * sysname(int sysnum)
82{
83 static char result[128];
84 static char * syscalent0[] = {
85 #include "syscallent.h"
86 };
87 int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
88
89 if (sysnum<0 || sysnum>nsyscals0) {
90 sprintf(result, "SYS_%d", sysnum);
91 return result;
92 } else {
93 sprintf(result, "SYS_%s", syscalent0[sysnum]);
94 return result;
95 }
96}
97
Juan Cespedes28f60191998-04-12 00:04:39 +020098static void remove_proc(struct process * proc);
99
Juan Cespedes5e01f651998-03-08 22:31:44 +0100100static void process_signal(struct event * event)
101{
Juan Cespedes28f60191998-04-12 00:04:39 +0200102 if (exiting && event->e_un.signum == SIGSTOP) {
103 pid_t pid = event->proc->pid;
104 disable_all_breakpoints(event->proc);
105 untrace_pid(pid);
106 remove_proc(event->proc);
107 continue_after_signal(pid, event->e_un.signum);
108 return;
109 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100110 output_line(event->proc, "--- %s (%s) ---",
111 shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
112 continue_after_signal(event->proc->pid, event->e_un.signum);
113}
114
115static void process_exit(struct event * event)
116{
117 output_line(event->proc, "+++ exited (status %d) +++",
118 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100119 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100120}
121
122static void process_exit_signal(struct event * event)
123{
124 output_line(event->proc, "+++ killed by %s +++",
125 shortsignal(event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100126 remove_proc(event->proc);
127}
128
129static void remove_proc(struct process * proc)
130{
131 struct process *tmp, *tmp2;
132
Juan Cespedes28f60191998-04-12 00:04:39 +0200133 if (opt_d) {
134 output_line(0,"Removing pid %u\n", proc->pid);
135 }
136
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100137 if (list_of_processes == proc) {
138 tmp = list_of_processes;
139 list_of_processes = list_of_processes->next;
140 free(tmp);
141 return;
142 }
143 tmp = list_of_processes;
144 while(tmp->next) {
145 if (tmp->next==proc) {
146 tmp2 = tmp->next;
147 tmp->next = tmp->next->next;
148 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200149 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100150 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100151 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100152 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100153}
154
155static void process_syscall(struct event * event)
156{
157 event->proc->current_syscall = event->e_un.sysnum;
158 if (opt_S) {
159 output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
160 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100161 if (fork_p(event->e_un.sysnum) || exec_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100162 disable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100163 } else if (!event->proc->breakpoints_enabled) {
164 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100165 }
166 continue_process(event->proc->pid);
167}
168
169static void process_sysret(struct event * event)
170{
171 if (opt_S) {
172 output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
173 }
Juan Cespedes81690ef1998-03-13 19:31:29 +0100174 if (exec_p(event->e_un.sysnum)) {
175 if (gimme_arg(LT_TOF_SYSCALL,event->proc,-1)==0) {
176 event->proc->filename = pid2name(event->proc->pid);
177 event->proc->list_of_symbols = read_elf(event->proc->filename);
178 event->proc->breakpoints_enabled = -1;
179 } else {
180 enable_all_breakpoints(event->proc);
Juan Cespedes81690ef1998-03-13 19:31:29 +0100181 }
182 }
183 if (fork_p(event->e_un.sysnum)) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100184 if (opt_f) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100185 pid_t child = gimme_arg(LT_TOF_SYSCALL,event->proc,-1);
186 if (child>0) {
187 open_pid(child, 0);
188 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100189 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100190 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100191 }
192 event->proc->current_syscall = -1;
193 continue_process(event->proc->pid);
194}
195
196static void process_breakpoint(struct event * event)
197{
198 struct library_symbol * tmp;
199
Juan Cespedesf0fdae91998-03-11 00:03:00 +0100200 if (opt_d>1) {
201 output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
202 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100203 if (event->proc->breakpoint_being_enabled) {
204 continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
205 event->proc->breakpoint_being_enabled = NULL;
206 return;
207 }
208 if (event->proc->current_symbol && event->e_un.brk_addr == event->proc->return_value.addr) {
209 output_right(LT_TOF_FUNCTION, event->proc, event->proc->current_symbol->name);
210 continue_after_breakpoint(event->proc, &event->proc->return_value, 1);
211 event->proc->current_symbol = NULL;
212 return;
213 }
214
215 tmp = event->proc->list_of_symbols;
216 while(tmp) {
217 if (event->e_un.brk_addr == tmp->brk.addr) {
218 if (event->proc->current_symbol) {
219 delete_breakpoint(event->proc->pid, &event->proc->return_value);
220 }
221 event->proc->current_symbol = tmp;
222 event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
223 event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
224 output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
225 event->proc->return_value.addr = event->proc->return_addr;
226 insert_breakpoint(event->proc->pid, &event->proc->return_value);
227 continue_after_breakpoint(event->proc, &tmp->brk, 0);
228 return;
229 }
230 tmp = tmp->next;
231 }
232 output_line(event->proc, "breakpointed at 0x%08x (?)",
233 (unsigned)event->e_un.brk_addr);
234 continue_process(event->proc->pid);
235}