tizen 2.0
[external/ltrace.git] / handle_event.c
1 #include "config.h"
2
3 #define _GNU_SOURCE
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <assert.h>
9 #include <sys/time.h>
10
11 #include "common.h"
12
13 #ifdef __powerpc__
14 #include <sys/ptrace.h>
15 #endif
16
17 static void handle_signal(Event *event);
18 static void handle_exit(Event *event);
19 static void handle_exit_signal(Event *event);
20 static void handle_syscall(Event *event);
21 static void handle_arch_syscall(Event *event);
22 static void handle_sysret(Event *event);
23 static void handle_arch_sysret(Event *event);
24 static void handle_clone(Event *event);
25 static void handle_exec(Event *event);
26 static void handle_breakpoint(Event *event);
27 static void handle_new(Event *event);
28 static void remove_proc(Process *proc);
29
30 static void callstack_push_syscall(Process *proc, int sysnum);
31 static void callstack_push_symfunc(Process *proc,
32                                    struct library_symbol *sym);
33 static void callstack_pop(Process *proc);
34
35 static char * shortsignal(Process *proc, int signum);
36 static char * sysname(Process *proc, int sysnum);
37 static char * arch_sysname(Process *proc, int sysnum);
38
39 void
40 handle_event(Event *event) {
41         debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type);
42         switch (event->type) {
43         case EVENT_NONE:
44                 debug(1, "event: none");
45                 return;
46         case EVENT_SIGNAL:
47                 debug(1, "event: signal (%s [%d])",
48                       shortsignal(event->proc, event->e_un.signum),
49                       event->e_un.signum);
50                 handle_signal(event);
51                 return;
52         case EVENT_EXIT:
53                 debug(1, "event: exit (%d)", event->e_un.ret_val);
54                 handle_exit(event);
55                 return;
56         case EVENT_EXIT_SIGNAL:
57                 debug(1, "event: exit signal (%s [%d])",
58                       shortsignal(event->proc, event->e_un.signum),
59                       event->e_un.signum);
60                 handle_exit_signal(event);
61                 return;
62         case EVENT_SYSCALL:
63                 debug(1, "event: syscall (%s [%d])",
64                       sysname(event->proc, event->e_un.sysnum),
65                       event->e_un.sysnum);
66                 handle_syscall(event);
67                 return;
68         case EVENT_SYSRET:
69                 debug(1, "event: sysret (%s [%d])",
70                       sysname(event->proc, event->e_un.sysnum),
71                       event->e_un.sysnum);
72                 handle_sysret(event);
73                 return;
74         case EVENT_ARCH_SYSCALL:
75                 debug(1, "event: arch_syscall (%s [%d])",
76                                 arch_sysname(event->proc, event->e_un.sysnum),
77                                 event->e_un.sysnum);
78                 handle_arch_syscall(event);
79                 return;
80         case EVENT_ARCH_SYSRET:
81                 debug(1, "event: arch_sysret (%s [%d])",
82                                 arch_sysname(event->proc, event->e_un.sysnum),
83                                 event->e_un.sysnum);
84                 handle_arch_sysret(event);
85                 return;
86         case EVENT_CLONE:
87                 debug(1, "event: clone (%u)", event->e_un.newpid);
88                 handle_clone(event);
89                 return;
90         case EVENT_EXEC:
91                 debug(1, "event: exec()");
92                 handle_exec(event);
93                 return;
94         case EVENT_BREAKPOINT:
95                 debug(1, "event: breakpoint");
96                 handle_breakpoint(event);
97                 return;
98         case EVENT_NEW:
99                 debug(1, "event: new process");
100                 handle_new(event);
101                 return;
102         default:
103                 fprintf(stderr, "Error! unknown event?\n");
104                 exit(1);
105         }
106 }
107
108 /* TODO */
109 static void *
110 address_clone(void * addr) {
111         debug(DEBUG_FUNCTION, "address_clone(%p)", addr);
112         return addr;
113 }
114
115 static void *
116 breakpoint_clone(void * bp) {
117         Breakpoint * b;
118         debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
119         b = malloc(sizeof(Breakpoint));
120         if (!b) {
121                 perror("malloc()");
122                 exit(1);
123         }
124         memcpy(b, bp, sizeof(Breakpoint));
125         return b;
126 }
127
128 typedef struct Pending_New Pending_New;
129 struct Pending_New {
130         pid_t pid;
131         Pending_New * next;
132 };
133 static Pending_New * pending_news = NULL;
134
135 static int
136 pending_new(pid_t pid) {
137         Pending_New * p;
138
139         debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
140
141         p = pending_news;
142         while (p) {
143                 if (p->pid == pid) {
144                         return 1;
145                 }
146                 p = p->next;
147         }
148         return 0;
149 }
150
151 static void
152 pending_new_insert(pid_t pid) {
153         Pending_New * p;
154
155         debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
156
157         p = malloc(sizeof(Pending_New));
158         if (!p) {
159                 perror("malloc()");
160                 exit(1);
161         }
162         p->pid = pid;
163         p->next = pending_news;
164         pending_news = p;
165 }
166
167 static void
168 pending_new_remove(pid_t pid) {
169         Pending_New *p, *pred;
170
171         debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
172
173         p = pending_news;
174         if (p->pid == pid) {
175                 pending_news = p->next;
176                 free(p);
177         } else {
178                 while (p) {
179                         if (p->pid == pid) {
180                                 pred->next = p->next;
181                                 free(p);
182                         }
183                         pred = p;
184                         p = p->next;
185                 }
186         }
187 }
188
189 static void
190 handle_clone(Event * event) {
191         Process *p;
192
193         debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
194
195         p = malloc(sizeof(Process));
196         if (!p) {
197                 perror("malloc()");
198                 exit(1);
199         }
200         memcpy(p, event->proc, sizeof(Process));
201         p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone);
202         p->pid = event->e_un.newpid;
203         p->parent = event->proc;
204
205         if (pending_new(p->pid)) {
206                 pending_new_remove(p->pid);
207                 if (p->breakpoint_being_enabled) {
208                         enable_breakpoint(p->pid, p->breakpoint_being_enabled);
209                         p->breakpoint_being_enabled = NULL;
210                 }
211                 if (event->proc->state == STATE_ATTACHED && options.follow) {
212                         p->state = STATE_ATTACHED;
213                 } else {
214                         p->state = STATE_IGNORED;
215                 }
216                 continue_process(p->pid);
217                 p->next = list_of_processes;
218                 list_of_processes = p;
219         } else {
220                 p->state = STATE_BEING_CREATED;
221                 p->next = list_of_processes;
222                 list_of_processes = p;
223         }
224         continue_process(event->proc->pid);
225 }
226
227 static void
228 handle_new(Event * event) {
229         Process * proc;
230
231         debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
232
233         proc = pid2proc(event->e_un.newpid);
234         if (!proc) {
235                 pending_new_insert(event->e_un.newpid);
236         } else {
237                 assert(proc->state == STATE_BEING_CREATED);
238                 if (proc->breakpoint_being_enabled) {
239                         enable_breakpoint(proc->pid, proc->breakpoint_being_enabled);
240                         proc->breakpoint_being_enabled = NULL;
241                 }
242                 if (options.follow) {
243                         proc->state = STATE_ATTACHED;
244                 } else {
245                         proc->state = STATE_IGNORED;
246                 }
247                 continue_process(proc->pid);
248         }
249 }
250
251 static char *
252 shortsignal(Process *proc, int signum) {
253         static char *signalent0[] = {
254 #include "signalent.h"
255         };
256         static char *signalent1[] = {
257 #include "signalent1.h"
258         };
259         static char **signalents[] = { signalent0, signalent1 };
260         int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
261                 sizeof signalent1 / sizeof signalent1[0]
262         };
263
264         debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
265
266         if (proc->personality > sizeof signalents / sizeof signalents[0])
267                 abort();
268         if (signum < 0 || signum >= nsignals[proc->personality]) {
269                 return "UNKNOWN_SIGNAL";
270         } else {
271                 return signalents[proc->personality][signum];
272         }
273 }
274
275 static char *
276 sysname(Process *proc, int sysnum) {
277         static char result[128];
278         static char *syscalent0[] = {
279 #include "syscallent.h"
280         };
281         static char *syscalent1[] = {
282 #include "syscallent1.h"
283         };
284         static char **syscalents[] = { syscalent0, syscalent1 };
285         int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
286                 sizeof syscalent1 / sizeof syscalent1[0]
287         };
288
289         debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
290
291         if (proc->personality > sizeof syscalents / sizeof syscalents[0])
292                 abort();
293         if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
294                 sprintf(result, "SYS_%d", sysnum);
295                 return result;
296         } else {
297                 sprintf(result, "SYS_%s",
298                         syscalents[proc->personality][sysnum]);
299                 return result;
300         }
301 }
302
303 static char *
304 arch_sysname(Process *proc, int sysnum) {
305         static char result[128];
306         static char *arch_syscalent[] = {
307 #include "arch_syscallent.h"
308         };
309         int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
310
311         debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
312
313         if (sysnum < 0 || sysnum >= nsyscals) {
314                 sprintf(result, "ARCH_%d", sysnum);
315                 return result;
316         } else {
317                 sprintf(result, "ARCH_%s",
318                                 arch_syscalent[sysnum]);
319                 return result;
320         }
321 }
322
323 static void
324 handle_signal(Event *event) {
325         debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
326         if (exiting && event->e_un.signum == SIGSTOP) {
327                 pid_t pid = event->proc->pid;
328                 disable_all_breakpoints(event->proc);
329                 untrace_pid(pid);
330                 remove_proc(event->proc);
331                 return;
332         }
333         if (event->proc->state != STATE_IGNORED) {
334                 output_line(event->proc, "--- %s (%s) ---",
335                                 shortsignal(event->proc, event->e_un.signum),
336                                 strsignal(event->e_un.signum));
337         }
338         continue_after_signal(event->proc->pid, event->e_un.signum);
339 }
340
341 static void
342 handle_exit(Event *event) {
343         debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
344         if (event->proc->state != STATE_IGNORED) {
345                 output_line(event->proc, "+++ exited (status %d) +++",
346                                 event->e_un.ret_val);
347         }
348         remove_proc(event->proc);
349 }
350
351 static void
352 handle_exit_signal(Event *event) {
353         debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
354         if (event->proc->state != STATE_IGNORED) {
355                 output_line(event->proc, "+++ killed by %s +++",
356                                 shortsignal(event->proc, event->e_un.signum));
357         }
358         remove_proc(event->proc);
359 }
360
361 static void
362 remove_proc(Process *proc) {
363         Process *tmp, *tmp2;
364
365         debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
366
367         if (list_of_processes == proc) {
368                 tmp = list_of_processes;
369                 list_of_processes = list_of_processes->next;
370                 free(tmp);
371                 return;
372         }
373         tmp = list_of_processes;
374         while (tmp->next) {
375                 if (tmp->next == proc) {
376                         tmp2 = tmp->next;
377                         tmp->next = tmp->next->next;
378                         free(tmp2);
379                         continue;
380                 }
381                 tmp = tmp->next;
382         }
383 }
384
385 static void
386 handle_syscall(Event *event) {
387         debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
388         if (event->proc->state != STATE_IGNORED) {
389                 if (options.syscalls) {
390                         output_left(LT_TOF_SYSCALL, event->proc,
391                                         sysname(event->proc, event->e_un.sysnum));
392                 }
393                 if (event->proc->breakpoints_enabled == 0) {
394                         enable_all_breakpoints(event->proc);
395                 }
396                 callstack_push_syscall(event->proc, event->e_un.sysnum);
397         }
398         continue_process(event->proc->pid);
399 }
400
401 static void
402 handle_exec(Event * event) {
403         Process * proc = event->proc;
404         pid_t saved_pid;
405
406         debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
407         if (proc->state == STATE_IGNORED) {
408                 untrace_pid(proc->pid);
409                 remove_proc(proc);
410                 return;
411         }
412         output_line(proc, "--- Called exec() ---");
413         proc->mask_32bit = 0;
414         proc->personality = 0;
415         proc->arch_ptr = NULL;
416         free(proc->filename);
417         proc->filename = pid2name(proc->pid);
418         saved_pid = proc->pid;
419         proc->pid = 0;
420         breakpoints_init(proc);
421         proc->pid = saved_pid;
422         proc->callstack_depth = 0;
423         continue_process(proc->pid);
424 }
425
426 static void
427 handle_arch_syscall(Event *event) {
428         debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
429         if (event->proc->state != STATE_IGNORED) {
430                 if (options.syscalls) {
431                         output_left(LT_TOF_SYSCALL, event->proc,
432                                         arch_sysname(event->proc, event->e_un.sysnum));
433                 }
434                 if (event->proc->breakpoints_enabled == 0) {
435                         enable_all_breakpoints(event->proc);
436                 }
437                 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
438         }
439         continue_process(event->proc->pid);
440 }
441
442 struct timeval current_time_spent;
443
444 static void
445 calc_time_spent(Process *proc) {
446         struct timeval tv;
447         struct timezone tz;
448         struct timeval diff;
449         struct callstack_element *elem;
450
451         debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
452         elem = &proc->callstack[proc->callstack_depth - 1];
453
454         gettimeofday(&tv, &tz);
455
456         diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
457         if (tv.tv_usec >= elem->time_spent.tv_usec) {
458                 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
459         } else {
460                 diff.tv_sec++;
461                 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
462         }
463         current_time_spent = diff;
464 }
465
466 static void
467 handle_sysret(Event *event) {
468         debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
469         if (event->proc->state != STATE_IGNORED) {
470                 if (opt_T || options.summary) {
471                         calc_time_spent(event->proc);
472                 }
473                 callstack_pop(event->proc);
474                 if (options.syscalls) {
475                         output_right(LT_TOF_SYSCALLR, event->proc,
476                                         sysname(event->proc, event->e_un.sysnum));
477                 }
478         }
479         continue_process(event->proc->pid);
480 }
481
482 static void
483 handle_arch_sysret(Event *event) {
484         debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
485         if (event->proc->state != STATE_IGNORED) {
486                 if (opt_T || options.summary) {
487                         calc_time_spent(event->proc);
488                 }
489                 callstack_pop(event->proc);
490                 if (options.syscalls) {
491                         output_right(LT_TOF_SYSCALLR, event->proc,
492                                         arch_sysname(event->proc, event->e_un.sysnum));
493                 }
494         }
495         continue_process(event->proc->pid);
496 }
497
498 static void
499 handle_breakpoint(Event *event) {
500         int i, j;
501         Breakpoint *sbp;
502
503         debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
504         debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
505
506 #ifdef __powerpc__
507         /* Need to skip following NOP's to prevent a fake function from being stacked.  */
508         long stub_addr = (long) get_count_register(event->proc);
509         Breakpoint *stub_bp = NULL;
510         char nop_instruction[] = PPC_NOP;
511
512         stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr);
513
514         if (stub_bp) {
515                 unsigned char *bp_instruction = stub_bp->orig_value;
516
517                 if (memcmp(bp_instruction, nop_instruction,
518                             PPC_NOP_LENGTH) == 0) {
519                         if (stub_addr != (long) event->e_un.brk_addr) {
520                                 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
521                                 continue_process(event->proc->pid);
522                                 return;
523                         }
524                 }
525         }
526 #endif
527         if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
528                 /* Reinsert breakpoint */
529                 continue_enabling_breakpoint(event->proc->pid,
530                                              event->proc->
531                                              breakpoint_being_enabled);
532                 event->proc->breakpoint_being_enabled = NULL;
533                 return;
534         }
535
536         for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
537                 if (event->e_un.brk_addr ==
538                     event->proc->callstack[i].return_addr) {
539 #ifdef __powerpc__
540                         /*
541                          * PPC HACK! (XXX FIXME TODO)
542                          * The PLT gets modified during the first call,
543                          * so be sure to re-enable the breakpoint.
544                          */
545                         unsigned long a;
546                         struct library_symbol *libsym =
547                             event->proc->callstack[i].c_un.libfunc;
548                         void *addr = sym2addr(event->proc, libsym);
549
550                         if (libsym->plt_type != LS_TOPLT_POINT) {
551                                 unsigned char break_insn[] = BREAKPOINT_VALUE;
552
553                                 sbp = address2bpstruct(event->proc, addr);
554                                 assert(sbp);
555                                 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
556                                            addr);
557
558                                 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
559                                         sbp->enabled--;
560                                         insert_breakpoint(event->proc, addr,
561                                                           libsym);
562                                 }
563                         } else {
564                                 sbp = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, libsym));
565                                 assert(sbp);
566                                 if (addr != sbp->addr) {
567                                         insert_breakpoint(event->proc, addr,
568                                                           libsym);
569                                 }
570                         }
571 #elif defined(__mips__)
572                         void *addr;
573                         void *old_addr;
574                         struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
575                         assert(sym);
576                         old_addr = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, sym))->addr;
577                         addr=sym2addr(event->proc,sym);
578                         assert(old_addr !=0 && addr !=0);
579                         if(addr != old_addr){
580                                 struct library_symbol *new_sym;
581                                 new_sym=malloc(sizeof(*new_sym));
582                                 memcpy(new_sym,sym,sizeof(*new_sym));
583                                 new_sym->next=event->proc->list_of_symbols;
584                                 event->proc->list_of_symbols=new_sym;
585                                 insert_breakpoint(event->proc, addr, new_sym);
586                         }
587 #endif
588                         for (j = event->proc->callstack_depth - 1; j > i; j--) {
589                                 callstack_pop(event->proc);
590                         }
591                         if (event->proc->state != STATE_IGNORED) {
592                                 if (opt_T || options.summary) {
593                                         calc_time_spent(event->proc);
594                                 }
595                         }
596                         callstack_pop(event->proc);
597                         event->proc->return_addr = event->e_un.brk_addr;
598                         if (event->proc->state != STATE_IGNORED) {
599                                 output_right(LT_TOF_FUNCTIONR, event->proc,
600                                                 event->proc->callstack[i].c_un.libfunc->name);
601                         }
602                         continue_after_breakpoint(event->proc,
603                                         address2bpstruct(event->proc,
604                                                 event->e_un.brk_addr));
605                         return;
606                 }
607         }
608
609         if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
610                 if (event->proc->state != STATE_IGNORED) {
611                         event->proc->stack_pointer = get_stack_pointer(event->proc);
612                         event->proc->return_addr =
613                                 get_return_addr(event->proc, event->proc->stack_pointer);
614                         output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
615                         callstack_push_symfunc(event->proc, sbp->libsym);
616                 }
617 #ifdef PLT_REINITALISATION_BP
618                 if (event->proc->need_to_reinitialize_breakpoints
619                     && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
620                         0))
621                         reinitialize_breakpoints(event->proc);
622 #endif
623
624                 continue_after_breakpoint(event->proc, sbp);
625                 return;
626         }
627
628         if (event->proc->state != STATE_IGNORED) {
629                 output_line(event->proc, "unexpected breakpoint at %p",
630                                 (void *)event->e_un.brk_addr);
631         }
632         continue_process(event->proc->pid);
633 }
634
635 static void
636 callstack_push_syscall(Process *proc, int sysnum) {
637         struct callstack_element *elem;
638
639         debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
640         /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
641         if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
642                 fprintf(stderr, "Error: call nesting too deep!\n");
643                 return;
644         }
645
646         elem = &proc->callstack[proc->callstack_depth];
647         elem->is_syscall = 1;
648         elem->c_un.syscall = sysnum;
649         elem->return_addr = NULL;
650
651         proc->callstack_depth++;
652         if (opt_T || options.summary) {
653                 struct timezone tz;
654                 gettimeofday(&elem->time_spent, &tz);
655         }
656 }
657
658 static void
659 callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
660         struct callstack_element *elem;
661
662         debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
663         /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
664         if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
665                 fprintf(stderr, "Error: call nesting too deep!\n");
666                 return;
667         }
668
669         elem = &proc->callstack[proc->callstack_depth];
670         elem->is_syscall = 0;
671         elem->c_un.libfunc = sym;
672
673         elem->return_addr = proc->return_addr;
674         if (elem->return_addr) {
675                 insert_breakpoint(proc, elem->return_addr, 0);
676         }
677
678         proc->callstack_depth++;
679         if (opt_T || options.summary) {
680                 struct timezone tz;
681                 gettimeofday(&elem->time_spent, &tz);
682         }
683 }
684
685 static void
686 callstack_pop(Process *proc) {
687         struct callstack_element *elem;
688         assert(proc->callstack_depth > 0);
689
690         debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
691         elem = &proc->callstack[proc->callstack_depth - 1];
692         if (!elem->is_syscall && elem->return_addr) {
693                 delete_breakpoint(proc, elem->return_addr);
694         }
695         proc->callstack_depth--;
696 }