handle_event.c revision ffe4cd25089680daf1bd1ec0114d177ec3e0cf95
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
574	/* The leader has terminated.  */
575	if (leader == NULL) {
576		continue_process(event->proc->pid);
577		return;
578	}
579
580	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
581	debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
582
583#ifdef __powerpc__
584	/* Need to skip following NOP's to prevent a fake function from being stacked.  */
585	long stub_addr = (long) get_count_register(event->proc);
586	Breakpoint *stub_bp = NULL;
587	char nop_instruction[] = PPC_NOP;
588
589	stub_bp = address2bpstruct(leader, event->e_un.brk_addr);
590
591	if (stub_bp) {
592		unsigned char *bp_instruction = stub_bp->orig_value;
593
594		if (memcmp(bp_instruction, nop_instruction,
595			    PPC_NOP_LENGTH) == 0) {
596			if (stub_addr != (long) event->e_un.brk_addr) {
597				set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
598				continue_process(event->proc->pid);
599				return;
600			}
601		}
602	}
603#endif
604
605	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
606		if (event->e_un.brk_addr ==
607		    event->proc->callstack[i].return_addr) {
608#ifdef __powerpc__
609			/*
610			 * PPC HACK! (XXX FIXME TODO)
611			 * The PLT gets modified during the first call,
612			 * so be sure to re-enable the breakpoint.
613			 */
614			unsigned long a;
615			struct library_symbol *libsym =
616			    event->proc->callstack[i].c_un.libfunc;
617			void *addr = sym2addr(event->proc, libsym);
618
619			if (libsym->plt_type != LS_TOPLT_POINT) {
620				unsigned char break_insn[] = BREAKPOINT_VALUE;
621
622				sbp = address2bpstruct(leader, addr);
623				assert(sbp);
624				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
625					   addr);
626
627				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
628					sbp->enabled--;
629					insert_breakpoint(event->proc, addr,
630							  libsym, 1);
631				}
632			} else {
633				sbp = dict_find_entry(leader->breakpoints, addr);
634				/* On powerpc, the breakpoint address
635				   may end up being actual entry point
636				   of the library symbol, not the PLT
637				   address we computed.  In that case,
638				   sbp is NULL.  */
639				if (sbp == NULL || addr != sbp->addr) {
640					insert_breakpoint(event->proc, addr,
641							  libsym, 1);
642				}
643			}
644#elif defined(__mips__)
645			void *addr = NULL;
646			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
647			struct library_symbol *new_sym;
648			assert(sym);
649			addr = sym2addr(event->proc, sym);
650			sbp = dict_find_entry(leader->breakpoints, addr);
651			if (sbp) {
652				if (addr != sbp->addr) {
653					insert_breakpoint(event->proc, addr, sym, 1);
654				}
655			} else {
656				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
657				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
658				new_sym->next = leader->list_of_symbols;
659				leader->list_of_symbols = new_sym;
660				insert_breakpoint(event->proc, addr, new_sym, 1);
661			}
662#endif
663			for (j = event->proc->callstack_depth - 1; j > i; j--) {
664				callstack_pop(event->proc);
665			}
666			if (event->proc->state != STATE_IGNORED) {
667				if (opt_T || options.summary) {
668					calc_time_spent(event->proc);
669				}
670			}
671			event->proc->return_addr = event->e_un.brk_addr;
672			if (event->proc->state != STATE_IGNORED) {
673				output_right(LT_TOF_FUNCTIONR, event->proc,
674						event->proc->callstack[i].c_un.libfunc->name);
675			}
676			callstack_pop(event->proc);
677			sbp = address2bpstruct(leader, event->e_un.brk_addr);
678			continue_after_breakpoint(event->proc, sbp);
679			return;
680		}
681	}
682
683	if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
684		if (sbp->libsym == NULL) {
685			continue_after_breakpoint(event->proc, sbp);
686			return;
687		}
688
689		if (strcmp(sbp->libsym->name, "") == 0) {
690			debug(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n");
691			arch_check_dbg(leader);
692		}
693
694		if (event->proc->state != STATE_IGNORED) {
695			event->proc->stack_pointer = get_stack_pointer(event->proc);
696			event->proc->return_addr =
697				get_return_addr(event->proc, event->proc->stack_pointer);
698			callstack_push_symfunc(event->proc, sbp->libsym);
699			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
700		}
701#ifdef PLT_REINITALISATION_BP
702		if (event->proc->need_to_reinitialize_breakpoints
703		    && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
704			0))
705			reinitialize_breakpoints(leader);
706#endif
707
708		continue_after_breakpoint(event->proc, sbp);
709		return;
710	}
711
712	if (event->proc->state != STATE_IGNORED && !options.no_plt) {
713		output_line(event->proc, "unexpected breakpoint at %p",
714				(void *)event->e_un.brk_addr);
715	}
716	continue_process(event->proc->pid);
717}
718
719static void
720callstack_push_syscall(Process *proc, int sysnum) {
721	struct callstack_element *elem;
722
723	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
724	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
725	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
726		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
727		abort();
728		return;
729	}
730
731	elem = &proc->callstack[proc->callstack_depth];
732	elem->is_syscall = 1;
733	elem->c_un.syscall = sysnum;
734	elem->return_addr = NULL;
735
736	proc->callstack_depth++;
737	if (opt_T || options.summary) {
738		struct timezone tz;
739		gettimeofday(&elem->time_spent, &tz);
740	}
741}
742
743static void
744callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
745	struct callstack_element *elem, *prev;
746
747	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
748	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
749	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
750		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
751		abort();
752		return;
753	}
754
755	prev = &proc->callstack[proc->callstack_depth-1];
756	elem = &proc->callstack[proc->callstack_depth];
757	elem->is_syscall = 0;
758	elem->c_un.libfunc = sym;
759
760	elem->return_addr = proc->return_addr;
761	if (elem->return_addr) {
762		insert_breakpoint(proc, elem->return_addr, NULL, 1);
763	}
764
765	/* handle functions like atexit() on mips which have no return */
766	if (elem->return_addr != prev->return_addr)
767		proc->callstack_depth++;
768	if (opt_T || options.summary) {
769		struct timezone tz;
770		gettimeofday(&elem->time_spent, &tz);
771	}
772}
773
774static void
775callstack_pop(Process *proc) {
776	struct callstack_element *elem;
777	assert(proc->callstack_depth > 0);
778
779	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
780	elem = &proc->callstack[proc->callstack_depth - 1];
781	if (!elem->is_syscall && elem->return_addr) {
782		assert(proc->leader != NULL);
783		delete_breakpoint(proc, elem->return_addr);
784	}
785	if (elem->arch_ptr != NULL) {
786		free(elem->arch_ptr);
787		elem->arch_ptr = NULL;
788	}
789	proc->callstack_depth--;
790}
791