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