1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2010 Arnaud Patard, Mandriva SA
5 * Copyright (C) 1998,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
6 * Copyright (C) 2008 Luis Machado, IBM Corporation
7 * Copyright (C) 2006 Ian Wienand
8 * Copyright (C) 2006 Paul Gilliam, IBM Corporation
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include "config.h"
27
28#define _GNU_SOURCE
29#include <assert.h>
30#include <errno.h>
31#include <signal.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
36
37#include "backend.h"
38#include "breakpoint.h"
39#include "common.h"
40#include "fetch.h"
41#include "library.h"
42#include "proc.h"
43#include "prototype.h"
44#include "summary.h"
45#include "value_dict.h"
46
47static void handle_signal(Event *event);
48static void handle_exit(Event *event);
49static void handle_exit_signal(Event *event);
50static void handle_syscall(Event *event);
51static void handle_arch_syscall(Event *event);
52static void handle_sysret(Event *event);
53static void handle_arch_sysret(Event *event);
54static void handle_clone(Event *event);
55static void handle_exec(Event *event);
56static void handle_breakpoint(Event *event);
57static void handle_new(Event *event);
58
59static void callstack_push_syscall(struct process *proc, int sysnum);
60static void callstack_push_symfunc(struct process *proc, struct breakpoint *bp);
61/* XXX Stack maintenance should be moved to a dedicated module, or to
62 * proc.c, and push/pop should be visible outside this module.  For
63 * now, because we need this in proc.c, this is non-static.  */
64void callstack_pop(struct process *proc);
65
66static char *shortsignal(struct process *proc, int signum);
67static char *sysname(struct process *proc, int sysnum);
68static char *arch_sysname(struct process *proc, int sysnum);
69
70static Event *
71call_handler(struct process *proc, Event *event)
72{
73	assert(proc != NULL);
74
75	struct event_handler *handler = proc->event_handler;
76	if (handler == NULL)
77		return event;
78
79	return (*handler->on_event) (handler, event);
80}
81
82void
83handle_event(Event *event)
84{
85	if (exiting == 1) {
86		debug(1, "ltrace about to exit");
87		os_ltrace_exiting();
88		exiting = 2;
89	}
90	debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)",
91	      event->proc ? event->proc->pid : -1, event->type);
92
93	/* If the thread group or an individual task define an
94	   overriding event handler, give them a chance to kick in.
95	   We will end up calling both handlers, if the first one
96	   doesn't sink the event.  */
97	if (event->proc != NULL) {
98		event = call_handler(event->proc, event);
99		if (event == NULL)
100			/* It was handled.  */
101			return;
102
103		/* Note: the previous handler has a chance to alter
104		 * the event.  */
105		if (event->proc != NULL
106		    && event->proc->leader != NULL
107		    && event->proc != event->proc->leader) {
108			event = call_handler(event->proc->leader, event);
109			if (event == NULL)
110				return;
111		}
112	}
113
114	switch (event->type) {
115	case EVENT_NONE:
116		debug(1, "event: none");
117		return;
118
119	case EVENT_SIGNAL:
120		assert(event->proc != NULL);
121		debug(1, "[%d] event: signal (%s [%d])",
122		      event->proc->pid,
123		      shortsignal(event->proc, event->e_un.signum),
124		      event->e_un.signum);
125		handle_signal(event);
126		return;
127
128	case EVENT_EXIT:
129		assert(event->proc != NULL);
130		debug(1, "[%d] event: exit (%d)",
131		      event->proc->pid,
132		      event->e_un.ret_val);
133		handle_exit(event);
134		return;
135
136	case EVENT_EXIT_SIGNAL:
137		assert(event->proc != NULL);
138		debug(1, "[%d] event: exit signal (%s [%d])",
139		      event->proc->pid,
140		      shortsignal(event->proc, event->e_un.signum),
141		      event->e_un.signum);
142		handle_exit_signal(event);
143		return;
144
145	case EVENT_SYSCALL:
146		assert(event->proc != NULL);
147		debug(1, "[%d] event: syscall (%s [%d])",
148		      event->proc->pid,
149		      sysname(event->proc, event->e_un.sysnum),
150		      event->e_un.sysnum);
151		handle_syscall(event);
152		return;
153
154	case EVENT_SYSRET:
155		assert(event->proc != NULL);
156		debug(1, "[%d] event: sysret (%s [%d])",
157		      event->proc->pid,
158		      sysname(event->proc, event->e_un.sysnum),
159		      event->e_un.sysnum);
160		handle_sysret(event);
161		return;
162
163	case EVENT_ARCH_SYSCALL:
164		assert(event->proc != NULL);
165		debug(1, "[%d] event: arch_syscall (%s [%d])",
166		      event->proc->pid,
167		      arch_sysname(event->proc, event->e_un.sysnum),
168		      event->e_un.sysnum);
169		handle_arch_syscall(event);
170		return;
171
172	case EVENT_ARCH_SYSRET:
173		assert(event->proc != NULL);
174		debug(1, "[%d] event: arch_sysret (%s [%d])",
175		      event->proc->pid,
176		      arch_sysname(event->proc, event->e_un.sysnum),
177		      event->e_un.sysnum);
178		handle_arch_sysret(event);
179		return;
180
181	case EVENT_CLONE:
182	case EVENT_VFORK:
183		assert(event->proc != NULL);
184		debug(1, "[%d] event: clone (%u)",
185		      event->proc->pid, event->e_un.newpid);
186		handle_clone(event);
187		return;
188
189	case EVENT_EXEC:
190		assert(event->proc != NULL);
191		debug(1, "[%d] event: exec()",
192		      event->proc->pid);
193		handle_exec(event);
194		return;
195
196	case EVENT_BREAKPOINT:
197		assert(event->proc != NULL);
198		debug(1, "[%d] event: breakpoint %p",
199		      event->proc->pid, event->e_un.brk_addr);
200		handle_breakpoint(event);
201		return;
202
203	case EVENT_NEW:
204		debug(1, "[%d] event: new process",
205		      event->e_un.newpid);
206		handle_new(event);
207		return;
208	default:
209		fprintf(stderr, "Error! unknown event?\n");
210		exit(1);
211	}
212}
213
214typedef struct Pending_New Pending_New;
215struct Pending_New {
216	pid_t pid;
217	Pending_New * next;
218};
219static Pending_New * pending_news = NULL;
220
221static int
222pending_new(pid_t pid) {
223	Pending_New * p;
224
225	debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
226
227	p = pending_news;
228	while (p) {
229		if (p->pid == pid) {
230			return 1;
231		}
232		p = p->next;
233	}
234	return 0;
235}
236
237static void
238pending_new_insert(pid_t pid) {
239	Pending_New * p;
240
241	debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
242
243	p = malloc(sizeof(Pending_New));
244	if (!p) {
245		perror("malloc()");
246		exit(1);
247	}
248	p->pid = pid;
249	p->next = pending_news;
250	pending_news = p;
251}
252
253static void
254pending_new_remove(pid_t pid)
255{
256	debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
257
258	Pending_New **pp;
259	for (pp = &pending_news; *pp != NULL; pp = &(*pp)->next)
260		if ((*pp)->pid == pid) {
261			Pending_New *p = *pp;
262			*pp = p->next;
263			free(p);
264			return;
265		}
266}
267
268static void
269handle_clone(Event *event)
270{
271	debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
272
273	struct process *proc = malloc(sizeof(*proc));
274	pid_t newpid = event->e_un.newpid;
275	if (proc == NULL
276	    || process_clone(proc, event->proc, newpid) < 0) {
277		free(proc);
278		proc = NULL;
279		fprintf(stderr,
280			"Couldn't initialize tracing of process %d.\n",
281			newpid);
282
283	} else {
284		proc->parent = event->proc;
285		/* We save register values to the arch pointer, and
286		 * these need to be per-thread.  XXX arch_ptr should
287		 * be retired in favor of fetch interface anyway.  */
288		proc->arch_ptr = NULL;
289	}
290
291	if (pending_new(newpid)) {
292		pending_new_remove(newpid);
293
294		if (proc != NULL) {
295			proc->event_handler = NULL;
296			if (event->proc->state == STATE_ATTACHED
297			    && options.follow)
298				proc->state = STATE_ATTACHED;
299			else
300				proc->state = STATE_IGNORED;
301		}
302
303		continue_process(newpid);
304
305	} else if (proc != NULL) {
306		proc->state = STATE_BEING_CREATED;
307	}
308
309	if (event->type != EVENT_VFORK)
310		continue_process(event->proc->pid);
311	else if (proc != NULL)
312		continue_after_vfork(proc);
313	else
314		continue_process(newpid);
315}
316
317static void
318handle_new(Event *event)
319{
320	debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
321
322	struct process *proc = pid2proc(event->e_un.newpid);
323	if (!proc) {
324		pending_new_insert(event->e_un.newpid);
325	} else {
326		assert(proc->state == STATE_BEING_CREATED);
327		if (options.follow) {
328			proc->state = STATE_ATTACHED;
329		} else {
330			proc->state = STATE_IGNORED;
331		}
332		continue_process(proc->pid);
333	}
334}
335
336static char *
337shortsignal(struct process *proc, int signum)
338{
339	static char *signalent0[] = {
340#include "signalent.h"
341	};
342	static char *signalent1[] = {
343#include "signalent1.h"
344	};
345	static char **signalents[] = { signalent0, signalent1 };
346	int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
347		sizeof signalent1 / sizeof signalent1[0]
348	};
349
350	debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
351
352	assert(proc->personality < sizeof signalents / sizeof signalents[0]);
353	if (signum < 0 || signum >= nsignals[proc->personality]) {
354		return "UNKNOWN_SIGNAL";
355	} else {
356		return signalents[proc->personality][signum];
357	}
358}
359
360static char *
361sysname(struct process *proc, int sysnum)
362{
363	static char result[128];
364	static char *syscallent0[] = {
365#include "syscallent.h"
366	};
367	static char *syscallent1[] = {
368#include "syscallent1.h"
369	};
370	static char **syscallents[] = { syscallent0, syscallent1 };
371	int nsyscalls[] = {
372		sizeof syscallent0 / sizeof syscallent0[0],
373		sizeof syscallent1 / sizeof syscallent1[0],
374	};
375
376	debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
377
378	assert(proc->personality < sizeof syscallents / sizeof syscallents[0]);
379	if (sysnum < 0 || sysnum >= nsyscalls[proc->personality]) {
380		sprintf(result, "SYS_%d", sysnum);
381		return result;
382	} else {
383		return syscallents[proc->personality][sysnum];
384	}
385}
386
387static char *
388arch_sysname(struct process *proc, int sysnum)
389{
390	static char result[128];
391	static char *arch_syscallent[] = {
392#include "arch_syscallent.h"
393	};
394	int nsyscalls = sizeof arch_syscallent / sizeof arch_syscallent[0];
395
396	debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
397
398	if (sysnum < 0 || sysnum >= nsyscalls) {
399		sprintf(result, "ARCH_%d", sysnum);
400		return result;
401	} else {
402		sprintf(result, "ARCH_%s", arch_syscallent[sysnum]);
403		return result;
404	}
405}
406
407#ifndef HAVE_STRSIGNAL
408# define strsignal(SIGNUM) "???"
409#endif
410
411static void
412handle_signal(Event *event) {
413	debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
414	if (event->proc->state != STATE_IGNORED && !options.no_signals) {
415		output_line(event->proc, "--- %s (%s) ---",
416				shortsignal(event->proc, event->e_un.signum),
417				strsignal(event->e_un.signum));
418	}
419	continue_after_signal(event->proc->pid, event->e_un.signum);
420}
421
422static int
423init_syscall_symbol(struct library_symbol *libsym, const char *name)
424{
425	static struct library syscall_lib;
426
427	if (syscall_lib.protolib == NULL) {
428		struct protolib *protolib
429			= protolib_cache_load(&g_protocache, "syscalls", 0, 1);
430		if (protolib == NULL) {
431			fprintf(stderr, "Couldn't load system call prototypes:"
432				" %s.\n", strerror(errno));
433
434			/* Instead, get a fake one just so we can
435			 * carry on, limping.  */
436			protolib = malloc(sizeof *protolib);
437			if (protolib == NULL) {
438				fprintf(stderr, "Couldn't even allocate a fake "
439					"prototype library: %s.\n",
440					strerror(errno));
441				abort();
442			}
443			protolib_init(protolib);
444		}
445
446		assert(protolib != NULL);
447		if (library_init(&syscall_lib, LT_LIBTYPE_SYSCALL) < 0) {
448			fprintf(stderr, "Couldn't initialize system call "
449				"library: %s.\n", strerror(errno));
450			abort();
451		}
452
453		library_set_soname(&syscall_lib, "SYS", 0);
454		syscall_lib.protolib = protolib;
455	}
456
457	if (library_symbol_init(libsym, 0, name, 0, LS_TOPLT_NONE) < 0)
458		return -1;
459
460	libsym->lib = &syscall_lib;
461	return 0;
462}
463
464/* Account the unfinished functions on the call stack.  */
465static void
466account_current_callstack(struct process *proc)
467{
468	if (! options.summary)
469		return;
470
471	struct timedelta spent[proc->callstack_depth];
472
473	size_t i;
474	for (i = 0; i < proc->callstack_depth; ++i) {
475		struct callstack_element *elem = &proc->callstack[i];
476		spent[i] = calc_time_spent(elem->enter_time);
477	}
478
479	for (i = 0; i < proc->callstack_depth; ++i) {
480		struct callstack_element *elem = &proc->callstack[i];
481		struct library_symbol syscall, *libsym = NULL;
482		if (elem->is_syscall) {
483			const char *name = sysname(proc, elem->c_un.syscall);
484			if (init_syscall_symbol(&syscall, name) >= 0)
485				libsym = &syscall;
486
487		} else {
488			libsym = elem->c_un.libfunc;
489		}
490
491		if (libsym != NULL) {
492			summary_account_call(libsym, spent[i]);
493
494			if (elem->is_syscall)
495				library_symbol_destroy(&syscall);
496		}
497	}
498}
499
500static void
501handle_exit(Event *event) {
502	debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
503	if (event->proc->state != STATE_IGNORED) {
504		output_line(event->proc, "+++ exited (status %d) +++",
505				event->e_un.ret_val);
506	}
507
508	account_current_callstack(event->proc);
509	remove_process(event->proc);
510}
511
512static void
513handle_exit_signal(Event *event) {
514	debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
515	if (event->proc->state != STATE_IGNORED) {
516		output_line(event->proc, "+++ killed by %s +++",
517				shortsignal(event->proc, event->e_un.signum));
518	}
519
520	account_current_callstack(event->proc);
521	remove_process(event->proc);
522}
523
524static void
525output_syscall(struct process *proc, const char *name, enum tof tof,
526	       bool left, struct timedelta *spent)
527{
528	if (left)
529		assert(spent == NULL);
530
531	struct library_symbol syscall;
532	if (init_syscall_symbol(&syscall, name) >= 0) {
533		if (left) {
534			if (! options.summary)
535				output_left(tof, proc, &syscall);
536		} else if (options.summary) {
537			summary_account_call(&syscall, *spent);
538		} else {
539			output_right(tof, proc, &syscall, spent);
540		}
541
542		library_symbol_destroy(&syscall);
543	}
544}
545
546static void
547output_syscall_left(struct process *proc, const char *name)
548{
549	output_syscall(proc, name, LT_TOF_SYSCALL, true, NULL);
550}
551
552static void
553output_syscall_right(struct process *proc, const char *name,
554		     struct timedelta *spent)
555{
556	output_syscall(proc, name, LT_TOF_SYSCALLR, false, spent);
557}
558
559static void
560handle_syscall(Event *event)
561{
562	debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
563	if (event->proc->state != STATE_IGNORED) {
564		callstack_push_syscall(event->proc, event->e_un.sysnum);
565		if (options.syscalls)
566			output_syscall_left(event->proc,
567					    sysname(event->proc,
568						    event->e_un.sysnum));
569	}
570	continue_after_syscall(event->proc, event->e_un.sysnum, 0);
571}
572
573static void
574handle_exec(Event *event)
575{
576	struct process *proc = event->proc;
577
578	/* Save the PID so that we can use it after unsuccessful
579	 * process_exec.  */
580	pid_t pid = proc->pid;
581
582	debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
583	if (proc->state == STATE_IGNORED) {
584	untrace:
585		untrace_pid(pid);
586		remove_process(proc);
587		return;
588	}
589	output_line(proc, "--- Called exec() ---");
590
591	account_current_callstack(proc);
592
593	if (process_exec(proc) < 0) {
594		fprintf(stderr,
595			"couldn't reinitialize process %d after exec\n", pid);
596		goto untrace;
597	}
598
599	continue_after_exec(proc);
600}
601
602static void
603handle_arch_syscall(Event *event) {
604	debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
605	if (event->proc->state != STATE_IGNORED) {
606		callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
607		if (options.syscalls) {
608			output_syscall_left(event->proc,
609					    arch_sysname(event->proc,
610							 event->e_un.sysnum));
611		}
612	}
613	continue_process(event->proc->pid);
614}
615
616static void
617handle_x_sysret(Event *event, char *(*name_cb)(struct process *, int))
618{
619	debug(DEBUG_FUNCTION, "handle_x_sysret(pid=%d, sysnum=%d)",
620	      event->proc->pid, event->e_un.sysnum);
621
622	unsigned d = event->proc->callstack_depth;
623	assert(d > 0);
624	struct callstack_element *elem = &event->proc->callstack[d - 1];
625	assert(elem->is_syscall);
626
627	if (event->proc->state != STATE_IGNORED) {
628		struct timedelta spent = calc_time_spent(elem->enter_time);
629		if (options.syscalls)
630			output_syscall_right(event->proc,
631					     name_cb(event->proc,
632						     event->e_un.sysnum),
633					     &spent);
634
635		callstack_pop(event->proc);
636	}
637	continue_after_syscall(event->proc, event->e_un.sysnum, 1);
638}
639
640static void
641handle_sysret(Event *event)
642{
643	handle_x_sysret(event, &sysname);
644}
645
646static void
647handle_arch_sysret(Event *event)
648{
649	handle_x_sysret(event, &arch_sysname);
650}
651
652static void
653output_right_tos(struct process *proc)
654{
655	size_t d = proc->callstack_depth;
656	assert(d > 0);
657	struct callstack_element *elem = &proc->callstack[d - 1];
658	assert(! elem->is_syscall);
659
660	if (proc->state != STATE_IGNORED) {
661		struct timedelta spent = calc_time_spent(elem->enter_time);
662		if (options.summary)
663			summary_account_call(elem->c_un.libfunc, spent);
664		else
665			output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc,
666				     &spent);
667	}
668}
669
670#ifndef ARCH_HAVE_SYMBOL_RET
671void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
672{
673}
674#endif
675
676static void
677handle_breakpoint(Event *event)
678{
679	int i, j;
680	struct breakpoint *sbp;
681	struct process *leader = event->proc->leader;
682	void *brk_addr = event->e_un.brk_addr;
683
684	/* The leader has terminated.  */
685	if (leader == NULL) {
686		continue_process(event->proc->pid);
687		return;
688	}
689
690	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)",
691	      event->proc->pid, brk_addr);
692	debug(2, "event: breakpoint (%p)", brk_addr);
693
694	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
695		if (brk_addr == event->proc->callstack[i].return_addr) {
696			for (j = event->proc->callstack_depth - 1; j > i; j--)
697				callstack_pop(event->proc);
698
699			struct library_symbol *libsym =
700			    event->proc->callstack[i].c_un.libfunc;
701
702			arch_symbol_ret(event->proc, libsym);
703			output_right_tos(event->proc);
704			callstack_pop(event->proc);
705
706			/* Pop also any other entries that seem like
707			 * they are linked to the current one: they
708			 * have the same return address, but were made
709			 * for different symbols.  This should only
710			 * happen for entry point tracing, i.e. for -x
711			 * everywhere, or -x and -e on MIPS.  */
712			while (event->proc->callstack_depth > 0) {
713				struct callstack_element *prev;
714				size_t d = event->proc->callstack_depth;
715				prev = &event->proc->callstack[d - 1];
716
717				if (prev->c_un.libfunc == libsym
718				    || prev->return_addr != brk_addr)
719					break;
720
721				arch_symbol_ret(event->proc,
722						prev->c_un.libfunc);
723				output_right_tos(event->proc);
724				callstack_pop(event->proc);
725			}
726
727			/* Maybe the previous callstack_pop's got rid
728			 * of the breakpoint, but if we are in a
729			 * recursive call, it's still enabled.  In
730			 * that case we need to skip it properly.  */
731			if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) {
732				continue_after_breakpoint(event->proc, sbp);
733			} else {
734				set_instruction_pointer(event->proc, brk_addr);
735				continue_process(event->proc->pid);
736			}
737			return;
738		}
739	}
740
741	if ((sbp = address2bpstruct(leader, brk_addr)) != NULL)
742		breakpoint_on_hit(sbp, event->proc);
743	else if (event->proc->state != STATE_IGNORED)
744		output_line(event->proc,
745			    "unexpected breakpoint at %p", brk_addr);
746
747	/* breakpoint_on_hit may delete its own breakpoint, so we have
748	 * to look it up again.  */
749	if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) {
750
751		if (event->proc->state != STATE_IGNORED
752		    && sbp->libsym != NULL) {
753			event->proc->stack_pointer = get_stack_pointer(event->proc);
754			callstack_push_symfunc(event->proc, sbp);
755			if (! options.summary)
756				output_left(LT_TOF_FUNCTION, event->proc,
757					    sbp->libsym);
758		}
759
760		breakpoint_on_continue(sbp, event->proc);
761		return;
762	} else {
763		set_instruction_pointer(event->proc, brk_addr);
764	}
765
766	continue_process(event->proc->pid);
767}
768
769static void
770callstack_push_syscall(struct process *proc, int sysnum)
771{
772	struct callstack_element *elem;
773
774	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
775	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
776	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
777		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
778		abort();
779		return;
780	}
781
782	elem = &proc->callstack[proc->callstack_depth];
783	*elem = (struct callstack_element){};
784	elem->is_syscall = 1;
785	elem->c_un.syscall = sysnum;
786	elem->return_addr = NULL;
787
788	proc->callstack_depth++;
789	if (opt_T || options.summary) {
790		struct timezone tz;
791		gettimeofday(&elem->enter_time, &tz);
792	}
793}
794
795static void
796callstack_push_symfunc(struct process *proc, struct breakpoint *bp)
797{
798	struct callstack_element *elem;
799
800	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)",
801	      proc->pid, bp->libsym->name);
802	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
803	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
804		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
805		abort();
806		return;
807	}
808
809	elem = &proc->callstack[proc->callstack_depth++];
810	*elem = (struct callstack_element){};
811	elem->is_syscall = 0;
812	elem->c_un.libfunc = bp->libsym;
813
814	struct breakpoint *rbp = NULL;
815	if (breakpoint_get_return_bp(&rbp, bp, proc) == 0
816	    && rbp != NULL) {
817		struct breakpoint *ext_rbp = insert_breakpoint(proc, rbp);
818		if (ext_rbp != rbp) {
819			breakpoint_destroy(rbp);
820			free(rbp);
821			rbp = ext_rbp;
822		}
823	}
824
825	elem->return_addr = rbp != NULL ? rbp->addr : 0;
826
827	if (opt_T || options.summary) {
828		struct timezone tz;
829		gettimeofday(&elem->enter_time, &tz);
830	}
831}
832
833void
834callstack_pop(struct process *proc)
835{
836	struct callstack_element *elem;
837	assert(proc->callstack_depth > 0);
838
839	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
840	elem = &proc->callstack[proc->callstack_depth - 1];
841	if (!elem->is_syscall && elem->return_addr) {
842		struct breakpoint *bp
843			= address2bpstruct(proc->leader, elem->return_addr);
844		if (bp != NULL) {
845			breakpoint_on_hit(bp, proc);
846			delete_breakpoint(proc, bp);
847		}
848	}
849
850	if (elem->fetch_context != NULL)
851		fetch_arg_done(elem->fetch_context);
852
853	if (elem->arguments != NULL) {
854		val_dict_destroy(elem->arguments);
855		free(elem->arguments);
856	}
857
858	proc->callstack_depth--;
859}
860