Beispiel #1
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 #2
0
int
entry_breakpoint_init(struct process *proc,
		      struct entry_breakpoint *bp, arch_addr_t addr,
		      struct library *lib)
{
	assert(addr != 0);
	int err = breakpoint_init(&bp->super, proc, addr, NULL);
	if (err < 0)
		return err;

	static struct bp_callbacks entry_callbacks = {
		.on_hit = entry_breakpoint_on_hit,
	};
	bp->super.cbs = &entry_callbacks;
	bp->dyn_addr = lib->dyn_addr;
	return 0;
}
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 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;
}