blob: 48b99458449a03804231d2ca1a39f1ac99110ae6 [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 Cespedesd65efa32003-02-03 00:22:30 +010011#include <sys/time.h>
Juan Cespedes5e01f651998-03-08 22:31:44 +010012
Juan Cespedesf7281232009-06-25 16:11:21 +020013#include "common.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010014
Juan Cespedesf1bfe202002-03-27 00:22:23 +010015#ifdef __powerpc__
16#include <sys/ptrace.h>
17#endif
18
Juan Cespedes03192f82009-07-03 10:16:22 +020019static void handle_signal(Event *event);
20static void handle_exit(Event *event);
21static void handle_exit_signal(Event *event);
22static void handle_syscall(Event *event);
23static void handle_arch_syscall(Event *event);
24static void handle_sysret(Event *event);
25static void handle_arch_sysret(Event *event);
26static void handle_clone(Event *event);
27static void handle_exec(Event *event);
28static void handle_breakpoint(Event *event);
29static void handle_new(Event *event);
Juan Cespedesa8909f72009-04-28 20:02:41 +020030static void remove_proc(Process *proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010031
Juan Cespedesa8909f72009-04-28 20:02:41 +020032static void callstack_push_syscall(Process *proc, int sysnum);
33static void callstack_push_symfunc(Process *proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +010034 struct library_symbol *sym);
Juan Cespedesa8909f72009-04-28 20:02:41 +020035static void callstack_pop(Process *proc);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020036
Juan Cespedes61da3372009-07-03 11:55:44 +020037static char * shortsignal(Process *proc, int signum);
38static char * sysname(Process *proc, int sysnum);
39static char * arch_sysname(Process *proc, int sysnum);
40
41void
42handle_event(Event *event) {
43 debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type);
44 switch (event->type) {
45 case EVENT_NONE:
46 debug(1, "event: none");
47 return;
48 case EVENT_SIGNAL:
49 debug(1, "event: signal (%s [%d])",
50 shortsignal(event->proc, event->e_un.signum),
51 event->e_un.signum);
52 handle_signal(event);
53 return;
54 case EVENT_EXIT:
55 debug(1, "event: exit (%d)", event->e_un.ret_val);
56 handle_exit(event);
57 return;
58 case EVENT_EXIT_SIGNAL:
59 debug(1, "event: exit signal (%s [%d])",
60 shortsignal(event->proc, event->e_un.signum),
61 event->e_un.signum);
62 handle_exit_signal(event);
63 return;
64 case EVENT_SYSCALL:
65 debug(1, "event: syscall (%s [%d])",
66 sysname(event->proc, event->e_un.sysnum),
67 event->e_un.sysnum);
68 handle_syscall(event);
69 return;
70 case EVENT_SYSRET:
71 debug(1, "event: sysret (%s [%d])",
72 sysname(event->proc, event->e_un.sysnum),
73 event->e_un.sysnum);
74 handle_sysret(event);
75 return;
76 case EVENT_ARCH_SYSCALL:
77 debug(1, "event: arch_syscall (%s [%d])",
78 arch_sysname(event->proc, event->e_un.sysnum),
79 event->e_un.sysnum);
80 handle_arch_syscall(event);
81 return;
82 case EVENT_ARCH_SYSRET:
83 debug(1, "event: arch_sysret (%s [%d])",
84 arch_sysname(event->proc, event->e_un.sysnum),
85 event->e_un.sysnum);
86 handle_arch_sysret(event);
87 return;
88 case EVENT_CLONE:
89 debug(1, "event: clone (%u)", event->e_un.newpid);
90 handle_clone(event);
91 return;
92 case EVENT_EXEC:
93 debug(1, "event: exec()");
94 handle_exec(event);
95 return;
96 case EVENT_BREAKPOINT:
97 debug(1, "event: breakpoint");
98 handle_breakpoint(event);
99 return;
100 case EVENT_NEW:
101 debug(1, "event: new process");
102 handle_new(event);
103 return;
104 default:
105 fprintf(stderr, "Error! unknown event?\n");
106 exit(1);
107 }
108}
109
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200110/* TODO */
Juan Cespedes61da3372009-07-03 11:55:44 +0200111static void *
112address_clone(void * addr) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200113 debug(DEBUG_FUNCTION, "address_clone(%p)", addr);
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200114 return addr;
115}
116
Juan Cespedes61da3372009-07-03 11:55:44 +0200117static void *
118breakpoint_clone(void * bp) {
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200119 Breakpoint * b;
Juan Cespedescd8976d2009-05-14 13:47:58 +0200120 debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200121 b = malloc(sizeof(Breakpoint));
122 if (!b) {
123 perror("malloc()");
124 exit(1);
125 }
126 memcpy(b, bp, sizeof(Breakpoint));
127 return b;
128}
129
130typedef struct Pending_New Pending_New;
131struct Pending_New {
132 pid_t pid;
133 Pending_New * next;
134};
135static Pending_New * pending_news = NULL;
136
137static int
138pending_new(pid_t pid) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200139 Pending_New * p;
140
141 debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
142
143 p = pending_news;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200144 while (p) {
145 if (p->pid == pid) {
146 return 1;
147 }
148 p = p->next;
149 }
150 return 0;
151}
152
153static void
154pending_new_insert(pid_t pid) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200155 Pending_New * p;
156
157 debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
158
159 p = malloc(sizeof(Pending_New));
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200160 if (!p) {
161 perror("malloc()");
162 exit(1);
163 }
164 p->pid = pid;
165 p->next = pending_news;
166 pending_news = p;
167}
168
169static void
170pending_new_remove(pid_t pid) {
171 Pending_New *p, *pred;
172
Juan Cespedescd8976d2009-05-14 13:47:58 +0200173 debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
174
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200175 p = pending_news;
176 if (p->pid == pid) {
177 pending_news = p->next;
178 free(p);
179 } else {
180 while (p) {
181 if (p->pid == pid) {
182 pred->next = p->next;
183 free(p);
184 }
185 pred = p;
186 p = p->next;
187 }
188 }
189}
190
191static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200192handle_clone(Event * event) {
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200193 Process *p;
194
Juan Cespedes03192f82009-07-03 10:16:22 +0200195 debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200196
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200197 p = malloc(sizeof(Process));
198 if (!p) {
199 perror("malloc()");
200 exit(1);
201 }
202 memcpy(p, event->proc, sizeof(Process));
203 p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone);
204 p->pid = event->e_un.newpid;
Juan Cespedes2721e6a2009-05-21 15:15:40 +0200205 p->parent = event->proc;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200206
207 if (pending_new(p->pid)) {
208 pending_new_remove(p->pid);
209 if (p->breakpoint_being_enabled) {
210 enable_breakpoint(p->pid, p->breakpoint_being_enabled);
211 p->breakpoint_being_enabled = NULL;
212 }
Juan Cespedes5c682042009-05-21 15:59:56 +0200213 if (event->proc->state == STATE_ATTACHED && options.follow) {
214 p->state = STATE_ATTACHED;
215 } else {
216 p->state = STATE_IGNORED;
217 }
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200218 continue_process(p->pid);
219 p->next = list_of_processes;
220 list_of_processes = p;
221 } else {
222 p->state = STATE_BEING_CREATED;
Juan Cespedes2721e6a2009-05-21 15:15:40 +0200223 p->next = list_of_processes;
224 list_of_processes = p;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200225 }
Juan Cespedes2721e6a2009-05-21 15:15:40 +0200226 continue_process(event->proc->pid);
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200227}
228
229static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200230handle_new(Event * event) {
Juan Cespedescd8976d2009-05-14 13:47:58 +0200231 Process * proc;
232
Juan Cespedes03192f82009-07-03 10:16:22 +0200233 debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
Juan Cespedescd8976d2009-05-14 13:47:58 +0200234
235 proc = pid2proc(event->e_un.newpid);
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200236 if (!proc) {
237 pending_new_insert(event->e_un.newpid);
238 } else {
239 assert(proc->state == STATE_BEING_CREATED);
240 if (proc->breakpoint_being_enabled) {
241 enable_breakpoint(proc->pid, proc->breakpoint_being_enabled);
242 proc->breakpoint_being_enabled = NULL;
243 }
Juan Cespedes30439b42009-05-22 19:03:09 +0200244 if (options.follow) {
Juan Cespedes5c682042009-05-21 15:59:56 +0200245 proc->state = STATE_ATTACHED;
246 } else {
247 proc->state = STATE_IGNORED;
248 }
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200249 continue_process(proc->pid);
250 }
251}
252
Juan Cespedesf1350522008-12-16 18:19:58 +0100253static char *
Juan Cespedesa8909f72009-04-28 20:02:41 +0200254shortsignal(Process *proc, int signum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100255 static char *signalent0[] = {
256#include "signalent.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +0100257 };
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100258 static char *signalent1[] = {
259#include "signalent1.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +0100260 };
261 static char **signalents[] = { signalent0, signalent1 };
262 int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100263 sizeof signalent1 / sizeof signalent1[0]
264 };
Juan Cespedes5e01f651998-03-08 22:31:44 +0100265
Juan Cespedescd8976d2009-05-14 13:47:58 +0200266 debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
267
Ian Wienand9a2ad352006-02-20 22:44:45 +0100268 if (proc->personality > sizeof signalents / sizeof signalents[0])
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100269 abort();
Ian Wienand9a2ad352006-02-20 22:44:45 +0100270 if (signum < 0 || signum >= nsignals[proc->personality]) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100271 return "UNKNOWN_SIGNAL";
272 } else {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100273 return signalents[proc->personality][signum];
Juan Cespedes5e01f651998-03-08 22:31:44 +0100274 }
275}
276
Juan Cespedesf1350522008-12-16 18:19:58 +0100277static char *
Juan Cespedesa8909f72009-04-28 20:02:41 +0200278sysname(Process *proc, int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100279 static char result[128];
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100280 static char *syscalent0[] = {
281#include "syscallent.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +0100282 };
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100283 static char *syscalent1[] = {
284#include "syscallent1.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +0100285 };
286 static char **syscalents[] = { syscalent0, syscalent1 };
287 int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100288 sizeof syscalent1 / sizeof syscalent1[0]
289 };
Juan Cespedes5e01f651998-03-08 22:31:44 +0100290
Juan Cespedescd8976d2009-05-14 13:47:58 +0200291 debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
292
Ian Wienand9a2ad352006-02-20 22:44:45 +0100293 if (proc->personality > sizeof syscalents / sizeof syscalents[0])
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100294 abort();
Ian Wienand9a2ad352006-02-20 22:44:45 +0100295 if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100296 sprintf(result, "SYS_%d", sysnum);
297 return result;
298 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100299 sprintf(result, "SYS_%s",
300 syscalents[proc->personality][sysnum]);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100301 return result;
302 }
303}
304
Juan Cespedesf1350522008-12-16 18:19:58 +0100305static char *
Juan Cespedesa8909f72009-04-28 20:02:41 +0200306arch_sysname(Process *proc, int sysnum) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100307 static char result[128];
308 static char *arch_syscalent[] = {
309#include "arch_syscallent.h"
310 };
311 int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
312
Juan Cespedescd8976d2009-05-14 13:47:58 +0200313 debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
314
Juan Cespedes63184be2008-12-10 13:30:12 +0100315 if (sysnum < 0 || sysnum >= nsyscals) {
316 sprintf(result, "ARCH_%d", sysnum);
317 return result;
318 } else {
319 sprintf(result, "ARCH_%s",
320 arch_syscalent[sysnum]);
321 return result;
322 }
323}
324
Juan Cespedesf1350522008-12-16 18:19:58 +0100325static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200326handle_signal(Event *event) {
327 debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
Juan Cespedes28f60191998-04-12 00:04:39 +0200328 if (exiting && event->e_un.signum == SIGSTOP) {
329 pid_t pid = event->proc->pid;
330 disable_all_breakpoints(event->proc);
331 untrace_pid(pid);
332 remove_proc(event->proc);
Juan Cespedes28f60191998-04-12 00:04:39 +0200333 return;
334 }
Juan Cespedes5c682042009-05-21 15:59:56 +0200335 if (event->proc->state != STATE_IGNORED) {
336 output_line(event->proc, "--- %s (%s) ---",
337 shortsignal(event->proc, event->e_un.signum),
338 strsignal(event->e_un.signum));
339 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100340 continue_after_signal(event->proc->pid, event->e_un.signum);
341}
342
Juan Cespedesf1350522008-12-16 18:19:58 +0100343static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200344handle_exit(Event *event) {
345 debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
Juan Cespedes5c682042009-05-21 15:59:56 +0200346 if (event->proc->state != STATE_IGNORED) {
347 output_line(event->proc, "+++ exited (status %d) +++",
348 event->e_un.ret_val);
349 }
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100350 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100351}
352
Juan Cespedesf1350522008-12-16 18:19:58 +0100353static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200354handle_exit_signal(Event *event) {
355 debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
Juan Cespedes5c682042009-05-21 15:59:56 +0200356 if (event->proc->state != STATE_IGNORED) {
357 output_line(event->proc, "+++ killed by %s +++",
358 shortsignal(event->proc, event->e_un.signum));
359 }
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100360 remove_proc(event->proc);
361}
362
Juan Cespedesf1350522008-12-16 18:19:58 +0100363static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200364remove_proc(Process *proc) {
365 Process *tmp, *tmp2;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100366
Juan Cespedescd8976d2009-05-14 13:47:58 +0200367 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
Juan Cespedes28f60191998-04-12 00:04:39 +0200368
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100369 if (list_of_processes == proc) {
370 tmp = list_of_processes;
371 list_of_processes = list_of_processes->next;
372 free(tmp);
373 return;
374 }
375 tmp = list_of_processes;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100376 while (tmp->next) {
377 if (tmp->next == proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100378 tmp2 = tmp->next;
379 tmp->next = tmp->next->next;
380 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200381 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100382 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100383 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100384 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100385}
386
Juan Cespedesf1350522008-12-16 18:19:58 +0100387static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200388handle_syscall(Event *event) {
389 debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
Juan Cespedes5c682042009-05-21 15:59:56 +0200390 if (event->proc->state != STATE_IGNORED) {
391 if (options.syscalls) {
392 output_left(LT_TOF_SYSCALL, event->proc,
393 sysname(event->proc, event->e_un.sysnum));
394 }
395 if (event->proc->breakpoints_enabled == 0) {
396 enable_all_breakpoints(event->proc);
397 }
398 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100399 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100400 continue_process(event->proc->pid);
401}
402
Juan Cespedesf1350522008-12-16 18:19:58 +0100403static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200404handle_exec(Event * event) {
Juan Cespedese0660df2009-05-21 18:14:39 +0200405 Process * proc = event->proc;
406 pid_t saved_pid;
407
Juan Cespedes03192f82009-07-03 10:16:22 +0200408 debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
Juan Cespedese0660df2009-05-21 18:14:39 +0200409 if (proc->state == STATE_IGNORED) {
410 untrace_pid(proc->pid);
411 remove_proc(proc);
412 return;
Juan Cespedes5c682042009-05-21 15:59:56 +0200413 }
Juan Cespedese0660df2009-05-21 18:14:39 +0200414 output_line(proc, "--- Called exec() ---");
415 proc->mask_32bit = 0;
416 proc->personality = 0;
417 proc->arch_ptr = NULL;
418 free(proc->filename);
419 proc->filename = pid2name(proc->pid);
420 saved_pid = proc->pid;
421 proc->pid = 0;
422 breakpoints_init(proc);
423 proc->pid = saved_pid;
424 proc->callstack_depth = 0;
425 continue_process(proc->pid);
Juan Cespedes1e583132009-04-07 18:17:11 +0200426}
427
428static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200429handle_arch_syscall(Event *event) {
430 debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
Juan Cespedes5c682042009-05-21 15:59:56 +0200431 if (event->proc->state != STATE_IGNORED) {
432 if (options.syscalls) {
433 output_left(LT_TOF_SYSCALL, event->proc,
434 arch_sysname(event->proc, event->e_un.sysnum));
435 }
436 if (event->proc->breakpoints_enabled == 0) {
437 enable_all_breakpoints(event->proc);
438 }
439 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
Juan Cespedes63184be2008-12-10 13:30:12 +0100440 }
Juan Cespedes63184be2008-12-10 13:30:12 +0100441 continue_process(event->proc->pid);
442}
443
Juan Cespedesd65efa32003-02-03 00:22:30 +0100444struct timeval current_time_spent;
445
Juan Cespedesf1350522008-12-16 18:19:58 +0100446static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200447calc_time_spent(Process *proc) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100448 struct timeval tv;
449 struct timezone tz;
450 struct timeval diff;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100451 struct callstack_element *elem;
Juan Cespedesd65efa32003-02-03 00:22:30 +0100452
Juan Cespedescd8976d2009-05-14 13:47:58 +0200453 debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100454 elem = &proc->callstack[proc->callstack_depth - 1];
Juan Cespedesd65efa32003-02-03 00:22:30 +0100455
456 gettimeofday(&tv, &tz);
457
458 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
459 if (tv.tv_usec >= elem->time_spent.tv_usec) {
460 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
461 } else {
462 diff.tv_sec++;
463 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
464 }
465 current_time_spent = diff;
466}
467
Juan Cespedesf1350522008-12-16 18:19:58 +0100468static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200469handle_sysret(Event *event) {
470 debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
Juan Cespedes5c682042009-05-21 15:59:56 +0200471 if (event->proc->state != STATE_IGNORED) {
472 if (opt_T || options.summary) {
473 calc_time_spent(event->proc);
474 }
475 callstack_pop(event->proc);
476 if (options.syscalls) {
477 output_right(LT_TOF_SYSCALLR, event->proc,
478 sysname(event->proc, event->e_un.sysnum));
479 }
Juan Cespedes21c63a12001-07-07 20:56:56 +0200480 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100481 continue_process(event->proc->pid);
482}
483
Juan Cespedesf1350522008-12-16 18:19:58 +0100484static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200485handle_arch_sysret(Event *event) {
486 debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
Juan Cespedes5c682042009-05-21 15:59:56 +0200487 if (event->proc->state != STATE_IGNORED) {
488 if (opt_T || options.summary) {
489 calc_time_spent(event->proc);
490 }
491 callstack_pop(event->proc);
492 if (options.syscalls) {
493 output_right(LT_TOF_SYSCALLR, event->proc,
494 arch_sysname(event->proc, event->e_un.sysnum));
495 }
Juan Cespedes63184be2008-12-10 13:30:12 +0100496 }
497 continue_process(event->proc->pid);
498}
499
Juan Cespedesf1350522008-12-16 18:19:58 +0100500static void
Juan Cespedes03192f82009-07-03 10:16:22 +0200501handle_breakpoint(Event *event) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100502 int i, j;
Juan Cespedes1dec2172009-05-07 10:12:10 +0200503 Breakpoint *sbp;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100504
Juan Cespedes03192f82009-07-03 10:16:22 +0200505 debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
Juan Cespedesefe85f02004-04-04 01:31:38 +0200506 debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
Luis Machado55c5feb2008-03-12 15:56:01 +0100507
Paul Gilliam76c61f12006-06-14 06:55:21 +0200508#ifdef __powerpc__
Luis Machado55c5feb2008-03-12 15:56:01 +0100509 /* Need to skip following NOP's to prevent a fake function from being stacked. */
510 long stub_addr = (long) get_count_register(event->proc);
Juan Cespedes1dec2172009-05-07 10:12:10 +0200511 Breakpoint *stub_bp = NULL;
Luis Machado55c5feb2008-03-12 15:56:01 +0100512 char nop_instruction[] = PPC_NOP;
513
514 stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr);
515
516 if (stub_bp) {
517 unsigned char *bp_instruction = stub_bp->orig_value;
518
519 if (memcmp(bp_instruction, nop_instruction,
520 PPC_NOP_LENGTH) == 0) {
521 if (stub_addr != (long) event->e_un.brk_addr) {
522 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
523 continue_process(event->proc->pid);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200524 return;
525 }
526 }
Luis Machado55c5feb2008-03-12 15:56:01 +0100527 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200528#endif
Luis Machado55c5feb2008-03-12 15:56:01 +0100529 if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100530 /* Reinsert breakpoint */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100531 continue_enabling_breakpoint(event->proc->pid,
532 event->proc->
533 breakpoint_being_enabled);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100534 event->proc->breakpoint_being_enabled = NULL;
535 return;
536 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200537
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100538 for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
539 if (event->e_un.brk_addr ==
540 event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200541#ifdef __powerpc__
Ian Wienand3219f322006-02-16 06:00:00 +0100542 /*
543 * PPC HACK! (XXX FIXME TODO)
544 * The PLT gets modified during the first call,
545 * so be sure to re-enable the breakpoint.
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100546 */
Ian Wienand9a2ad352006-02-20 22:44:45 +0100547 unsigned long a;
548 struct library_symbol *libsym =
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100549 event->proc->callstack[i].c_un.libfunc;
Paul Gilliam76c61f12006-06-14 06:55:21 +0200550 void *addr = sym2addr(event->proc, libsym);
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200551
Paul Gilliam76c61f12006-06-14 06:55:21 +0200552 if (libsym->plt_type != LS_TOPLT_POINT) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100553 unsigned char break_insn[] = BREAKPOINT_VALUE;
554
555 sbp = address2bpstruct(event->proc, addr);
556 assert(sbp);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100557 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
558 addr);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100559
Paul Gilliam76c61f12006-06-14 06:55:21 +0200560 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100561 sbp->enabled--;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100562 insert_breakpoint(event->proc, addr,
563 libsym);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100564 }
565 } else {
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200566 sbp = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, libsym));
Ian Wienand9a2ad352006-02-20 22:44:45 +0100567 assert(sbp);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200568 if (addr != sbp->addr) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100569 insert_breakpoint(event->proc, addr,
570 libsym);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200571 }
Ian Wienand3219f322006-02-16 06:00:00 +0100572 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100573#elif defined(__mips__)
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200574 void *addr;
575 void *old_addr;
576 struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
Juan Cespedesbc8caf02009-05-07 19:38:38 +0200577 assert(sym);
578 old_addr = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, sym))->addr;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200579 addr=sym2addr(event->proc,sym);
580 assert(old_addr !=0 && addr !=0);
581 if(addr != old_addr){
582 struct library_symbol *new_sym;
583 new_sym=malloc(sizeof(*new_sym));
584 memcpy(new_sym,sym,sizeof(*new_sym));
585 new_sym->next=event->proc->list_of_symbols;
586 event->proc->list_of_symbols=new_sym;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200587 insert_breakpoint(event->proc, addr, new_sym);
588 }
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200589#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100590 for (j = event->proc->callstack_depth - 1; j > i; j--) {
Juan Cespedes5916fda2002-02-25 00:19:21 +0100591 callstack_pop(event->proc);
592 }
Juan Cespedes5c682042009-05-21 15:59:56 +0200593 if (event->proc->state != STATE_IGNORED) {
594 if (opt_T || options.summary) {
595 calc_time_spent(event->proc);
596 }
Juan Cespedesd65efa32003-02-03 00:22:30 +0100597 }
598 callstack_pop(event->proc);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100599 event->proc->return_addr = event->e_un.brk_addr;
Juan Cespedes5c682042009-05-21 15:59:56 +0200600 if (event->proc->state != STATE_IGNORED) {
601 output_right(LT_TOF_FUNCTIONR, event->proc,
602 event->proc->callstack[i].c_un.libfunc->name);
603 }
Juan Cespedes5916fda2002-02-25 00:19:21 +0100604 continue_after_breakpoint(event->proc,
Juan Cespedes5c682042009-05-21 15:59:56 +0200605 address2bpstruct(event->proc,
606 event->e_un.brk_addr));
Juan Cespedes5916fda2002-02-25 00:19:21 +0100607 return;
608 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100609 }
610
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100611 if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
Juan Cespedes5c682042009-05-21 15:59:56 +0200612 if (event->proc->state != STATE_IGNORED) {
613 event->proc->stack_pointer = get_stack_pointer(event->proc);
614 event->proc->return_addr =
615 get_return_addr(event->proc, event->proc->stack_pointer);
616 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
617 callstack_push_symfunc(event->proc, sbp->libsym);
618 }
Paul Gilliambe320772006-04-24 22:06:23 +0200619#ifdef PLT_REINITALISATION_BP
620 if (event->proc->need_to_reinitialize_breakpoints
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100621 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
622 0))
623 reinitialize_breakpoints(event->proc);
Paul Gilliambe320772006-04-24 22:06:23 +0200624#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100625
626 continue_after_breakpoint(event->proc, sbp);
627 return;
628 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100629
Juan Cespedes5c682042009-05-21 15:59:56 +0200630 if (event->proc->state != STATE_IGNORED) {
631 output_line(event->proc, "unexpected breakpoint at %p",
632 (void *)event->e_un.brk_addr);
633 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100634 continue_process(event->proc->pid);
635}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200636
Juan Cespedesf1350522008-12-16 18:19:58 +0100637static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200638callstack_push_syscall(Process *proc, int sysnum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100639 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200640
Juan Cespedescd8976d2009-05-14 13:47:58 +0200641 debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200642 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100643 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200644 fprintf(stderr, "Error: call nesting too deep!\n");
645 return;
646 }
647
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100648 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200649 elem->is_syscall = 1;
650 elem->c_un.syscall = sysnum;
651 elem->return_addr = NULL;
652
653 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200654 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100655 struct timezone tz;
656 gettimeofday(&elem->time_spent, &tz);
657 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200658}
659
Juan Cespedes21c63a12001-07-07 20:56:56 +0200660static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200661callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100662 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200663
Juan Cespedescd8976d2009-05-14 13:47:58 +0200664 debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200665 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100666 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200667 fprintf(stderr, "Error: call nesting too deep!\n");
668 return;
669 }
670
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100671 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200672 elem->is_syscall = 0;
673 elem->c_un.libfunc = sym;
674
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200675 elem->return_addr = proc->return_addr;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200676 if (elem->return_addr) {
Paul Gilliam76c61f12006-06-14 06:55:21 +0200677 insert_breakpoint(proc, elem->return_addr, 0);
678 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200679
680 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200681 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100682 struct timezone tz;
683 gettimeofday(&elem->time_spent, &tz);
684 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200685}
686
Juan Cespedesf1350522008-12-16 18:19:58 +0100687static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200688callstack_pop(Process *proc) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100689 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200690 assert(proc->callstack_depth > 0);
691
Juan Cespedescd8976d2009-05-14 13:47:58 +0200692 debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100693 elem = &proc->callstack[proc->callstack_depth - 1];
Paul Gilliam76c61f12006-06-14 06:55:21 +0200694 if (!elem->is_syscall && elem->return_addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200695 delete_breakpoint(proc, elem->return_addr);
696 }
697 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200698}