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