handle_event.c revision 2662768efe599f6bb43c4310177e30f56b601bb7
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->pid, 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->pid, 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		continue_enabling_breakpoint(event->proc->pid,
535					     event->proc->
536					     breakpoint_being_enabled);
537		event->proc->breakpoint_being_enabled = NULL;
538		return;
539	}
540
541	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
542		if (event->e_un.brk_addr ==
543		    event->proc->callstack[i].return_addr) {
544#ifdef __powerpc__
545			/*
546			 * PPC HACK! (XXX FIXME TODO)
547			 * The PLT gets modified during the first call,
548			 * so be sure to re-enable the breakpoint.
549			 */
550			unsigned long a;
551			struct library_symbol *libsym =
552			    event->proc->callstack[i].c_un.libfunc;
553			void *addr = sym2addr(event->proc, libsym);
554
555			if (libsym->plt_type != LS_TOPLT_POINT) {
556				unsigned char break_insn[] = BREAKPOINT_VALUE;
557
558				sbp = address2bpstruct(event->proc, addr);
559				assert(sbp);
560				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
561					   addr);
562
563				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
564					sbp->enabled--;
565					insert_breakpoint(event->proc, addr,
566							  libsym);
567				}
568			} else {
569				sbp = dict_find_entry(event->proc->breakpoints, addr);
570				/* On powerpc, the breakpoint address
571				   may end up being actual entry point
572				   of the library symbol, not the PLT
573				   address we computed.  In that case,
574				   sbp is NULL.  */
575				if (sbp == NULL || addr != sbp->addr) {
576					insert_breakpoint(event->proc, addr,
577							  libsym);
578				}
579			}
580#elif defined(__mips__)
581			void *addr = NULL;
582			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
583			struct library_symbol *new_sym;
584			assert(sym);
585			addr = sym2addr(event->proc, sym);
586			sbp = dict_find_entry(event->proc->breakpoints, addr);
587			if (sbp) {
588				if (addr != sbp->addr) {
589					insert_breakpoint(event->proc, addr, sym);
590				}
591			} else {
592				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
593				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
594				new_sym->next = leader->list_of_symbols;
595				event->proc->list_of_symbols = new_sym;
596				insert_breakpoint(event->proc, addr, new_sym);
597			}
598#endif
599			for (j = event->proc->callstack_depth - 1; j > i; j--) {
600				callstack_pop(event->proc);
601			}
602			if (event->proc->state != STATE_IGNORED) {
603				if (opt_T || options.summary) {
604					calc_time_spent(event->proc);
605				}
606			}
607			event->proc->return_addr = event->e_un.brk_addr;
608			if (event->proc->state != STATE_IGNORED) {
609				output_right(LT_TOF_FUNCTIONR, event->proc,
610						event->proc->callstack[i].c_un.libfunc->name);
611			}
612			callstack_pop(event->proc);
613			continue_after_breakpoint(event->proc,
614					address2bpstruct(event->proc,
615						event->e_un.brk_addr));
616			return;
617		}
618	}
619
620	if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
621		if (strcmp(sbp->libsym->name, "") == 0) {
622			debug(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n");
623			arch_check_dbg(event->proc);
624		}
625		if (event->proc->state != STATE_IGNORED) {
626			event->proc->stack_pointer = get_stack_pointer(event->proc);
627			event->proc->return_addr =
628				get_return_addr(event->proc, event->proc->stack_pointer);
629			callstack_push_symfunc(event->proc, sbp->libsym);
630			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
631		}
632#ifdef PLT_REINITALISATION_BP
633		if (event->proc->need_to_reinitialize_breakpoints
634		    && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
635			0))
636			reinitialize_breakpoints(event->proc);
637#endif
638
639		continue_after_breakpoint(event->proc, sbp);
640		return;
641	}
642
643	if (event->proc->state != STATE_IGNORED && !options.no_plt) {
644		output_line(event->proc, "unexpected breakpoint at %p",
645				(void *)event->e_un.brk_addr);
646	}
647	continue_process(event->proc->pid);
648}
649
650static void
651callstack_push_syscall(Process *proc, int sysnum) {
652	struct callstack_element *elem;
653
654	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
655	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
656	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
657		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
658		abort();
659		return;
660	}
661
662	elem = &proc->callstack[proc->callstack_depth];
663	elem->is_syscall = 1;
664	elem->c_un.syscall = sysnum;
665	elem->return_addr = NULL;
666
667	proc->callstack_depth++;
668	if (opt_T || options.summary) {
669		struct timezone tz;
670		gettimeofday(&elem->time_spent, &tz);
671	}
672}
673
674static void
675callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
676	struct callstack_element *elem, *prev;
677
678	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
679	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
680	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
681		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
682		abort();
683		return;
684	}
685
686	prev = &proc->callstack[proc->callstack_depth-1];
687	elem = &proc->callstack[proc->callstack_depth];
688	elem->is_syscall = 0;
689	elem->c_un.libfunc = sym;
690
691	elem->return_addr = proc->return_addr;
692	if (elem->return_addr) {
693		insert_breakpoint(proc, elem->return_addr, NULL);
694	}
695
696	/* handle functions like atexit() on mips which have no return */
697	if (elem->return_addr != prev->return_addr)
698		proc->callstack_depth++;
699	if (opt_T || options.summary) {
700		struct timezone tz;
701		gettimeofday(&elem->time_spent, &tz);
702	}
703}
704
705static void
706callstack_pop(Process *proc) {
707	struct callstack_element *elem;
708	assert(proc->callstack_depth > 0);
709
710	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
711	elem = &proc->callstack[proc->callstack_depth - 1];
712	if (!elem->is_syscall && elem->return_addr) {
713		delete_breakpoint(proc, elem->return_addr);
714	}
715	if (elem->arch_ptr != NULL) {
716		free(elem->arch_ptr);
717		elem->arch_ptr = NULL;
718	}
719	proc->callstack_depth--;
720}
721