Blame proc.c

Packit 0021fb
/*
Packit 0021fb
 * This file is part of ltrace.
Packit 0021fb
 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
Packit 0021fb
 * Copyright (C) 2010 Joe Damato
Packit 0021fb
 * Copyright (C) 1998,2009 Juan Cespedes
Packit 0021fb
 *
Packit 0021fb
 * This program is free software; you can redistribute it and/or
Packit 0021fb
 * modify it under the terms of the GNU General Public License as
Packit 0021fb
 * published by the Free Software Foundation; either version 2 of the
Packit 0021fb
 * License, or (at your option) any later version.
Packit 0021fb
 *
Packit 0021fb
 * This program is distributed in the hope that it will be useful, but
Packit 0021fb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0021fb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0021fb
 * General Public License for more details.
Packit 0021fb
 *
Packit 0021fb
 * You should have received a copy of the GNU General Public License
Packit 0021fb
 * along with this program; if not, write to the Free Software
Packit 0021fb
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
Packit 0021fb
 * 02110-1301 USA
Packit 0021fb
 */
Packit 0021fb
Packit 0021fb
#include "config.h"
Packit 0021fb
Packit 0021fb
#include <sys/types.h>
Packit 0021fb
#include <assert.h>
Packit 0021fb
#include <errno.h>
Packit 0021fb
#include <stdio.h>
Packit 0021fb
#include <stdlib.h>
Packit 0021fb
#include <string.h>
Packit 0021fb
Packit 0021fb
#if defined(HAVE_LIBUNWIND)
Packit 0021fb
#include <libunwind.h>
Packit 0021fb
#include <libunwind-ptrace.h>
Packit 0021fb
#endif /* defined(HAVE_LIBUNWIND) */
Packit 0021fb
Packit 0021fb
#include "backend.h"
Packit 0021fb
#include "breakpoint.h"
Packit 0021fb
#include "debug.h"
Packit 0021fb
#include "fetch.h"
Packit 0021fb
#include "options.h"
Packit 0021fb
#include "proc.h"
Packit 0021fb
#include "value_dict.h"
Packit 0021fb
Packit 0021fb
#ifndef OS_HAVE_PROCESS_DATA
Packit 0021fb
int
Packit 0021fb
os_process_init(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
os_process_destroy(struct process *proc)
Packit 0021fb
{
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
os_process_clone(struct process *retp, struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
os_process_exec(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
#endif
Packit 0021fb
Packit 0021fb
#ifndef ARCH_HAVE_PROCESS_DATA
Packit 0021fb
int
Packit 0021fb
arch_process_init(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
arch_process_destroy(struct process *proc)
Packit 0021fb
{
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
arch_process_clone(struct process *retp, struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
arch_process_exec(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
#endif
Packit 0021fb
Packit 0021fb
#ifndef ARCH_HAVE_DYNLINK_DONE
Packit 0021fb
void
Packit 0021fb
arch_dynlink_done(struct process *proc)
Packit 0021fb
{
Packit 0021fb
}
Packit 0021fb
#endif
Packit 0021fb
Packit 0021fb
static int add_process(struct process *proc, int was_exec);
Packit 0021fb
static void unlist_process(struct process *proc);
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
destroy_unwind(struct process *proc)
Packit 0021fb
{
Packit 0021fb
#if defined(HAVE_LIBUNWIND)
Packit 0021fb
	if (proc->unwind_priv != NULL)
Packit 0021fb
		_UPT_destroy(proc->unwind_priv);
Packit 0021fb
	if (proc->unwind_as != NULL)
Packit 0021fb
		unw_destroy_addr_space(proc->unwind_as);
Packit 0021fb
#endif /* defined(HAVE_LIBUNWIND) */
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
process_bare_init(struct process *proc, const char *filename,
Packit 0021fb
		  pid_t pid, int was_exec)
Packit 0021fb
{
Packit 0021fb
	if (!was_exec) {
Packit 0021fb
		memset(proc, 0, sizeof(*proc));
Packit 0021fb
Packit 0021fb
		proc->filename = strdup(filename);
Packit 0021fb
		if (proc->filename == NULL) {
Packit 0021fb
		fail:
Packit 0021fb
			free(proc->filename);
Packit 0021fb
			if (proc->breakpoints != NULL) {
Packit 0021fb
				dict_destroy(proc->breakpoints,
Packit 0021fb
					     NULL, NULL, NULL);
Packit 0021fb
				free(proc->breakpoints);
Packit 0021fb
				proc->breakpoints = NULL;
Packit 0021fb
			}
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* Add process so that we know who the leader is.  */
Packit 0021fb
	proc->pid = pid;
Packit 0021fb
	if (add_process(proc, was_exec) < 0)
Packit 0021fb
		goto fail;
Packit 0021fb
	if (proc->leader == NULL) {
Packit 0021fb
	unlist_and_fail:
Packit 0021fb
		if (!was_exec)
Packit 0021fb
			unlist_process(proc);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (proc->leader == proc) {
Packit 0021fb
		proc->breakpoints = malloc(sizeof(*proc->breakpoints));
Packit 0021fb
		if (proc->breakpoints == NULL)
Packit 0021fb
			goto unlist_and_fail;
Packit 0021fb
		DICT_INIT(proc->breakpoints,
Packit 0021fb
			  arch_addr_t, struct breakpoint *,
Packit 0021fb
			  arch_addr_hash, arch_addr_eq, NULL);
Packit 0021fb
	} else {
Packit 0021fb
		proc->breakpoints = NULL;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
#if defined(HAVE_LIBUNWIND)
Packit 0021fb
	if (options.bt_depth > 0) {
Packit 0021fb
		proc->unwind_priv = _UPT_create(pid);
Packit 0021fb
		proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
Packit 0021fb
Packit 0021fb
		if (proc->unwind_priv == NULL || proc->unwind_as == NULL) {
Packit 0021fb
			fprintf(stderr,
Packit 0021fb
				"Couldn't initialize unwinding "
Packit 0021fb
				"for process %d\n", proc->pid);
Packit 0021fb
			destroy_unwind(proc);
Packit 0021fb
			proc->unwind_priv = NULL;
Packit 0021fb
			proc->unwind_as = NULL;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
#endif /* defined(HAVE_LIBUNWIND) */
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
process_bare_destroy(struct process *proc, int was_exec)
Packit 0021fb
{
Packit 0021fb
	dict_destroy(proc->breakpoints, NULL, NULL, NULL);
Packit 0021fb
	free(proc->breakpoints);
Packit 0021fb
	if (!was_exec) {
Packit 0021fb
		free(proc->filename);
Packit 0021fb
		unlist_process(proc);
Packit 0021fb
		destroy_unwind(proc);
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
process_init_main(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	if (breakpoints_init(proc) < 0) {
Packit 0021fb
		fprintf(stderr, "failed to init breakpoints %d\n",
Packit 0021fb
			proc->pid);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
process_init(struct process *proc, const char *filename, pid_t pid)
Packit 0021fb
{
Packit 0021fb
	if (process_bare_init(proc, filename, pid, 0) < 0) {
Packit 0021fb
	fail:
Packit 0021fb
		fprintf(stderr, "failed to initialize process %d: %s\n",
Packit 0021fb
			pid, strerror(errno));
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (os_process_init(proc) < 0) {
Packit 0021fb
		process_bare_destroy(proc, 0);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (arch_process_init(proc) < 0) {
Packit 0021fb
		os_process_destroy(proc);
Packit 0021fb
		process_bare_destroy(proc, 0);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (proc->leader != proc)
Packit 0021fb
		return 0;
Packit 0021fb
	if (process_init_main(proc) < 0) {
Packit 0021fb
		process_bare_destroy(proc, 0);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
destroy_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
Packit 0021fb
{
Packit 0021fb
	breakpoint_destroy(bp);
Packit 0021fb
	free(bp);
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
// XXX see comment in handle_event.c
Packit 0021fb
void callstack_pop(struct process *proc);
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
private_process_destroy(struct process *proc, int was_exec)
Packit 0021fb
{
Packit 0021fb
	/* Pop remaining stack elements.  */
Packit 0021fb
	while (proc->callstack_depth > 0) {
Packit 0021fb
		/* When this is called just before a process is
Packit 0021fb
		 * destroyed, the breakpoints should either have been
Packit 0021fb
		 * retracted by now, or were killed by exec.  In any
Packit 0021fb
		 * case, it's safe to pretend that there are no
Packit 0021fb
		 * breakpoints associated with the stack elements, so
Packit 0021fb
		 * that stack_pop doesn't attempt to destroy them.  */
Packit 0021fb
		size_t i = proc->callstack_depth - 1;
Packit 0021fb
		if (!proc->callstack[i].is_syscall)
Packit 0021fb
			proc->callstack[i].return_addr = 0;
Packit 0021fb
Packit 0021fb
		callstack_pop(proc);
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (!was_exec)
Packit 0021fb
		free(proc->filename);
Packit 0021fb
Packit 0021fb
	/* Libraries and symbols.  This is only relevant in
Packit 0021fb
	 * leader.  */
Packit 0021fb
	struct library *lib;
Packit 0021fb
	for (lib = proc->libraries; lib != NULL; ) {
Packit 0021fb
		struct library *next = lib->next;
Packit 0021fb
		library_destroy(lib);
Packit 0021fb
		free(lib);
Packit 0021fb
		lib = next;
Packit 0021fb
	}
Packit 0021fb
	proc->libraries = NULL;
Packit 0021fb
Packit 0021fb
	/* Breakpoints.  */
Packit 0021fb
	if (proc->breakpoints != NULL) {
Packit 0021fb
		proc_each_breakpoint(proc, NULL, destroy_breakpoint_cb, NULL);
Packit 0021fb
		dict_destroy(proc->breakpoints, NULL, NULL, NULL);
Packit 0021fb
		free(proc->breakpoints);
Packit 0021fb
		proc->breakpoints = NULL;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	destroy_unwind(proc);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
process_destroy(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	arch_process_destroy(proc);
Packit 0021fb
	os_process_destroy(proc);
Packit 0021fb
	private_process_destroy(proc, 0);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
process_exec(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	/* Call exec handlers first, before we destroy the main
Packit 0021fb
	 * state.  */
Packit 0021fb
	if (arch_process_exec(proc) < 0
Packit 0021fb
	    || os_process_exec(proc) < 0)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	private_process_destroy(proc, 1);
Packit 0021fb
Packit 0021fb
	if (process_bare_init(proc, NULL, proc->pid, 1) < 0)
Packit 0021fb
		return -1;
Packit 0021fb
	if (process_init_main(proc) < 0) {
Packit 0021fb
		process_bare_destroy(proc, 1);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct process *
Packit 0021fb
open_program(const char *filename, pid_t pid)
Packit 0021fb
{
Packit 0021fb
	assert(pid != 0);
Packit 0021fb
	struct process *proc = malloc(sizeof(*proc));
Packit 0021fb
	if (proc == NULL || process_init(proc, filename, pid) < 0) {
Packit 0021fb
		free(proc);
Packit 0021fb
		return NULL;
Packit 0021fb
	}
Packit 0021fb
	return proc;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct clone_single_bp_data {
Packit 0021fb
	struct process *old_proc;
Packit 0021fb
	struct process *new_proc;
Packit 0021fb
};
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
clone_single_bp(arch_addr_t *key, struct breakpoint **bpp, void *u)
Packit 0021fb
{
Packit 0021fb
	struct breakpoint *bp = *bpp;
Packit 0021fb
	struct clone_single_bp_data *data = u;
Packit 0021fb
Packit 0021fb
	struct breakpoint *clone = malloc(sizeof(*clone));
Packit 0021fb
	if (clone == NULL
Packit 0021fb
	    || breakpoint_clone(clone, data->new_proc, bp) < 0) {
Packit 0021fb
	fail:
Packit 0021fb
		free(clone);
Packit 0021fb
		return CBS_STOP;
Packit 0021fb
	}
Packit 0021fb
	if (proc_add_breakpoint(data->new_proc->leader, clone) < 0) {
Packit 0021fb
		breakpoint_destroy(clone);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
process_clone(struct process *retp, struct process *proc, pid_t pid)
Packit 0021fb
{
Packit 0021fb
	if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
Packit 0021fb
	fail1:
Packit 0021fb
		fprintf(stderr, "Failed to clone process %d to %d: %s\n",
Packit 0021fb
			proc->pid, pid, strerror(errno));
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	retp->tracesysgood = proc->tracesysgood;
Packit 0021fb
	retp->e_machine = proc->e_machine;
Packit 0021fb
	retp->e_class = proc->e_class;
Packit 0021fb
Packit 0021fb
	/* For non-leader processes, that's all we need to do.  */
Packit 0021fb
	if (retp->leader != retp)
Packit 0021fb
		return 0;
Packit 0021fb
Packit 0021fb
	/* Clone symbols first so that we can clone and relink
Packit 0021fb
	 * breakpoints.  */
Packit 0021fb
	struct library *lib;
Packit 0021fb
	struct library **nlibp = &retp->libraries;
Packit 0021fb
	for (lib = proc->leader->libraries; lib != NULL; lib = lib->next) {
Packit 0021fb
		*nlibp = malloc(sizeof(**nlibp));
Packit 0021fb
Packit 0021fb
		if (*nlibp == NULL
Packit 0021fb
		    || library_clone(*nlibp, lib) < 0) {
Packit 0021fb
			free(*nlibp);
Packit 0021fb
			*nlibp = NULL;
Packit 0021fb
Packit 0021fb
		fail2:
Packit 0021fb
			process_bare_destroy(retp, 0);
Packit 0021fb
Packit 0021fb
			/* Error when cloning.  Unroll what was done.  */
Packit 0021fb
			for (lib = retp->libraries; lib != NULL; ) {
Packit 0021fb
				struct library *next = lib->next;
Packit 0021fb
				library_destroy(lib);
Packit 0021fb
				free(lib);
Packit 0021fb
				lib = next;
Packit 0021fb
			}
Packit 0021fb
			goto fail1;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		nlibp = &(*nlibp)->next;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* Now clone breakpoints.  Symbol relinking is done in
Packit 0021fb
	 * clone_single_bp.  */
Packit 0021fb
	struct clone_single_bp_data data = {
Packit 0021fb
		.old_proc = proc,
Packit 0021fb
		.new_proc = retp,
Packit 0021fb
	};
Packit 0021fb
	if (DICT_EACH(proc->leader->breakpoints,
Packit 0021fb
		      arch_addr_t, struct breakpoint *, NULL,
Packit 0021fb
		      clone_single_bp, &data) != NULL)
Packit 0021fb
		goto fail2;
Packit 0021fb
Packit 0021fb
	/* And finally the call stack.  */
Packit 0021fb
	/* XXX clearly the callstack handling should be moved to a
Packit 0021fb
	 * separate module and this whole business extracted to
Packit 0021fb
	 * callstack_clone, or callstack_element_clone.  */
Packit 0021fb
	memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack));
Packit 0021fb
	retp->callstack_depth = proc->callstack_depth;
Packit 0021fb
Packit 0021fb
	size_t i;
Packit 0021fb
	for (i = 0; i < retp->callstack_depth; ++i) {
Packit 0021fb
		struct callstack_element *elem = &retp->callstack[i];
Packit 0021fb
		struct fetch_context *ctx = elem->fetch_context;
Packit 0021fb
		if (ctx != NULL) {
Packit 0021fb
			struct fetch_context *nctx = fetch_arg_clone(retp, ctx);
Packit 0021fb
			if (nctx == NULL) {
Packit 0021fb
				size_t j;
Packit 0021fb
			fail3:
Packit 0021fb
				for (j = 0; j < i; ++j) {
Packit 0021fb
					nctx = retp->callstack[j].fetch_context;
Packit 0021fb
					fetch_arg_done(nctx);
Packit 0021fb
					elem->fetch_context = NULL;
Packit 0021fb
				}
Packit 0021fb
				goto fail2;
Packit 0021fb
			}
Packit 0021fb
			elem->fetch_context = nctx;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		if (elem->arguments != NULL) {
Packit 0021fb
			struct value_dict *nargs = malloc(sizeof(*nargs));
Packit 0021fb
			if (nargs == NULL
Packit 0021fb
			    || val_dict_clone(nargs, elem->arguments) < 0) {
Packit 0021fb
				size_t j;
Packit 0021fb
				for (j = 0; j < i; ++j) {
Packit 0021fb
					nargs = retp->callstack[j].arguments;
Packit 0021fb
					val_dict_destroy(nargs);
Packit 0021fb
					free(nargs);
Packit 0021fb
					elem->arguments = NULL;
Packit 0021fb
				}
Packit 0021fb
Packit 0021fb
				/* Pretend that this round went well,
Packit 0021fb
				 * so that fail3 frees I-th
Packit 0021fb
				 * fetch_context.  */
Packit 0021fb
				++i;
Packit 0021fb
				goto fail3;
Packit 0021fb
			}
Packit 0021fb
			elem->arguments = nargs;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		/* If it's not a syscall, we need to find the
Packit 0021fb
		 * corresponding library symbol in the cloned
Packit 0021fb
		 * library.  */
Packit 0021fb
		if (!elem->is_syscall && elem->c_un.libfunc != NULL) {
Packit 0021fb
			struct library_symbol *libfunc = elem->c_un.libfunc;
Packit 0021fb
			int rc = proc_find_symbol(retp, libfunc,
Packit 0021fb
						  NULL, &elem->c_un.libfunc);
Packit 0021fb
			assert(rc == 0);
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* At this point, retp is fully initialized, except for OS and
Packit 0021fb
	 * arch parts, and we can call private_process_destroy.  */
Packit 0021fb
	if (os_process_clone(retp, proc) < 0) {
Packit 0021fb
		private_process_destroy(retp, 0);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	if (arch_process_clone(retp, proc) < 0) {
Packit 0021fb
		os_process_destroy(retp);
Packit 0021fb
		private_process_destroy(retp, 0);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
open_one_pid(pid_t pid)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
Packit 0021fb
Packit 0021fb
	/* Get the filename first.  Should the trace_pid fail, we can
Packit 0021fb
	 * easily free it, untracing is more work.  */
Packit 0021fb
	char *filename = pid2name(pid);
Packit 0021fb
	if (filename == NULL || trace_pid(pid) < 0) {
Packit 0021fb
	fail:
Packit 0021fb
		free(filename);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	struct process *proc = open_program(filename, pid);
Packit 0021fb
	if (proc == NULL)
Packit 0021fb
		goto fail;
Packit 0021fb
	free(filename);
Packit 0021fb
	trace_set_options(proc);
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
start_one_pid(struct process *proc, void *data)
Packit 0021fb
{
Packit 0021fb
	continue_process(proc->pid);
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
is_main(struct process *proc, struct library *lib, void *data)
Packit 0021fb
{
Packit 0021fb
	return CBS_STOP_IF(lib->type == LT_LIBTYPE_MAIN);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
process_hit_start(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	struct process *leader = proc->leader;
Packit 0021fb
	assert(leader != NULL);
Packit 0021fb
Packit 0021fb
	struct library *mainlib
Packit 0021fb
		= proc_each_library(leader, NULL, is_main, NULL);
Packit 0021fb
	assert(mainlib != NULL);
Packit 0021fb
	linkmap_init(leader, mainlib->dyn_addr);
Packit 0021fb
	arch_dynlink_done(leader);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
open_pid(pid_t pid)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_PROCESS, "open_pid(pid=%d)", pid);
Packit 0021fb
	/* If we are already tracing this guy, we should be seeing all
Packit 0021fb
	 * his children via normal tracing route.  */
Packit 0021fb
	if (pid2proc(pid) != NULL)
Packit 0021fb
		return;
Packit 0021fb
Packit 0021fb
	/* First, see if we can attach the requested PID itself.  */
Packit 0021fb
	if (open_one_pid(pid) < 0) {
Packit 0021fb
		fprintf(stderr, "Cannot attach to pid %u: %s\n",
Packit 0021fb
			pid, strerror(errno));
Packit 0021fb
		trace_fail_warning(pid);
Packit 0021fb
		return;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* Now attach to all tasks that belong to that PID.  There's a
Packit 0021fb
	 * race between process_tasks and open_one_pid.  So when we
Packit 0021fb
	 * fail in open_one_pid below, we just do another round.
Packit 0021fb
	 * Chances are that by then that PID will have gone away, and
Packit 0021fb
	 * that's why we have seen the failure.  The processes that we
Packit 0021fb
	 * manage to open_one_pid are stopped, so we should eventually
Packit 0021fb
	 * reach a point where process_tasks doesn't give any new
Packit 0021fb
	 * processes (because there's nobody left to produce
Packit 0021fb
	 * them).  */
Packit 0021fb
	size_t old_ntasks = 0;
Packit 0021fb
	int have_all;
Packit 0021fb
	while (1) {
Packit 0021fb
		pid_t *tasks;
Packit 0021fb
		size_t ntasks;
Packit 0021fb
		size_t i;
Packit 0021fb
Packit 0021fb
		if (process_tasks(pid, &tasks, &ntasks) < 0) {
Packit 0021fb
			fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n",
Packit 0021fb
				pid, strerror(errno));
Packit 0021fb
			break;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		have_all = 1;
Packit 0021fb
		for (i = 0; i < ntasks; ++i)
Packit 0021fb
			if (pid2proc(tasks[i]) == NULL
Packit 0021fb
			    && open_one_pid(tasks[i]) < 0)
Packit 0021fb
				have_all = 0;
Packit 0021fb
Packit 0021fb
		free(tasks);
Packit 0021fb
Packit 0021fb
		if (have_all && old_ntasks == ntasks)
Packit 0021fb
			break;
Packit 0021fb
		old_ntasks = ntasks;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	struct process *leader = pid2proc(pid)->leader;
Packit 0021fb
Packit 0021fb
	/* XXX Is there a way to figure out whether _start has
Packit 0021fb
	 * actually already been hit?  */
Packit 0021fb
	process_hit_start(leader);
Packit 0021fb
Packit 0021fb
	/* Done.  Continue everyone.  */
Packit 0021fb
	each_task(leader, NULL, start_one_pid, NULL);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
find_proc(struct process *proc, void *data)
Packit 0021fb
{
Packit 0021fb
	return CBS_STOP_IF(proc->pid == (pid_t)(uintptr_t)data);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct process *
Packit 0021fb
pid2proc(pid_t pid)
Packit 0021fb
{
Packit 0021fb
	return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct process *list_of_processes = NULL;
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
unlist_process(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	if (list_of_processes == proc) {
Packit 0021fb
		list_of_processes = list_of_processes->next;
Packit 0021fb
		return;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	struct process *tmp;
Packit 0021fb
	for (tmp = list_of_processes; ; tmp = tmp->next) {
Packit 0021fb
		/* If the following assert fails, the process wasn't
Packit 0021fb
		 * in the list.  */
Packit 0021fb
		assert(tmp->next != NULL);
Packit 0021fb
Packit 0021fb
		if (tmp->next == proc) {
Packit 0021fb
			tmp->next = tmp->next->next;
Packit 0021fb
			return;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct process *
Packit 0021fb
each_process(struct process *start_after,
Packit 0021fb
	     enum callback_status(*cb)(struct process *proc, void *data),
Packit 0021fb
	     void *data)
Packit 0021fb
{
Packit 0021fb
	struct process *it = start_after == NULL ? list_of_processes
Packit 0021fb
		: start_after->next;
Packit 0021fb
Packit 0021fb
	while (it != NULL) {
Packit 0021fb
		/* Callback might call remove_process.  */
Packit 0021fb
		struct process *next = it->next;
Packit 0021fb
		switch ((*cb)(it, data)) {
Packit 0021fb
		case CBS_FAIL:
Packit 0021fb
			/* XXX handle me */
Packit 0021fb
		case CBS_STOP:
Packit 0021fb
			return it;
Packit 0021fb
		case CBS_CONT:
Packit 0021fb
			break;
Packit 0021fb
		}
Packit 0021fb
		it = next;
Packit 0021fb
	}
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct process *
Packit 0021fb
each_task(struct process *proc, struct process *start_after,
Packit 0021fb
	  enum callback_status(*cb)(struct process *proc, void *data),
Packit 0021fb
	  void *data)
Packit 0021fb
{
Packit 0021fb
	assert(proc != NULL);
Packit 0021fb
	struct process *it = start_after == NULL ? proc->leader
Packit 0021fb
		: start_after->next;
Packit 0021fb
Packit 0021fb
	if (it != NULL) {
Packit 0021fb
		struct process *leader = it->leader;
Packit 0021fb
		while (it != NULL && it->leader == leader) {
Packit 0021fb
			/* Callback might call remove_process.  */
Packit 0021fb
			struct process *next = it->next;
Packit 0021fb
			switch ((*cb)(it, data)) {
Packit 0021fb
			case CBS_FAIL:
Packit 0021fb
				/* XXX handle me */
Packit 0021fb
			case CBS_STOP:
Packit 0021fb
				return it;
Packit 0021fb
			case CBS_CONT:
Packit 0021fb
				break;
Packit 0021fb
			}
Packit 0021fb
			it = next;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
add_process(struct process *proc, int was_exec)
Packit 0021fb
{
Packit 0021fb
	struct process **leaderp = &list_of_processes;
Packit 0021fb
	if (proc->pid) {
Packit 0021fb
		pid_t tgid = process_leader(proc->pid);
Packit 0021fb
		if (tgid == 0)
Packit 0021fb
			/* Must have been terminated before we managed
Packit 0021fb
			 * to fully attach.  */
Packit 0021fb
			return -1;
Packit 0021fb
		if (tgid == proc->pid) {
Packit 0021fb
			proc->leader = proc;
Packit 0021fb
		} else {
Packit 0021fb
			struct process *leader = pid2proc(tgid);
Packit 0021fb
			proc->leader = leader;
Packit 0021fb
			if (leader != NULL)
Packit 0021fb
				leaderp = &leader->next;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (!was_exec) {
Packit 0021fb
		proc->next = *leaderp;
Packit 0021fb
		*leaderp = proc;
Packit 0021fb
	}
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
change_process_leader(struct process *proc, struct process *leader)
Packit 0021fb
{
Packit 0021fb
	struct process **leaderp = &list_of_processes;
Packit 0021fb
	if (proc->leader == leader)
Packit 0021fb
		return;
Packit 0021fb
Packit 0021fb
	assert(leader != NULL);
Packit 0021fb
	unlist_process(proc);
Packit 0021fb
	if (proc != leader)
Packit 0021fb
		leaderp = &leader->next;
Packit 0021fb
Packit 0021fb
	proc->leader = leader;
Packit 0021fb
	proc->next = *leaderp;
Packit 0021fb
	*leaderp = proc;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
clear_leader(struct process *proc, void *data)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
Packit 0021fb
	      proc->pid, proc->leader->pid);
Packit 0021fb
	proc->leader = NULL;
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
remove_process(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
Packit 0021fb
Packit 0021fb
	if (proc->leader == proc)
Packit 0021fb
		each_task(proc, NULL, &clear_leader, NULL);
Packit 0021fb
Packit 0021fb
	unlist_process(proc);
Packit 0021fb
	process_removed(proc);
Packit 0021fb
	process_destroy(proc);
Packit 0021fb
	free(proc);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
install_event_handler(struct process *proc, struct event_handler *handler)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler);
Packit 0021fb
	assert(proc->event_handler == NULL);
Packit 0021fb
	proc->event_handler = handler;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
destroy_event_handler(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	struct event_handler *handler = proc->event_handler;
Packit 0021fb
	debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler);
Packit 0021fb
	assert(handler != NULL);
Packit 0021fb
	if (handler->destroy != NULL)
Packit 0021fb
		handler->destroy(handler);
Packit 0021fb
	free(handler);
Packit 0021fb
	proc->event_handler = NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
breakpoint_for_symbol(struct library_symbol *libsym, struct process *proc)
Packit 0021fb
{
Packit 0021fb
	arch_addr_t bp_addr;
Packit 0021fb
	assert(proc->leader == proc);
Packit 0021fb
Packit 0021fb
	/* Don't enable latent or delayed symbols.  */
Packit 0021fb
	if (libsym->latent || libsym->delayed) {
Packit 0021fb
		debug(DEBUG_FUNCTION,
Packit 0021fb
		      "delayed and/or latent breakpoint pid=%d, %s@%p",
Packit 0021fb
		      proc->pid, libsym->name, libsym->enter_addr);
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	bp_addr = sym2addr(proc, libsym);
Packit 0021fb
Packit 0021fb
	/* If there is an artificial breakpoint on the same address,
Packit 0021fb
	 * its libsym will be NULL, and we can smuggle our libsym
Packit 0021fb
	 * there.  That artificial breakpoint is there presumably for
Packit 0021fb
	 * the callbacks, which we don't touch.  If there is a real
Packit 0021fb
	 * breakpoint, then this is a bug.  ltrace-elf.c should filter
Packit 0021fb
	 * symbols and ignore extra symbol aliases.
Packit 0021fb
	 *
Packit 0021fb
	 * The other direction is more complicated and currently not
Packit 0021fb
	 * supported.  If a breakpoint has custom callbacks, it might
Packit 0021fb
	 * be also custom-allocated, and we would really need to swap
Packit 0021fb
	 * the two: delete the one now in the dictionary, swap values
Packit 0021fb
	 * around, and put the new breakpoint back in.  */
Packit 0021fb
	struct breakpoint *bp;
Packit 0021fb
	if (DICT_FIND_VAL(proc->breakpoints, &bp_addr, &bp) == 0) {
Packit 0021fb
		/* MIPS backend makes duplicate requests.  This is
Packit 0021fb
		 * likely a bug in the backend.  Currently there's no
Packit 0021fb
		 * point assigning more than one symbol to a
Packit 0021fb
		 * breakpoint, because when it hits, we won't know
Packit 0021fb
		 * what to print out.  But it's easier to fix it here
Packit 0021fb
		 * before someone who understands MIPS has the time to
Packit 0021fb
		 * look into it.  So turn the sanity check off on
Packit 0021fb
		 * MIPS.  References:
Packit 0021fb
		 *
Packit 0021fb
		 *   http://lists.alioth.debian.org/pipermail/ltrace-devel/2012-November/000764.html
Packit 0021fb
		 *   http://lists.alioth.debian.org/pipermail/ltrace-devel/2012-November/000770.html
Packit 0021fb
		 */
Packit 0021fb
#ifndef __mips__
Packit 0021fb
		assert(bp->libsym == NULL);
Packit 0021fb
		bp->libsym = libsym;
Packit 0021fb
#endif
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	bp = malloc(sizeof(*bp));
Packit 0021fb
	if (bp == NULL
Packit 0021fb
	    || breakpoint_init(bp, proc, bp_addr, libsym) < 0) {
Packit 0021fb
	fail:
Packit 0021fb
		free(bp);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	if (proc_add_breakpoint(proc, bp) < 0) {
Packit 0021fb
		breakpoint_destroy(bp);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (breakpoint_turn_on(bp, proc) < 0) {
Packit 0021fb
		proc_remove_breakpoint(proc, bp);
Packit 0021fb
		breakpoint_destroy(bp);
Packit 0021fb
		goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
Packit 0021fb
{
Packit 0021fb
	return CBS_STOP_IF(breakpoint_for_symbol(libsym, data) < 0);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
proc_activate_latent_symbol(struct process *proc,
Packit 0021fb
			    struct library_symbol *libsym)
Packit 0021fb
{
Packit 0021fb
	assert(libsym->latent);
Packit 0021fb
	libsym->latent = 0;
Packit 0021fb
	debug(DEBUG_FUNCTION, "activated latent symbol");
Packit 0021fb
	return breakpoint_for_symbol(libsym, proc);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
proc_activate_delayed_symbol(struct process *proc,
Packit 0021fb
			     struct library_symbol *libsym)
Packit 0021fb
{
Packit 0021fb
	assert(libsym->delayed);
Packit 0021fb
	libsym->delayed = 0;
Packit 0021fb
	debug(DEBUG_FUNCTION, "activated delayed symbol");
Packit 0021fb
	return breakpoint_for_symbol(libsym, proc);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
activate_latent_in(struct process *proc, struct library *lib, void *data)
Packit 0021fb
{
Packit 0021fb
	struct library_exported_name *exported;
Packit 0021fb
	for (exported = data; exported != NULL; exported = exported->next) {
Packit 0021fb
		struct library_symbol *libsym = NULL;
Packit 0021fb
		while ((libsym = library_each_symbol(lib, libsym,
Packit 0021fb
						     library_symbol_named_cb,
Packit 0021fb
						     (void *)exported->name))
Packit 0021fb
		       != NULL)
Packit 0021fb
			if (libsym->latent
Packit 0021fb
			    && proc_activate_latent_symbol(proc, libsym) < 0)
Packit 0021fb
				return CBS_FAIL;
Packit 0021fb
	}
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
proc_add_library(struct process *proc, struct library *lib)
Packit 0021fb
{
Packit 0021fb
	assert(lib->next == NULL);
Packit 0021fb
	lib->next = proc->libraries;
Packit 0021fb
	proc->libraries = lib;
Packit 0021fb
	debug(DEBUG_PROCESS, "added library %s@%p (%s) to %d",
Packit 0021fb
	      lib->soname, lib->base, lib->pathname, proc->pid);
Packit 0021fb
Packit 0021fb
	/* Insert breakpoints for all active (non-latent) symbols.  */
Packit 0021fb
	struct library_symbol *libsym = NULL;
Packit 0021fb
	while ((libsym = library_each_symbol(lib, libsym,
Packit 0021fb
					     cb_breakpoint_for_symbol,
Packit 0021fb
					     proc)) != NULL)
Packit 0021fb
		fprintf(stderr,
Packit 0021fb
			"Couldn't insert breakpoint for %s to %d: %s.\n",
Packit 0021fb
			libsym->name, proc->pid, strerror(errno));
Packit 0021fb
Packit 0021fb
	/* Look through export list of the new library and compare it
Packit 0021fb
	 * with latent symbols of all libraries (including this
Packit 0021fb
	 * library itself).  */
Packit 0021fb
	struct library *lib2 = NULL;
Packit 0021fb
	while ((lib2 = proc_each_library(proc, lib2, activate_latent_in,
Packit 0021fb
					 lib->exported_names)) != NULL)
Packit 0021fb
		fprintf(stderr,
Packit 0021fb
			"Couldn't activate latent symbols for %s in %d: %s.\n",
Packit 0021fb
			lib2->soname, proc->pid, strerror(errno));
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
proc_remove_library(struct process *proc, struct library *lib)
Packit 0021fb
{
Packit 0021fb
	struct library **libp;
Packit 0021fb
	for (libp = &proc->libraries; *libp != NULL; libp = &(*libp)->next)
Packit 0021fb
		if (*libp == lib) {
Packit 0021fb
			*libp = lib->next;
Packit 0021fb
			return 0;
Packit 0021fb
		}
Packit 0021fb
	return -1;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct library *
Packit 0021fb
proc_each_library(struct process *proc, struct library *it,
Packit 0021fb
		  enum callback_status (*cb)(struct process *proc,
Packit 0021fb
					     struct library *lib, void *data),
Packit 0021fb
		  void *data)
Packit 0021fb
{
Packit 0021fb
	if (it == NULL)
Packit 0021fb
		it = proc->libraries;
Packit 0021fb
	else
Packit 0021fb
		it = it->next;
Packit 0021fb
Packit 0021fb
	while (it != NULL) {
Packit 0021fb
		struct library *next = it->next;
Packit 0021fb
Packit 0021fb
		switch (cb(proc, it, data)) {
Packit 0021fb
		case CBS_FAIL:
Packit 0021fb
			/* XXX handle me */
Packit 0021fb
		case CBS_STOP:
Packit 0021fb
			return it;
Packit 0021fb
		case CBS_CONT:
Packit 0021fb
			break;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		it = next;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
check_leader(struct process *proc)
Packit 0021fb
{
Packit 0021fb
	/* Only the group leader should be getting the breakpoints and
Packit 0021fb
	 * thus have ->breakpoint initialized.  */
Packit 0021fb
	assert(proc->leader != NULL);
Packit 0021fb
	assert(proc->leader == proc);
Packit 0021fb
	assert(proc->breakpoints != NULL);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
proc_add_breakpoint(struct process *proc, struct breakpoint *bp)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)",
Packit 0021fb
	      proc->pid, breakpoint_name(bp), bp->addr);
Packit 0021fb
	check_leader(proc);
Packit 0021fb
Packit 0021fb
	/* XXX We might merge bp->libsym instead of the following
Packit 0021fb
	 * assert, but that's not necessary right now.  Read the
Packit 0021fb
	 * comment in breakpoint_for_symbol.  */
Packit 0021fb
	assert(dict_find(proc->breakpoints, &bp->addr) == NULL);
Packit 0021fb
Packit 0021fb
	if (DICT_INSERT(proc->breakpoints, &bp->addr, &bp) < 0) {
Packit 0021fb
		fprintf(stderr,
Packit 0021fb
			"couldn't enter breakpoint %s@%p to dictionary: %s\n",
Packit 0021fb
			breakpoint_name(bp), bp->addr, strerror(errno));
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void
Packit 0021fb
proc_remove_breakpoint(struct process *proc, struct breakpoint *bp)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "proc_remove_breakpoint(pid=%d, %s@%p)",
Packit 0021fb
	      proc->pid, breakpoint_name(bp), bp->addr);
Packit 0021fb
	check_leader(proc);
Packit 0021fb
	int rc = DICT_ERASE(proc->breakpoints, &bp->addr, struct breakpoint *,
Packit 0021fb
			    NULL, NULL, NULL);
Packit 0021fb
	assert(rc == 0);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct each_breakpoint_data
Packit 0021fb
{
Packit 0021fb
	struct process *proc;
Packit 0021fb
	enum callback_status (*cb)(struct process *proc,
Packit 0021fb
				   struct breakpoint *bp,
Packit 0021fb
				   void *data);
Packit 0021fb
	void *cb_data;
Packit 0021fb
};
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
each_breakpoint_cb(arch_addr_t *key, struct breakpoint **bpp, void *d)
Packit 0021fb
{
Packit 0021fb
	struct each_breakpoint_data *data = d;
Packit 0021fb
	return data->cb(data->proc, *bpp, data->cb_data);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
void *
Packit 0021fb
proc_each_breakpoint(struct process *proc, void *start,
Packit 0021fb
		     enum callback_status (*cb)(struct process *proc,
Packit 0021fb
						struct breakpoint *bp,
Packit 0021fb
						void *data), void *data)
Packit 0021fb
{
Packit 0021fb
	struct each_breakpoint_data dd = {
Packit 0021fb
		.proc = proc,
Packit 0021fb
		.cb = cb,
Packit 0021fb
		.cb_data = data,
Packit 0021fb
	};
Packit 0021fb
	return DICT_EACH(proc->breakpoints,
Packit 0021fb
			 arch_addr_t, struct breakpoint *, start,
Packit 0021fb
			 &each_breakpoint_cb, &dd);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
proc_find_symbol(struct process *proc, struct library_symbol *sym,
Packit 0021fb
		 struct library **retlib, struct library_symbol **retsym)
Packit 0021fb
{
Packit 0021fb
	struct library *lib = sym->lib;
Packit 0021fb
	assert(lib != NULL);
Packit 0021fb
Packit 0021fb
	struct library *flib
Packit 0021fb
		= proc_each_library(proc, NULL, library_with_key_cb, &lib->key);
Packit 0021fb
	if (flib == NULL)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	struct library_symbol *fsym
Packit 0021fb
		= library_each_symbol(flib, NULL, library_symbol_named_cb,
Packit 0021fb
				      (char *)sym->name);
Packit 0021fb
	if (fsym == NULL)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	if (retlib != NULL)
Packit 0021fb
		*retlib = flib;
Packit 0021fb
	if (retsym != NULL)
Packit 0021fb
		*retsym = fsym;
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
struct library_symbol *
Packit 0021fb
proc_each_symbol(struct process *proc, struct library_symbol *start_after,
Packit 0021fb
		 enum callback_status (*cb)(struct library_symbol *, void *),
Packit 0021fb
		 void *data)
Packit 0021fb
{
Packit 0021fb
	struct library *lib;
Packit 0021fb
	for (lib = start_after != NULL ? start_after->lib : proc->libraries;
Packit 0021fb
	     lib != NULL; lib = lib->next) {
Packit 0021fb
		start_after = library_each_symbol(lib, start_after, cb, data);
Packit 0021fb
		if (start_after != NULL)
Packit 0021fb
			return start_after;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
#define DEF_READER(NAME, SIZE)						\
Packit 0021fb
	int								\
Packit 0021fb
	NAME(struct process *proc, arch_addr_t addr,			\
Packit 0021fb
	     uint##SIZE##_t *lp)					\
Packit 0021fb
	{								\
Packit 0021fb
		union {							\
Packit 0021fb
			uint##SIZE##_t dst;				\
Packit 0021fb
			char buf[0];					\
Packit 0021fb
		} u;							\
Packit 0021fb
		if (umovebytes(proc, addr, &u.buf, sizeof(u.dst))	\
Packit 0021fb
		    != sizeof(u.dst))					\
Packit 0021fb
			return -1;					\
Packit 0021fb
		*lp = u.dst;						\
Packit 0021fb
		return 0;						\
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
DEF_READER(proc_read_8, 8)
Packit 0021fb
DEF_READER(proc_read_16, 16)
Packit 0021fb
DEF_READER(proc_read_32, 32)
Packit 0021fb
DEF_READER(proc_read_64, 64)
Packit 0021fb
Packit 0021fb
#undef DEF_READER