blob: c54f637a00ac54499c37d24fc53c9c8cd6cc7865 [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
13#include "ltrace.h"
14#include "output.h"
15#include "options.h"
Juan Cespedes81690ef1998-03-13 19:31:29 +010016#include "elf.h"
Juan Cespedescac15c32003-01-31 18:58:58 +010017#include "debug.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010018
Juan Cespedesf1bfe202002-03-27 00:22:23 +010019#ifdef __powerpc__
20#include <sys/ptrace.h>
21#endif
22
Ian Wienand2d45b1a2006-02-20 22:48:07 +010023static void process_signal(struct event *event);
24static void process_exit(struct event *event);
25static void process_exit_signal(struct event *event);
26static void process_syscall(struct event *event);
Juan Cespedes63184be2008-12-10 13:30:12 +010027static void process_arch_syscall(struct event *event);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010028static void process_sysret(struct event *event);
Juan Cespedes63184be2008-12-10 13:30:12 +010029static void process_arch_sysret(struct event *event);
Juan Cespedes1e583132009-04-07 18:17:11 +020030static void process_fork(struct event *event);
31static void process_clone(struct event *event);
32static void process_exec(struct event *event);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010033static void process_breakpoint(struct event *event);
34static void remove_proc(struct process *proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010035
Ian Wienand2d45b1a2006-02-20 22:48:07 +010036static void callstack_push_syscall(struct process *proc, int sysnum);
37static void callstack_push_symfunc(struct process *proc,
38 struct library_symbol *sym);
39static void callstack_pop(struct process *proc);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020040
Juan Cespedesf1350522008-12-16 18:19:58 +010041static char *
42shortsignal(struct process *proc, int signum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010043 static char *signalent0[] = {
44#include "signalent.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010045 };
Ian Wienand2d45b1a2006-02-20 22:48:07 +010046 static char *signalent1[] = {
47#include "signalent1.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +010048 };
49 static char **signalents[] = { signalent0, signalent1 };
50 int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
Ian Wienand2d45b1a2006-02-20 22:48:07 +010051 sizeof signalent1 / sizeof signalent1[0]
52 };
Juan Cespedes5e01f651998-03-08 22:31:44 +010053
Ian Wienand9a2ad352006-02-20 22:44:45 +010054 if (proc->personality > sizeof signalents / sizeof signalents[0])
Ian Wienand2d45b1a2006-02-20 22:48:07 +010055 abort();
Ian Wienand9a2ad352006-02-20 22:44:45 +010056 if (signum < 0 || signum >= nsignals[proc->personality]) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010057 return "UNKNOWN_SIGNAL";
58 } else {
Ian Wienand9a2ad352006-02-20 22:44:45 +010059 return signalents[proc->personality][signum];
Juan Cespedes5e01f651998-03-08 22:31:44 +010060 }
61}
62
Juan Cespedesf1350522008-12-16 18:19:58 +010063static char *
64sysname(struct process *proc, int sysnum) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010065 static char result[128];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010066 static char *syscalent0[] = {
67#include "syscallent.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010068 };
Ian Wienand2d45b1a2006-02-20 22:48:07 +010069 static char *syscalent1[] = {
70#include "syscallent1.h"
Ian Wienand9a2ad352006-02-20 22:44:45 +010071 };
72 static char **syscalents[] = { syscalent0, syscalent1 };
73 int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
Ian Wienand2d45b1a2006-02-20 22:48:07 +010074 sizeof syscalent1 / sizeof syscalent1[0]
75 };
Juan Cespedes5e01f651998-03-08 22:31:44 +010076
Ian Wienand9a2ad352006-02-20 22:44:45 +010077 if (proc->personality > sizeof syscalents / sizeof syscalents[0])
Ian Wienand2d45b1a2006-02-20 22:48:07 +010078 abort();
Ian Wienand9a2ad352006-02-20 22:44:45 +010079 if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010080 sprintf(result, "SYS_%d", sysnum);
81 return result;
82 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010083 sprintf(result, "SYS_%s",
84 syscalents[proc->personality][sysnum]);
Juan Cespedes5e01f651998-03-08 22:31:44 +010085 return result;
86 }
87}
88
Juan Cespedesf1350522008-12-16 18:19:58 +010089static char *
90arch_sysname(struct process *proc, int sysnum) {
Juan Cespedes63184be2008-12-10 13:30:12 +010091 static char result[128];
92 static char *arch_syscalent[] = {
93#include "arch_syscallent.h"
94 };
95 int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
96
97 if (sysnum < 0 || sysnum >= nsyscals) {
98 sprintf(result, "ARCH_%d", sysnum);
99 return result;
100 } else {
101 sprintf(result, "ARCH_%s",
102 arch_syscalent[sysnum]);
103 return result;
104 }
105}
106
Juan Cespedesf1350522008-12-16 18:19:58 +0100107void
108process_event(struct event *event) {
Juan Cespedesefe85f02004-04-04 01:31:38 +0200109 switch (event->thing) {
Juan Cespedes138d41c2009-04-07 00:49:12 +0200110 case EVENT_NONE:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100111 debug(1, "event: none");
112 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200113 case EVENT_SIGNAL:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100114 debug(1, "event: signal (%s [%d])",
115 shortsignal(event->proc, event->e_un.signum),
116 event->e_un.signum);
117 process_signal(event);
118 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200119 case EVENT_EXIT:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100120 debug(1, "event: exit (%d)", event->e_un.ret_val);
121 process_exit(event);
122 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200123 case EVENT_EXIT_SIGNAL:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100124 debug(1, "event: exit signal (%s [%d])",
125 shortsignal(event->proc, event->e_un.signum),
126 event->e_un.signum);
127 process_exit_signal(event);
128 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200129 case EVENT_SYSCALL:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100130 debug(1, "event: syscall (%s [%d])",
131 sysname(event->proc, event->e_un.sysnum),
132 event->e_un.sysnum);
133 process_syscall(event);
134 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200135 case EVENT_SYSRET:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100136 debug(1, "event: sysret (%s [%d])",
137 sysname(event->proc, event->e_un.sysnum),
138 event->e_un.sysnum);
139 process_sysret(event);
140 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200141 case EVENT_ARCH_SYSCALL:
Juan Cespedes63184be2008-12-10 13:30:12 +0100142 debug(1, "event: arch_syscall (%s [%d])",
143 arch_sysname(event->proc, event->e_un.sysnum),
144 event->e_un.sysnum);
145 process_arch_syscall(event);
146 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200147 case EVENT_ARCH_SYSRET:
Juan Cespedes63184be2008-12-10 13:30:12 +0100148 debug(1, "event: arch_sysret (%s [%d])",
149 arch_sysname(event->proc, event->e_un.sysnum),
150 event->e_un.sysnum);
151 process_arch_sysret(event);
152 return;
Juan Cespedes1e583132009-04-07 18:17:11 +0200153 case EVENT_FORK:
154 debug(1, "event: fork (%u)", event->e_un.newpid);
155 process_fork(event);
156 return;
157 case EVENT_CLONE:
158 debug(1, "event: clone (%u)", event->e_un.newpid);
159 process_clone(event);
160 return;
161 case EVENT_EXEC:
162 debug(1, "event: exec()");
163 process_exec(event);
164 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200165 case EVENT_BREAKPOINT:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100166 debug(1, "event: breakpoint");
167 process_breakpoint(event);
168 return;
169 default:
170 fprintf(stderr, "Error! unknown event?\n");
171 exit(1);
Juan Cespedesefe85f02004-04-04 01:31:38 +0200172 }
173}
174
Juan Cespedesf1350522008-12-16 18:19:58 +0100175static void
176process_signal(struct event *event) {
Juan Cespedes28f60191998-04-12 00:04:39 +0200177 if (exiting && event->e_un.signum == SIGSTOP) {
178 pid_t pid = event->proc->pid;
179 disable_all_breakpoints(event->proc);
180 untrace_pid(pid);
181 remove_proc(event->proc);
Juan Cespedes28f60191998-04-12 00:04:39 +0200182 return;
183 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100184 output_line(event->proc, "--- %s (%s) ---",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100185 shortsignal(event->proc, event->e_un.signum),
186 strsignal(event->e_un.signum));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100187 continue_after_signal(event->proc->pid, event->e_un.signum);
188}
189
Juan Cespedesf1350522008-12-16 18:19:58 +0100190static void
191process_exit(struct event *event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100192 output_line(event->proc, "+++ exited (status %d) +++",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100193 event->e_un.ret_val);
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100194 remove_proc(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100195}
196
Juan Cespedesf1350522008-12-16 18:19:58 +0100197static void
198process_exit_signal(struct event *event) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100199 output_line(event->proc, "+++ killed by %s +++",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100200 shortsignal(event->proc, event->e_un.signum));
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100201 remove_proc(event->proc);
202}
203
Juan Cespedesf1350522008-12-16 18:19:58 +0100204static void
205remove_proc(struct process *proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100206 struct process *tmp, *tmp2;
207
Juan Cespedescac15c32003-01-31 18:58:58 +0100208 debug(1, "Removing pid %u\n", proc->pid);
Juan Cespedes28f60191998-04-12 00:04:39 +0200209
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100210 if (list_of_processes == proc) {
211 tmp = list_of_processes;
212 list_of_processes = list_of_processes->next;
213 free(tmp);
214 return;
215 }
216 tmp = list_of_processes;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100217 while (tmp->next) {
218 if (tmp->next == proc) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100219 tmp2 = tmp->next;
220 tmp->next = tmp->next->next;
221 free(tmp2);
Juan Cespedes28f60191998-04-12 00:04:39 +0200222 continue;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100223 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100224 tmp = tmp->next;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100225 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100226}
227
Juan Cespedesf1350522008-12-16 18:19:58 +0100228static void
229process_syscall(struct event *event) {
Juan Cespedesce377d52008-12-16 19:38:10 +0100230 if (options.syscalls) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100231 output_left(LT_TOF_SYSCALL, event->proc,
232 sysname(event->proc, event->e_un.sysnum));
Juan Cespedes5e01f651998-03-08 22:31:44 +0100233 }
Juan Cespedesaee09312007-08-31 18:49:48 +0200234 if (fork_p(event->proc, event->e_un.sysnum)) {
235 disable_all_breakpoints(event->proc);
236 } else if (event->proc->breakpoints_enabled == 0) {
Juan Cespedes81690ef1998-03-13 19:31:29 +0100237 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100238 }
Juan Cespedesd65efa32003-02-03 00:22:30 +0100239 callstack_push_syscall(event->proc, event->e_un.sysnum);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100240 continue_process(event->proc->pid);
241}
242
Juan Cespedesf1350522008-12-16 18:19:58 +0100243static void
Juan Cespedes1e583132009-04-07 18:17:11 +0200244process_fork(struct event * event) {
245 output_line(event->proc, "--- fork() = %u ---",
246 event->e_un.newpid);
247 continue_process(event->proc->pid);
248}
249
250static void
251process_clone(struct event * event) {
252 output_line(event->proc, "--- clone() = %u ---",
253 event->e_un.newpid);
254 abort();
255}
256
257static void
258process_exec(struct event * event) {
259 output_line(event->proc, "--- exec() ---");
260 abort();
261}
262
263static void
Juan Cespedesf1350522008-12-16 18:19:58 +0100264process_arch_syscall(struct event *event) {
Juan Cespedesce377d52008-12-16 19:38:10 +0100265 if (options.syscalls) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100266 output_left(LT_TOF_SYSCALL, event->proc,
267 arch_sysname(event->proc, event->e_un.sysnum));
268 }
269 if (event->proc->breakpoints_enabled == 0) {
270 enable_all_breakpoints(event->proc);
271 }
272 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
273 continue_process(event->proc->pid);
274}
275
Juan Cespedesd65efa32003-02-03 00:22:30 +0100276struct timeval current_time_spent;
277
Juan Cespedesf1350522008-12-16 18:19:58 +0100278static void
279calc_time_spent(struct process *proc) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100280 struct timeval tv;
281 struct timezone tz;
282 struct timeval diff;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100283 struct callstack_element *elem;
Juan Cespedesd65efa32003-02-03 00:22:30 +0100284
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100285 elem = &proc->callstack[proc->callstack_depth - 1];
Juan Cespedesd65efa32003-02-03 00:22:30 +0100286
287 gettimeofday(&tv, &tz);
288
289 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
290 if (tv.tv_usec >= elem->time_spent.tv_usec) {
291 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
292 } else {
293 diff.tv_sec++;
294 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
295 }
296 current_time_spent = diff;
297}
298
Juan Cespedesf1350522008-12-16 18:19:58 +0100299static void
300process_sysret(struct event *event) {
Juan Cespedesda9b9532009-04-07 15:33:50 +0200301 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100302 calc_time_spent(event->proc);
303 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100304 if (fork_p(event->proc, event->e_un.sysnum)) {
Juan Cespedescc813cd2009-04-07 15:45:53 +0200305 if (options.follow) {
Steve Fink65b53df2006-09-25 02:27:08 +0200306 arg_type_info info;
Steve Fink65b53df2006-09-25 02:27:08 +0200307 info.type = ARGTYPE_LONG;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100308 pid_t child =
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200309 gimme_arg(LT_TOF_SYSCALLR, event->proc, -1, &info);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100310 if (child > 0) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100311 open_pid(child, 0);
312 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100313 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100314 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100315 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200316 callstack_pop(event->proc);
Juan Cespedesce377d52008-12-16 19:38:10 +0100317 if (options.syscalls) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100318 output_right(LT_TOF_SYSCALLR, event->proc,
319 sysname(event->proc, event->e_un.sysnum));
Juan Cespedes21c63a12001-07-07 20:56:56 +0200320 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100321 continue_process(event->proc->pid);
322}
323
Juan Cespedesf1350522008-12-16 18:19:58 +0100324static void
325process_arch_sysret(struct event *event) {
Juan Cespedesda9b9532009-04-07 15:33:50 +0200326 if (opt_T || options.summary) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100327 calc_time_spent(event->proc);
328 }
329 callstack_pop(event->proc);
Juan Cespedesce377d52008-12-16 19:38:10 +0100330 if (options.syscalls) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100331 output_right(LT_TOF_SYSCALLR, event->proc,
332 arch_sysname(event->proc, event->e_un.sysnum));
333 }
334 continue_process(event->proc->pid);
335}
336
Juan Cespedesf1350522008-12-16 18:19:58 +0100337static void
338process_breakpoint(struct event *event) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100339 int i, j;
Steve Fink65b53df2006-09-25 02:27:08 +0200340 struct breakpoint *sbp;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100341
Juan Cespedesefe85f02004-04-04 01:31:38 +0200342 debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
Luis Machado55c5feb2008-03-12 15:56:01 +0100343
Paul Gilliam76c61f12006-06-14 06:55:21 +0200344#ifdef __powerpc__
Luis Machado55c5feb2008-03-12 15:56:01 +0100345 /* Need to skip following NOP's to prevent a fake function from being stacked. */
346 long stub_addr = (long) get_count_register(event->proc);
347 struct breakpoint *stub_bp = NULL;
348 char nop_instruction[] = PPC_NOP;
349
350 stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr);
351
352 if (stub_bp) {
353 unsigned char *bp_instruction = stub_bp->orig_value;
354
355 if (memcmp(bp_instruction, nop_instruction,
356 PPC_NOP_LENGTH) == 0) {
357 if (stub_addr != (long) event->e_un.brk_addr) {
358 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
359 continue_process(event->proc->pid);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200360 return;
361 }
362 }
Luis Machado55c5feb2008-03-12 15:56:01 +0100363 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200364#endif
Luis Machado55c5feb2008-03-12 15:56:01 +0100365 if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100366 /* Reinsert breakpoint */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100367 continue_enabling_breakpoint(event->proc->pid,
368 event->proc->
369 breakpoint_being_enabled);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100370 event->proc->breakpoint_being_enabled = NULL;
371 return;
372 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200373
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100374 for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
375 if (event->e_un.brk_addr ==
376 event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200377#ifdef __powerpc__
Ian Wienand3219f322006-02-16 06:00:00 +0100378 /*
379 * PPC HACK! (XXX FIXME TODO)
380 * The PLT gets modified during the first call,
381 * so be sure to re-enable the breakpoint.
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100382 */
Ian Wienand9a2ad352006-02-20 22:44:45 +0100383 unsigned long a;
384 struct library_symbol *libsym =
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100385 event->proc->callstack[i].c_un.libfunc;
Paul Gilliam76c61f12006-06-14 06:55:21 +0200386 void *addr = sym2addr(event->proc, libsym);
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200387
Paul Gilliam76c61f12006-06-14 06:55:21 +0200388 if (libsym->plt_type != LS_TOPLT_POINT) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100389 unsigned char break_insn[] = BREAKPOINT_VALUE;
390
391 sbp = address2bpstruct(event->proc, addr);
392 assert(sbp);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100393 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
394 addr);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100395
Paul Gilliam76c61f12006-06-14 06:55:21 +0200396 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100397 sbp->enabled--;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100398 insert_breakpoint(event->proc, addr,
399 libsym);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100400 }
401 } else {
402 sbp = libsym->brkpnt;
403 assert(sbp);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200404 if (addr != sbp->addr) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100405 insert_breakpoint(event->proc, addr,
406 libsym);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200407 }
Ian Wienand3219f322006-02-16 06:00:00 +0100408 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100409#elif defined(__mips__)
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200410 void *addr;
411 void *old_addr;
412 struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
413 assert(sym && sym->brkpnt);
414 old_addr=sym->brkpnt->addr;
415 addr=sym2addr(event->proc,sym);
416 assert(old_addr !=0 && addr !=0);
417 if(addr != old_addr){
418 struct library_symbol *new_sym;
419 new_sym=malloc(sizeof(*new_sym));
420 memcpy(new_sym,sym,sizeof(*new_sym));
421 new_sym->next=event->proc->list_of_symbols;
422 event->proc->list_of_symbols=new_sym;
423 new_sym->brkpnt=0;
424 insert_breakpoint(event->proc, addr, new_sym);
425 }
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200426#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100427 for (j = event->proc->callstack_depth - 1; j > i; j--) {
Juan Cespedes5916fda2002-02-25 00:19:21 +0100428 callstack_pop(event->proc);
429 }
Juan Cespedesda9b9532009-04-07 15:33:50 +0200430 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100431 calc_time_spent(event->proc);
432 }
433 callstack_pop(event->proc);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100434 event->proc->return_addr = event->e_un.brk_addr;
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200435 output_right(LT_TOF_FUNCTIONR, event->proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100436 event->proc->callstack[i].c_un.libfunc->
437 name);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100438 continue_after_breakpoint(event->proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100439 address2bpstruct(event->proc,
440 event->e_un.
441 brk_addr));
Juan Cespedes5916fda2002-02-25 00:19:21 +0100442 return;
443 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100444 }
445
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100446 if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
447 event->proc->stack_pointer = get_stack_pointer(event->proc);
448 event->proc->return_addr =
449 get_return_addr(event->proc, event->proc->stack_pointer);
450 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
451 callstack_push_symfunc(event->proc, sbp->libsym);
Paul Gilliambe320772006-04-24 22:06:23 +0200452#ifdef PLT_REINITALISATION_BP
453 if (event->proc->need_to_reinitialize_breakpoints
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100454 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
455 0))
456 reinitialize_breakpoints(event->proc);
Paul Gilliambe320772006-04-24 22:06:23 +0200457#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100458
459 continue_after_breakpoint(event->proc, sbp);
460 return;
461 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100462
463 output_line(event->proc, "unexpected breakpoint at %p",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100464 (void *)event->e_un.brk_addr);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100465 continue_process(event->proc->pid);
466}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200467
Juan Cespedesf1350522008-12-16 18:19:58 +0100468static void
469callstack_push_syscall(struct process *proc, int sysnum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100470 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200471
472 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100473 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200474 fprintf(stderr, "Error: call nesting too deep!\n");
475 return;
476 }
477
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100478 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200479 elem->is_syscall = 1;
480 elem->c_un.syscall = sysnum;
481 elem->return_addr = NULL;
482
483 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200484 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100485 struct timezone tz;
486 gettimeofday(&elem->time_spent, &tz);
487 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200488}
489
Juan Cespedes21c63a12001-07-07 20:56:56 +0200490static void
Juan Cespedesf1350522008-12-16 18:19:58 +0100491callstack_push_symfunc(struct process *proc, struct library_symbol *sym) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100492 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200493
494 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100495 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200496 fprintf(stderr, "Error: call nesting too deep!\n");
497 return;
498 }
499
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100500 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200501 elem->is_syscall = 0;
502 elem->c_un.libfunc = sym;
503
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200504 elem->return_addr = proc->return_addr;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200505 if (elem->return_addr) {
Paul Gilliam76c61f12006-06-14 06:55:21 +0200506 insert_breakpoint(proc, elem->return_addr, 0);
507 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200508
509 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200510 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100511 struct timezone tz;
512 gettimeofday(&elem->time_spent, &tz);
513 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200514}
515
Juan Cespedesf1350522008-12-16 18:19:58 +0100516static void
517callstack_pop(struct process *proc) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100518 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200519 assert(proc->callstack_depth > 0);
520
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100521 elem = &proc->callstack[proc->callstack_depth - 1];
Paul Gilliam76c61f12006-06-14 06:55:21 +0200522 if (!elem->is_syscall && elem->return_addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200523 delete_breakpoint(proc, elem->return_addr);
524 }
525 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200526}