Beispiel #1
0
int
breakpoints_init(struct process *proc)
{
	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);

	/* XXX breakpoint dictionary should be initialized
	 * outside.  Here we just put in breakpoints.  */
	assert(proc->breakpoints != NULL);

	/* Only the thread group leader should hold the breakpoints.  */
	assert(proc->leader == proc);

	/* N.B. the following used to be conditional on this, and
	 * maybe it still needs to be.  */
	assert(proc->filename != NULL);

	struct library *lib = ltelf_read_main_binary(proc, proc->filename);
	struct entry_breakpoint *entry_bp = NULL;
	int bp_state = 0;
	int result = -1;
	switch ((int)(lib != NULL)) {
	fail:
		switch (bp_state) {
		case 2:
			proc_remove_library(proc, lib);
			proc_remove_breakpoint(proc, &entry_bp->super);
		case 1:
			breakpoint_destroy(&entry_bp->super);
		}
		library_destroy(lib);
		free(entry_bp);
	case 0:
		return result;
	}

	entry_bp = malloc(sizeof(*entry_bp));
	if (entry_bp == NULL
	    || (entry_breakpoint_init(proc, entry_bp,
				      lib->entry, lib)) < 0) {
		fprintf(stderr,
			"Couldn't initialize entry breakpoint for PID %d.\n"
			"Some tracing events may be missed.\n", proc->pid);
		free(entry_bp);

	} else {
		++bp_state;

		if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0)
			goto fail;
		++bp_state;

		if ((result = breakpoint_turn_on(&entry_bp->super, proc)) < 0)
			goto fail;
	}
	proc_add_library(proc, lib);

	proc->callstack_depth = 0;
	return 0;
}
Beispiel #2
0
/* When functions return we check if the symbol needs an updated
   breakpoint with the resolved address.  */
void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym)
{
	struct breakpoint *bp;
	arch_addr_t resolved_addr;
	struct Process *leader = proc->leader;

	/* Only deal with unresolved symbols.  */
	if (libsym->arch.type != MIPS_PLT_UNRESOLVED)
		return;

	/* Get out if we are always using the PLT.  */
	if (libsym->arch.pltalways)
		return;

	resolved_addr = sym2addr(proc, libsym);
	libsym->arch.resolved_addr = (uintptr_t) resolved_addr;
	libsym->arch.type = MIPS_PLT_RESOLVED;

	if (libsym->arch.stub_addr == libsym->arch.resolved_addr) {
		/* Prelinked symbol. No need to add new breakpoint.  */
		return;
	}

	bp = malloc(sizeof (*bp));
	if (bp == NULL) {
		fprintf(stderr, "Failed to allocate bp for %s\n",
			libsym->name);
		return;
	}

	if (breakpoint_init(bp, leader, resolved_addr, libsym) < 0)
		goto err;

	if (proc_add_breakpoint(leader, bp) < 0) {
		breakpoint_destroy(bp);
		goto err;
	}

	if (breakpoint_turn_on(bp, leader) < 0) {
		proc_remove_breakpoint(leader, bp);
		breakpoint_destroy(bp);
		goto err;
	}
	return;
err:
	free(bp);
}
Beispiel #3
0
struct breakpoint *
insert_breakpoint(struct process *proc, void *addr,
		  struct library_symbol *libsym)
{
	struct process *leader = proc->leader;

	/* Only the group leader should be getting the breakpoints and
	 * thus have ->breakpoint initialized.  */
	assert(leader != NULL);
	assert(leader->breakpoints != NULL);

	debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)",
	      proc->pid, addr, libsym ? libsym->name : "NULL");

	assert(addr != 0);

	/* XXX what we need to do instead is have a list of
	 * breakpoints that are enabled at this address.  The
	 * following works if every breakpoint is the same and there's
	 * no extra data, but that doesn't hold anymore.  For now it
	 * will suffice, about the only realistic case where we need
	 * to have more than one breakpoint per address is return from
	 * a recursive library call.  */
	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
	if (sbp == NULL) {
		sbp = malloc(sizeof(*sbp));
		if (sbp == NULL
		    || breakpoint_init(sbp, proc, addr, libsym) < 0) {
			free(sbp);
			return NULL;
		}
		if (proc_add_breakpoint(leader, sbp) < 0) {
		fail:
			breakpoint_destroy(sbp);
			free(sbp);
			return NULL;
		}
	}

	if (breakpoint_turn_on(sbp, proc) < 0) {
		proc_remove_breakpoint(leader, sbp);
		goto fail;
	}

	return sbp;
}
Beispiel #4
0
static void
clone_single_bp(void *key, void *value, void *u)
{
	struct breakpoint *bp = value;
	struct clone_single_bp_data *data = u;

	/* Don't bother if there were errors anyway.  */
	if (data->error != 0)
		return;

	struct breakpoint *clone = malloc(sizeof(*clone));
	if (clone == NULL
	    || breakpoint_clone(clone, data->new_proc,
				bp, data->old_proc) < 0) {
	fail:
		free(clone);
		data->error = -1;
	}
	if (proc_add_breakpoint(data->new_proc->leader, clone) < 0) {
		breakpoint_destroy(clone);
		goto fail;
	}
}
Beispiel #5
0
static int
breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
{
	arch_addr_t bp_addr;
	assert(proc->leader == proc);

	/* Don't enable latent or delayed symbols.  */
	if (libsym->latent || libsym->delayed) {
		debug(DEBUG_FUNCTION,
		      "delayed and/or latent breakpoint pid=%d, %s@%p",
		      proc->pid, libsym->name, libsym->enter_addr);
		return 0;
	}

	bp_addr = sym2addr(proc, libsym);

	/* If there is an artificial breakpoint on the same address,
	 * its libsym will be NULL, and we can smuggle our libsym
	 * there.  That artificial breakpoint is there presumably for
	 * the callbacks, which we don't touch.  If there is a real
	 * breakpoint, then this is a bug.  ltrace-elf.c should filter
	 * symbols and ignore extra symbol aliases.
	 *
	 * The other direction is more complicated and currently not
	 * supported.  If a breakpoint has custom callbacks, it might
	 * be also custom-allocated, and we would really need to swap
	 * the two: delete the one now in the dictionary, swap values
	 * around, and put the new breakpoint back in.  */
	struct breakpoint *bp = dict_find_entry(proc->breakpoints,
						bp_addr);
	if (bp != NULL) {
		/* MIPS backend makes duplicate requests.  This is
		 * likely a bug in the backend.  Currently there's no
		 * point assigning more than one symbol to a
		 * breakpoint, because when it hits, we won't know
		 * what to print out.  But it's easier to fix it here
		 * before someone who understands MIPS has the time to
		 * look into it.  So turn the sanity check off on
		 * MIPS.  References:
		 *
		 *   http://lists.alioth.debian.org/pipermail/ltrace-devel/2012-November/000764.html
		 *   http://lists.alioth.debian.org/pipermail/ltrace-devel/2012-November/000770.html
		 */
#ifndef __mips__
		assert(bp->libsym == NULL);
		bp->libsym = libsym;
#endif
		return 0;
	}

	bp = malloc(sizeof(*bp));
	if (bp == NULL
	    || breakpoint_init(bp, proc, bp_addr, libsym) < 0) {
	fail:
		free(bp);
		return -1;
	}
	if (proc_add_breakpoint(proc, bp) < 0) {
		breakpoint_destroy(bp);
		goto fail;
	}

	if (breakpoint_turn_on(bp, proc) < 0) {
		proc_remove_breakpoint(proc, bp);
		breakpoint_destroy(bp);
		goto fail;
	}

	return 0;
}