handle_event.c revision 0b55b5852b9fe2ed6cceada004db303fe6efe6ce
1#define _GNU_SOURCE
2#include "config.h"
3
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#include <errno.h>
11
12#ifdef __powerpc__
13#include <sys/ptrace.h>
14#endif
15
16#include "common.h"
17#include "breakpoint.h"
18#include "proc.h"
19#include "library.h"
20
21static void handle_signal(Event *event);
22static void handle_exit(Event *event);
23static void handle_exit_signal(Event *event);
24static void handle_syscall(Event *event);
25static void handle_arch_syscall(Event *event);
26static void handle_sysret(Event *event);
27static void handle_arch_sysret(Event *event);
28static void handle_clone(Event *event);
29static void handle_exec(Event *event);
30static void handle_breakpoint(Event *event);
31static void handle_new(Event *event);
32
33static void callstack_push_syscall(Process *proc, int sysnum);
34static void callstack_push_symfunc(Process *proc,
35				   struct library_symbol *sym);
36static void callstack_pop(Process *proc);
37
38static char * shortsignal(Process *proc, int signum);
39static char * sysname(Process *proc, int sysnum);
40static char * arch_sysname(Process *proc, int sysnum);
41
42static Event *
43call_handler(Process * proc, Event * event)
44{
45	assert(proc != NULL);
46
47	struct event_handler *handler = proc->event_handler;
48	if (handler == NULL)
49		return event;
50
51	return (*handler->on_event) (handler, event);
52}
53
54void
55handle_event(Event *event)
56{
57	if (exiting == 1) {
58		debug(1, "ltrace about to exit");
59		os_ltrace_exiting();
60		exiting = 2;
61	}
62	debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)",
63	      event->proc ? event->proc->pid : -1, event->type);
64
65	/* If the thread group or an individual task define an
66	   overriding event handler, give them a chance to kick in.
67	   We will end up calling both handlers, if the first one
68	   doesn't sink the event.  */
69	if (event->proc != NULL) {
70		event = call_handler(event->proc, event);
71		if (event == NULL)
72			/* It was handled.  */
73			return;
74
75		/* Note: the previous handler has a chance to alter
76		 * the event.  */
77		if (event->proc != NULL
78		    && event->proc->leader != NULL
79		    && event->proc != event->proc->leader) {
80			event = call_handler(event->proc->leader, event);
81			if (event == NULL)
82				return;
83		}
84	}
85
86	switch (event->type) {
87	case EVENT_NONE:
88		debug(1, "event: none");
89		return;
90	case EVENT_SIGNAL:
91		debug(1, "event: signal (%s [%d])",
92		      shortsignal(event->proc, event->e_un.signum),
93		      event->e_un.signum);
94		handle_signal(event);
95		return;
96	case EVENT_EXIT:
97		debug(1, "event: exit (%d)", event->e_un.ret_val);
98		handle_exit(event);
99		return;
100	case EVENT_EXIT_SIGNAL:
101		debug(1, "event: exit signal (%s [%d])",
102		      shortsignal(event->proc, event->e_un.signum),
103		      event->e_un.signum);
104		handle_exit_signal(event);
105		return;
106	case EVENT_SYSCALL:
107		debug(1, "event: syscall (%s [%d])",
108		      sysname(event->proc, event->e_un.sysnum),
109		      event->e_un.sysnum);
110		handle_syscall(event);
111		return;
112	case EVENT_SYSRET:
113		debug(1, "event: sysret (%s [%d])",
114		      sysname(event->proc, event->e_un.sysnum),
115		      event->e_un.sysnum);
116		handle_sysret(event);
117		return;
118	case EVENT_ARCH_SYSCALL:
119		debug(1, "event: arch_syscall (%s [%d])",
120				arch_sysname(event->proc, event->e_un.sysnum),
121				event->e_un.sysnum);
122		handle_arch_syscall(event);
123		return;
124	case EVENT_ARCH_SYSRET:
125		debug(1, "event: arch_sysret (%s [%d])",
126				arch_sysname(event->proc, event->e_un.sysnum),
127				event->e_un.sysnum);
128		handle_arch_sysret(event);
129		return;
130	case EVENT_CLONE:
131	case EVENT_VFORK:
132		debug(1, "event: clone (%u)", event->e_un.newpid);
133		handle_clone(event);
134		return;
135	case EVENT_EXEC:
136		debug(1, "event: exec()");
137		handle_exec(event);
138		return;
139	case EVENT_BREAKPOINT:
140		debug(1, "event: breakpoint");
141		handle_breakpoint(event);
142		return;
143	case EVENT_NEW:
144		debug(1, "event: new process");
145		handle_new(event);
146		return;
147	default:
148		fprintf(stderr, "Error! unknown event?\n");
149		exit(1);
150	}
151}
152
153typedef struct Pending_New Pending_New;
154struct Pending_New {
155	pid_t pid;
156	Pending_New * next;
157};
158static Pending_New * pending_news = NULL;
159
160static int
161pending_new(pid_t pid) {
162	Pending_New * p;
163
164	debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
165
166	p = pending_news;
167	while (p) {
168		if (p->pid == pid) {
169			return 1;
170		}
171		p = p->next;
172	}
173	return 0;
174}
175
176static void
177pending_new_insert(pid_t pid) {
178	Pending_New * p;
179
180	debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
181
182	p = malloc(sizeof(Pending_New));
183	if (!p) {
184		perror("malloc()");
185		exit(1);
186	}
187	p->pid = pid;
188	p->next = pending_news;
189	pending_news = p;
190}
191
192static void
193pending_new_remove(pid_t pid) {
194	Pending_New *p, *pred;
195
196	debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
197
198	p = pending_news;
199	if (p->pid == pid) {
200		pending_news = p->next;
201		free(p);
202	} else {
203		while (p) {
204			if (p->pid == pid) {
205				pred->next = p->next;
206				free(p);
207			}
208			pred = p;
209			p = p->next;
210		}
211	}
212}
213
214#if 0
215static int
216clone_breakpoints(Process * proc, Process * orig_proc)
217{
218	/* When copying breakpoints, we also have to copy the
219	 * referenced symbols, and link them properly.  */
220	Dict * map = dict_init(&dict_key2hash_int, &dict_key_cmp_int);
221	struct library_symbol * it = proc->list_of_symbols;
222	proc->list_of_symbols = NULL;
223	for (; it != NULL; it = it->next) {
224		struct library_symbol * libsym = clone_library_symbol(it);
225		if (libsym == NULL) {
226			int save_errno;
227		err:
228			save_errno = errno;
229			destroy_library_symbol_chain(proc->list_of_symbols);
230			dict_clear(map);
231			errno = save_errno;
232			return -1;
233		}
234		libsym->next = proc->list_of_symbols;
235		proc->list_of_symbols = libsym;
236		if (dict_enter(map, it, libsym) != 0)
237			goto err;
238	}
239
240	proc->breakpoints = dict_clone2(orig_proc->breakpoints,
241					address_clone, breakpoint_clone, map);
242	if (proc->breakpoints == NULL)
243		goto err;
244
245	dict_clear(map);
246	return 0;
247}
248#endif
249
250static void
251handle_clone(Event *event)
252{
253	debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
254
255	struct Process *proc = malloc(sizeof(*proc));
256	if (proc == NULL) {
257	fail:
258		free(proc);
259		/* XXX proper error handling here, please.  */
260		perror("malloc()");
261		exit(1);
262	}
263
264	if (process_clone(proc, event->proc, event->e_un.newpid) < 0)
265		goto fail;
266	proc->parent = event->proc;
267
268	/* We save register values to the arch pointer, and these need
269	   to be per-thread.  */
270	proc->arch_ptr = NULL;
271
272	if (pending_new(proc->pid)) {
273		pending_new_remove(proc->pid);
274		/* XXX this used to be destroy_event_handler call, but
275		 * I don't think we want to call that on a shared
276		 * state.  */
277		proc->event_handler = NULL;
278		if (event->proc->state == STATE_ATTACHED && options.follow)
279			proc->state = STATE_ATTACHED;
280		else
281			proc->state = STATE_IGNORED;
282		continue_process(proc->pid);
283	} else {
284		proc->state = STATE_BEING_CREATED;
285	}
286	add_process(proc);
287
288	if (event->type == EVENT_VFORK)
289		continue_after_vfork(proc);
290	else
291		continue_process(event->proc->pid);
292}
293
294static void
295handle_new(Event * event) {
296	Process * proc;
297
298	debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
299
300	proc = pid2proc(event->e_un.newpid);
301	if (!proc) {
302		pending_new_insert(event->e_un.newpid);
303	} else {
304		assert(proc->state == STATE_BEING_CREATED);
305		if (options.follow) {
306			proc->state = STATE_ATTACHED;
307		} else {
308			proc->state = STATE_IGNORED;
309		}
310		continue_process(proc->pid);
311	}
312}
313
314static char *
315shortsignal(Process *proc, int signum) {
316	static char *signalent0[] = {
317#include "signalent.h"
318	};
319	static char *signalent1[] = {
320#include "signalent1.h"
321	};
322	static char **signalents[] = { signalent0, signalent1 };
323	int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
324		sizeof signalent1 / sizeof signalent1[0]
325	};
326
327	debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
328
329	if (proc->personality > sizeof signalents / sizeof signalents[0])
330		abort();
331	if (signum < 0 || signum >= nsignals[proc->personality]) {
332		return "UNKNOWN_SIGNAL";
333	} else {
334		return signalents[proc->personality][signum];
335	}
336}
337
338static char *
339sysname(Process *proc, int sysnum) {
340	static char result[128];
341	static char *syscalent0[] = {
342#include "syscallent.h"
343	};
344	static char *syscalent1[] = {
345#include "syscallent1.h"
346	};
347	static char **syscalents[] = { syscalent0, syscalent1 };
348	int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
349		sizeof syscalent1 / sizeof syscalent1[0]
350	};
351
352	debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
353
354	if (proc->personality > sizeof syscalents / sizeof syscalents[0])
355		abort();
356	if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
357		sprintf(result, "SYS_%d", sysnum);
358		return result;
359	} else {
360		sprintf(result, "SYS_%s",
361			syscalents[proc->personality][sysnum]);
362		return result;
363	}
364}
365
366static char *
367arch_sysname(Process *proc, int sysnum) {
368	static char result[128];
369	static char *arch_syscalent[] = {
370#include "arch_syscallent.h"
371	};
372	int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
373
374	debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
375
376	if (sysnum < 0 || sysnum >= nsyscals) {
377		sprintf(result, "ARCH_%d", sysnum);
378		return result;
379	} else {
380		sprintf(result, "ARCH_%s",
381				arch_syscalent[sysnum]);
382		return result;
383	}
384}
385
386static void
387handle_signal(Event *event) {
388	debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
389	if (event->proc->state != STATE_IGNORED && !options.no_signals) {
390		output_line(event->proc, "--- %s (%s) ---",
391				shortsignal(event->proc, event->e_un.signum),
392				strsignal(event->e_un.signum));
393	}
394	continue_after_signal(event->proc->pid, event->e_un.signum);
395}
396
397static void
398handle_exit(Event *event) {
399	debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
400	if (event->proc->state != STATE_IGNORED) {
401		output_line(event->proc, "+++ exited (status %d) +++",
402				event->e_un.ret_val);
403	}
404	remove_process(event->proc);
405	free(event->proc);
406}
407
408static void
409handle_exit_signal(Event *event) {
410	debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
411	if (event->proc->state != STATE_IGNORED) {
412		output_line(event->proc, "+++ killed by %s +++",
413				shortsignal(event->proc, event->e_un.signum));
414	}
415	remove_process(event->proc);
416	free(event->proc);
417}
418
419static struct library_symbol *
420temporary_syscall_symbol(const char *name)
421{
422	struct library *syscalls = malloc(sizeof(*syscalls));
423	struct library_symbol *syscall = malloc(sizeof(*syscall));
424	if (syscalls == NULL || syscall == NULL) {
425		free(syscalls);
426		free(syscall);
427		return NULL;
428	}
429	library_init(syscalls);
430	library_set_soname(syscalls, "SYS", 0);
431	library_symbol_init(syscall, 0, name, 0, LS_TOPLT_NONE);
432	library_add_symbol(syscalls, syscall);
433	return syscall;
434}
435
436static void
437output_syscall_left(struct Process *proc, const char *name)
438{
439	struct library_symbol *syscall = temporary_syscall_symbol(name);
440	output_left(LT_TOF_SYSCALL, proc, syscall);
441	struct library *lib = syscall->lib;
442	library_destroy(lib);
443	free(lib);
444}
445
446static void
447output_syscall_right(struct Process *proc, const char *name)
448{
449	struct library_symbol *syscall = temporary_syscall_symbol(name);
450	output_right(LT_TOF_SYSCALLR, proc, syscall);
451	struct library *lib = syscall->lib;
452	library_destroy(lib);
453	free(lib);
454}
455
456static void
457handle_syscall(Event *event) {
458	debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
459	if (event->proc->state != STATE_IGNORED) {
460		callstack_push_syscall(event->proc, event->e_un.sysnum);
461		if (options.syscalls)
462			output_syscall_left(event->proc,
463					    sysname(event->proc,
464						    event->e_un.sysnum));
465	}
466	continue_after_syscall(event->proc, event->e_un.sysnum, 0);
467}
468
469static void
470handle_exec(Event * event) {
471	Process * proc = event->proc;
472
473	debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
474	if (proc->state == STATE_IGNORED) {
475		untrace_pid(proc->pid);
476		remove_process(proc);
477		free(proc);
478		return;
479	}
480	output_line(proc, "--- Called exec() ---");
481	proc->mask_32bit = 0;
482	proc->personality = 0;
483	proc->arch_ptr = NULL;
484	free(proc->filename);
485	proc->filename = pid2name(proc->pid);
486	breakpoints_init(proc, 0);
487	proc->callstack_depth = 0;
488	continue_process(proc->pid);
489}
490
491static void
492handle_arch_syscall(Event *event) {
493	debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
494	if (event->proc->state != STATE_IGNORED) {
495		callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
496		if (options.syscalls) {
497			output_syscall_left(event->proc,
498					    arch_sysname(event->proc,
499							 event->e_un.sysnum));
500		}
501	}
502	continue_process(event->proc->pid);
503}
504
505struct timeval current_time_spent;
506
507static void
508calc_time_spent(Process *proc) {
509	struct timeval tv;
510	struct timezone tz;
511	struct timeval diff;
512	struct callstack_element *elem;
513
514	debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
515	elem = &proc->callstack[proc->callstack_depth - 1];
516
517	gettimeofday(&tv, &tz);
518
519	diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
520	if (tv.tv_usec >= elem->time_spent.tv_usec) {
521		diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
522	} else {
523		diff.tv_sec++;
524		diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
525	}
526	current_time_spent = diff;
527}
528
529static void
530handle_sysret(Event *event) {
531	debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
532	if (event->proc->state != STATE_IGNORED) {
533		if (opt_T || options.summary) {
534			calc_time_spent(event->proc);
535		}
536		if (options.syscalls)
537			output_syscall_right(event->proc,
538					     sysname(event->proc,
539						     event->e_un.sysnum));
540
541		assert(event->proc->callstack_depth > 0);
542		unsigned d = event->proc->callstack_depth - 1;
543		assert(event->proc->callstack[d].is_syscall);
544		callstack_pop(event->proc);
545	}
546	continue_after_syscall(event->proc, event->e_un.sysnum, 1);
547}
548
549static void
550handle_arch_sysret(Event *event) {
551	debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
552	if (event->proc->state != STATE_IGNORED) {
553		if (opt_T || options.summary) {
554			calc_time_spent(event->proc);
555		}
556		if (options.syscalls)
557			output_syscall_right(event->proc,
558					     arch_sysname(event->proc,
559							  event->e_un.sysnum));
560		callstack_pop(event->proc);
561	}
562	continue_process(event->proc->pid);
563}
564
565static void
566output_right_tos(struct Process *proc)
567{
568	size_t d = proc->callstack_depth;
569	struct callstack_element *elem = &proc->callstack[d - 1];
570	if (proc->state != STATE_IGNORED)
571		output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc->name);
572}
573
574static void
575handle_breakpoint(Event *event)
576{
577	int i, j;
578	struct breakpoint *sbp;
579	Process *leader = event->proc->leader;
580	void *brk_addr = event->e_un.brk_addr;
581
582	/* The leader has terminated.  */
583	if (leader == NULL) {
584		continue_process(event->proc->pid);
585		return;
586	}
587
588	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)",
589	      event->proc->pid, brk_addr);
590	debug(2, "event: breakpoint (%p)", brk_addr);
591
592	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
593		if (brk_addr == event->proc->callstack[i].return_addr) {
594#ifdef __powerpc__
595			/*
596			 * PPC HACK! (XXX FIXME TODO)
597			 * The PLT gets modified during the first call,
598			 * so be sure to re-enable the breakpoint.
599			 */
600			unsigned long a;
601			struct library_symbol *libsym =
602			    event->proc->callstack[i].c_un.libfunc;
603			void *addr = sym2addr(event->proc, libsym);
604
605			if (libsym->plt_type != LS_TOPLT_POINT) {
606				unsigned char break_insn[] = BREAKPOINT_VALUE;
607
608				sbp = address2bpstruct(leader, addr);
609				assert(sbp);
610				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
611					   addr);
612
613				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
614					sbp->enabled--;
615					insert_breakpoint(event->proc, addr,
616							  libsym);
617				}
618			} else {
619				sbp = dict_find_entry(leader->breakpoints, addr);
620				/* On powerpc, the breakpoint address
621				   may end up being actual entry point
622				   of the library symbol, not the PLT
623				   address we computed.  In that case,
624				   sbp is NULL.  */
625				if (sbp == NULL || addr != sbp->addr) {
626					insert_breakpoint(event->proc, addr,
627							  libsym);
628				}
629			}
630#elif defined(__mips__)
631			void *addr = NULL;
632			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
633			struct library_symbol *new_sym;
634			assert(sym);
635			addr = sym2addr(event->proc, sym);
636			sbp = dict_find_entry(leader->breakpoints, addr);
637			if (sbp) {
638				if (addr != sbp->addr) {
639					insert_breakpoint(event->proc, addr, sym);
640				}
641			} else {
642				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
643				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
644				new_sym->next = leader->list_of_symbols;
645				leader->list_of_symbols = new_sym;
646				insert_breakpoint(event->proc, addr, new_sym);
647			}
648#endif
649			for (j = event->proc->callstack_depth - 1; j > i; j--) {
650				callstack_pop(event->proc);
651			}
652			if (event->proc->state != STATE_IGNORED) {
653				if (opt_T || options.summary) {
654					calc_time_spent(event->proc);
655				}
656			}
657			event->proc->return_addr = brk_addr;
658
659			output_right_tos(event->proc);
660			callstack_pop(event->proc);
661
662			/* Pop also any other entries that seem like
663			 * they are linked to the current one: they
664			 * have the same return address, but were made
665			 * for different symbols.  This should only
666			 * happen for entry point tracing, i.e. for -x
667			 * everywhere, or -x and -e on PPC64.  */
668			while (event->proc->callstack_depth > 0) {
669				struct callstack_element *prev;
670				size_t d = event->proc->callstack_depth;
671				prev = &event->proc->callstack[d - 1];
672
673				if (prev->c_un.libfunc == libsym
674				    || prev->return_addr != brk_addr)
675					break;
676
677				output_right_tos(event->proc);
678				callstack_pop(event->proc);
679			}
680
681			sbp = address2bpstruct(leader, brk_addr);
682			continue_after_breakpoint(event->proc, sbp);
683			return;
684		}
685	}
686
687	if ((sbp = address2bpstruct(leader, brk_addr))) {
688		breakpoint_on_hit(sbp, event->proc);
689
690		if (event->proc->state != STATE_IGNORED
691		    && sbp->libsym != NULL) {
692			event->proc->stack_pointer = get_stack_pointer(event->proc);
693			event->proc->return_addr =
694				get_return_addr(event->proc, event->proc->stack_pointer);
695			callstack_push_symfunc(event->proc, sbp->libsym);
696			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym);
697		}
698
699		breakpoint_on_continue(sbp, event->proc);
700		return;
701	}
702
703	if (event->proc->state != STATE_IGNORED && !options.no_plt) {
704		output_line(event->proc, "unexpected breakpoint at %p",
705			    brk_addr);
706	}
707	continue_process(event->proc->pid);
708}
709
710static void
711callstack_push_syscall(Process *proc, int sysnum) {
712	struct callstack_element *elem;
713
714	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
715	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
716	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
717		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
718		abort();
719		return;
720	}
721
722	elem = &proc->callstack[proc->callstack_depth];
723	elem->is_syscall = 1;
724	elem->c_un.syscall = sysnum;
725	elem->return_addr = NULL;
726
727	proc->callstack_depth++;
728	if (opt_T || options.summary) {
729		struct timezone tz;
730		gettimeofday(&elem->time_spent, &tz);
731	}
732}
733
734static void
735callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
736	struct callstack_element *elem;
737
738	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
739	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
740	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
741		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
742		abort();
743		return;
744	}
745
746	elem = &proc->callstack[proc->callstack_depth++];
747	elem->is_syscall = 0;
748	elem->c_un.libfunc = sym;
749
750	elem->return_addr = proc->return_addr;
751	if (elem->return_addr)
752		insert_breakpoint(proc, elem->return_addr, NULL);
753
754	/* handle functions like atexit() on mips which have no return */
755	if (opt_T || options.summary) {
756		struct timezone tz;
757		gettimeofday(&elem->time_spent, &tz);
758	}
759}
760
761static void
762callstack_pop(Process *proc) {
763	struct callstack_element *elem;
764	assert(proc->callstack_depth > 0);
765
766	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
767	elem = &proc->callstack[proc->callstack_depth - 1];
768	if (!elem->is_syscall && elem->return_addr) {
769		assert(proc->leader != NULL);
770		delete_breakpoint(proc, elem->return_addr);
771	}
772	if (elem->arch_ptr != NULL) {
773		free(elem->arch_ptr);
774		elem->arch_ptr = NULL;
775	}
776	proc->callstack_depth--;
777}
778