blob: 5346be07463dc153b150be572e50726a64d10e33 [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
Juan Cespedes393f1d02009-05-07 11:13:54 +020023static void process_signal(Event *event);
24static void process_exit(Event *event);
25static void process_exit_signal(Event *event);
26static void process_syscall(Event *event);
27static void process_arch_syscall(Event *event);
28static void process_sysret(Event *event);
29static void process_arch_sysret(Event *event);
Juan Cespedes393f1d02009-05-07 11:13:54 +020030static void process_clone(Event *event);
31static void process_exec(Event *event);
32static void process_breakpoint(Event *event);
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +020033static void process_new(Event *event);
Juan Cespedesa8909f72009-04-28 20:02:41 +020034static void remove_proc(Process *proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +010035
Juan Cespedesa8909f72009-04-28 20:02:41 +020036static void callstack_push_syscall(Process *proc, int sysnum);
37static void callstack_push_symfunc(Process *proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +010038 struct library_symbol *sym);
Juan Cespedesa8909f72009-04-28 20:02:41 +020039static void callstack_pop(Process *proc);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020040
Juan Cespedesf1350522008-12-16 18:19:58 +010041static char *
Juan Cespedesa8909f72009-04-28 20:02:41 +020042shortsignal(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 *
Juan Cespedesa8909f72009-04-28 20:02:41 +020064sysname(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 *
Juan Cespedesa8909f72009-04-28 20:02:41 +020090arch_sysname(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
Juan Cespedes393f1d02009-05-07 11:13:54 +0200108process_event(Event *event) {
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200109 switch (event->type) {
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_CLONE:
154 debug(1, "event: clone (%u)", event->e_un.newpid);
155 process_clone(event);
156 return;
157 case EVENT_EXEC:
158 debug(1, "event: exec()");
159 process_exec(event);
160 return;
Juan Cespedes138d41c2009-04-07 00:49:12 +0200161 case EVENT_BREAKPOINT:
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100162 debug(1, "event: breakpoint");
163 process_breakpoint(event);
164 return;
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200165 case EVENT_NEW:
166 debug(1, "event: new process");
167 process_new(event);
168 return;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100169 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
Juan Cespedes393f1d02009-05-07 11:13:54 +0200176process_signal(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
Juan Cespedes393f1d02009-05-07 11:13:54 +0200191process_exit(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
Juan Cespedes393f1d02009-05-07 11:13:54 +0200198process_exit_signal(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
Juan Cespedesa8909f72009-04-28 20:02:41 +0200205remove_proc(Process *proc) {
206 Process *tmp, *tmp2;
Juan Cespedes1fe93d51998-03-13 00:29:21 +0100207
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
Juan Cespedes393f1d02009-05-07 11:13:54 +0200229process_syscall(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 Cespedes8f6d1ec2009-05-07 17:50:34 +0200244process_clone(Event * event) {
245 output_line(event->proc, "--- clone() = %u ---",
Juan Cespedes1e583132009-04-07 18:17:11 +0200246 event->e_un.newpid);
247 continue_process(event->proc->pid);
248}
249
250static void
Juan Cespedes8f6d1ec2009-05-07 17:50:34 +0200251process_new(Event * event) {
252 output_line(NULL, "--- new child = %u ---",
Juan Cespedes1e583132009-04-07 18:17:11 +0200253 event->e_un.newpid);
Juan Cespedes1e583132009-04-07 18:17:11 +0200254}
255
256static void
Juan Cespedes393f1d02009-05-07 11:13:54 +0200257process_exec(Event * event) {
Juan Cespedes1e583132009-04-07 18:17:11 +0200258 output_line(event->proc, "--- exec() ---");
259 abort();
260}
261
262static void
Juan Cespedes393f1d02009-05-07 11:13:54 +0200263process_arch_syscall(Event *event) {
Juan Cespedesce377d52008-12-16 19:38:10 +0100264 if (options.syscalls) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100265 output_left(LT_TOF_SYSCALL, event->proc,
266 arch_sysname(event->proc, event->e_un.sysnum));
267 }
268 if (event->proc->breakpoints_enabled == 0) {
269 enable_all_breakpoints(event->proc);
270 }
271 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
272 continue_process(event->proc->pid);
273}
274
Juan Cespedesd65efa32003-02-03 00:22:30 +0100275struct timeval current_time_spent;
276
Juan Cespedesf1350522008-12-16 18:19:58 +0100277static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200278calc_time_spent(Process *proc) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100279 struct timeval tv;
280 struct timezone tz;
281 struct timeval diff;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100282 struct callstack_element *elem;
Juan Cespedesd65efa32003-02-03 00:22:30 +0100283
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100284 elem = &proc->callstack[proc->callstack_depth - 1];
Juan Cespedesd65efa32003-02-03 00:22:30 +0100285
286 gettimeofday(&tv, &tz);
287
288 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
289 if (tv.tv_usec >= elem->time_spent.tv_usec) {
290 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
291 } else {
292 diff.tv_sec++;
293 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
294 }
295 current_time_spent = diff;
296}
297
Juan Cespedesf1350522008-12-16 18:19:58 +0100298static void
Juan Cespedes393f1d02009-05-07 11:13:54 +0200299process_sysret(Event *event) {
Juan Cespedesda9b9532009-04-07 15:33:50 +0200300 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100301 calc_time_spent(event->proc);
302 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100303 if (fork_p(event->proc, event->e_un.sysnum)) {
Juan Cespedescc813cd2009-04-07 15:45:53 +0200304 if (options.follow) {
Steve Fink65b53df2006-09-25 02:27:08 +0200305 arg_type_info info;
Steve Fink65b53df2006-09-25 02:27:08 +0200306 info.type = ARGTYPE_LONG;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100307 pid_t child =
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200308 gimme_arg(LT_TOF_SYSCALLR, event->proc, -1, &info);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100309 if (child > 0) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +0100310 open_pid(child, 0);
311 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100312 }
Juan Cespedes35d70631998-03-15 14:05:40 +0100313 enable_all_breakpoints(event->proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100314 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200315 callstack_pop(event->proc);
Juan Cespedesce377d52008-12-16 19:38:10 +0100316 if (options.syscalls) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100317 output_right(LT_TOF_SYSCALLR, event->proc,
318 sysname(event->proc, event->e_un.sysnum));
Juan Cespedes21c63a12001-07-07 20:56:56 +0200319 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100320 continue_process(event->proc->pid);
321}
322
Juan Cespedesf1350522008-12-16 18:19:58 +0100323static void
Juan Cespedes393f1d02009-05-07 11:13:54 +0200324process_arch_sysret(Event *event) {
Juan Cespedesda9b9532009-04-07 15:33:50 +0200325 if (opt_T || options.summary) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100326 calc_time_spent(event->proc);
327 }
328 callstack_pop(event->proc);
Juan Cespedesce377d52008-12-16 19:38:10 +0100329 if (options.syscalls) {
Juan Cespedes63184be2008-12-10 13:30:12 +0100330 output_right(LT_TOF_SYSCALLR, event->proc,
331 arch_sysname(event->proc, event->e_un.sysnum));
332 }
333 continue_process(event->proc->pid);
334}
335
Juan Cespedesf1350522008-12-16 18:19:58 +0100336static void
Juan Cespedes393f1d02009-05-07 11:13:54 +0200337process_breakpoint(Event *event) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100338 int i, j;
Juan Cespedes1dec2172009-05-07 10:12:10 +0200339 Breakpoint *sbp;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100340
Juan Cespedesefe85f02004-04-04 01:31:38 +0200341 debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
Luis Machado55c5feb2008-03-12 15:56:01 +0100342
Paul Gilliam76c61f12006-06-14 06:55:21 +0200343#ifdef __powerpc__
Luis Machado55c5feb2008-03-12 15:56:01 +0100344 /* Need to skip following NOP's to prevent a fake function from being stacked. */
345 long stub_addr = (long) get_count_register(event->proc);
Juan Cespedes1dec2172009-05-07 10:12:10 +0200346 Breakpoint *stub_bp = NULL;
Luis Machado55c5feb2008-03-12 15:56:01 +0100347 char nop_instruction[] = PPC_NOP;
348
349 stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr);
350
351 if (stub_bp) {
352 unsigned char *bp_instruction = stub_bp->orig_value;
353
354 if (memcmp(bp_instruction, nop_instruction,
355 PPC_NOP_LENGTH) == 0) {
356 if (stub_addr != (long) event->e_un.brk_addr) {
357 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
358 continue_process(event->proc->pid);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200359 return;
360 }
361 }
Luis Machado55c5feb2008-03-12 15:56:01 +0100362 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200363#endif
Luis Machado55c5feb2008-03-12 15:56:01 +0100364 if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
Juan Cespedesb1dd77d2002-03-03 00:22:06 +0100365 /* Reinsert breakpoint */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100366 continue_enabling_breakpoint(event->proc->pid,
367 event->proc->
368 breakpoint_being_enabled);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100369 event->proc->breakpoint_being_enabled = NULL;
370 return;
371 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200372
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100373 for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
374 if (event->e_un.brk_addr ==
375 event->proc->callstack[i].return_addr) {
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200376#ifdef __powerpc__
Ian Wienand3219f322006-02-16 06:00:00 +0100377 /*
378 * PPC HACK! (XXX FIXME TODO)
379 * The PLT gets modified during the first call,
380 * so be sure to re-enable the breakpoint.
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100381 */
Ian Wienand9a2ad352006-02-20 22:44:45 +0100382 unsigned long a;
383 struct library_symbol *libsym =
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100384 event->proc->callstack[i].c_un.libfunc;
Paul Gilliam76c61f12006-06-14 06:55:21 +0200385 void *addr = sym2addr(event->proc, libsym);
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200386
Paul Gilliam76c61f12006-06-14 06:55:21 +0200387 if (libsym->plt_type != LS_TOPLT_POINT) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100388 unsigned char break_insn[] = BREAKPOINT_VALUE;
389
390 sbp = address2bpstruct(event->proc, addr);
391 assert(sbp);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100392 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
393 addr);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100394
Paul Gilliam76c61f12006-06-14 06:55:21 +0200395 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100396 sbp->enabled--;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100397 insert_breakpoint(event->proc, addr,
398 libsym);
Ian Wienand9a2ad352006-02-20 22:44:45 +0100399 }
400 } else {
401 sbp = libsym->brkpnt;
402 assert(sbp);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200403 if (addr != sbp->addr) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100404 insert_breakpoint(event->proc, addr,
405 libsym);
Paul Gilliam76c61f12006-06-14 06:55:21 +0200406 }
Ian Wienand3219f322006-02-16 06:00:00 +0100407 }
Eric Vaitl1228a912006-12-28 16:16:56 +0100408#elif defined(__mips__)
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200409 void *addr;
410 void *old_addr;
411 struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
412 assert(sym && sym->brkpnt);
413 old_addr=sym->brkpnt->addr;
414 addr=sym2addr(event->proc,sym);
415 assert(old_addr !=0 && addr !=0);
416 if(addr != old_addr){
417 struct library_symbol *new_sym;
418 new_sym=malloc(sizeof(*new_sym));
419 memcpy(new_sym,sym,sizeof(*new_sym));
420 new_sym->next=event->proc->list_of_symbols;
421 event->proc->list_of_symbols=new_sym;
422 new_sym->brkpnt=0;
423 insert_breakpoint(event->proc, addr, new_sym);
424 }
Juan Cespedes5bfb0612002-03-31 20:01:28 +0200425#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100426 for (j = event->proc->callstack_depth - 1; j > i; j--) {
Juan Cespedes5916fda2002-02-25 00:19:21 +0100427 callstack_pop(event->proc);
428 }
Juan Cespedesda9b9532009-04-07 15:33:50 +0200429 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100430 calc_time_spent(event->proc);
431 }
432 callstack_pop(event->proc);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100433 event->proc->return_addr = event->e_un.brk_addr;
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200434 output_right(LT_TOF_FUNCTIONR, event->proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100435 event->proc->callstack[i].c_un.libfunc->
436 name);
Juan Cespedes5916fda2002-02-25 00:19:21 +0100437 continue_after_breakpoint(event->proc,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100438 address2bpstruct(event->proc,
439 event->e_un.
440 brk_addr));
Juan Cespedes5916fda2002-02-25 00:19:21 +0100441 return;
442 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100443 }
444
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100445 if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
446 event->proc->stack_pointer = get_stack_pointer(event->proc);
447 event->proc->return_addr =
448 get_return_addr(event->proc, event->proc->stack_pointer);
449 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
450 callstack_push_symfunc(event->proc, sbp->libsym);
Paul Gilliambe320772006-04-24 22:06:23 +0200451#ifdef PLT_REINITALISATION_BP
452 if (event->proc->need_to_reinitialize_breakpoints
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100453 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
454 0))
455 reinitialize_breakpoints(event->proc);
Paul Gilliambe320772006-04-24 22:06:23 +0200456#endif
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100457
458 continue_after_breakpoint(event->proc, sbp);
459 return;
460 }
Ian Wienand9a2ad352006-02-20 22:44:45 +0100461
462 output_line(event->proc, "unexpected breakpoint at %p",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100463 (void *)event->e_un.brk_addr);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100464 continue_process(event->proc->pid);
465}
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200466
Juan Cespedesf1350522008-12-16 18:19:58 +0100467static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200468callstack_push_syscall(Process *proc, int sysnum) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100469 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200470
471 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100472 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200473 fprintf(stderr, "Error: call nesting too deep!\n");
474 return;
475 }
476
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100477 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200478 elem->is_syscall = 1;
479 elem->c_un.syscall = sysnum;
480 elem->return_addr = NULL;
481
482 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200483 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100484 struct timezone tz;
485 gettimeofday(&elem->time_spent, &tz);
486 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200487}
488
Juan Cespedes21c63a12001-07-07 20:56:56 +0200489static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200490callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100491 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200492
493 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100494 if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200495 fprintf(stderr, "Error: call nesting too deep!\n");
496 return;
497 }
498
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100499 elem = &proc->callstack[proc->callstack_depth];
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200500 elem->is_syscall = 0;
501 elem->c_un.libfunc = sym;
502
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200503 elem->return_addr = proc->return_addr;
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200504 if (elem->return_addr) {
Paul Gilliam76c61f12006-06-14 06:55:21 +0200505 insert_breakpoint(proc, elem->return_addr, 0);
506 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200507
508 proc->callstack_depth++;
Juan Cespedesda9b9532009-04-07 15:33:50 +0200509 if (opt_T || options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100510 struct timezone tz;
511 gettimeofday(&elem->time_spent, &tz);
512 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200513}
514
Juan Cespedesf1350522008-12-16 18:19:58 +0100515static void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200516callstack_pop(Process *proc) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100517 struct callstack_element *elem;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200518 assert(proc->callstack_depth > 0);
519
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100520 elem = &proc->callstack[proc->callstack_depth - 1];
Paul Gilliam76c61f12006-06-14 06:55:21 +0200521 if (!elem->is_syscall && elem->return_addr) {
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200522 delete_breakpoint(proc, elem->return_addr);
523 }
524 proc->callstack_depth--;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200525}