Example #1
0
void
delete_breakpoint(struct process *proc, void *addr)
{
	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);

	struct process *leader = proc->leader;
	assert(leader != NULL);

	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
	assert(sbp != NULL);
	/* This should only happen on out-of-memory conditions. */
	if (sbp == NULL)
		return;

	if (breakpoint_turn_off(sbp, proc) < 0) {
		fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n",
			breakpoint_name(sbp), sbp->addr);
		return;
	}
	if (sbp->enabled == 0) {
		proc_remove_breakpoint(leader, sbp);
		breakpoint_destroy(sbp);
		free(sbp);
	}
}
Example #2
0
void
insert_breakpoint(Process *proc, void *addr,
		  struct library_symbol *libsym) {
	Breakpoint *sbp;

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

	if (!addr)
		return;

	if (libsym)
		libsym->needs_init = 0;

	sbp = dict_find_entry(proc->breakpoints, addr);
	if (!sbp) {
		sbp = calloc(1, sizeof(Breakpoint));
		if (!sbp) {
			return;	/* TODO FIXME XXX: error_mem */
		}
		dict_enter(proc->breakpoints, addr, sbp);
		sbp->addr = addr;
		sbp->libsym = libsym;
	}
#ifdef __arm__
	sbp->thumb_mode = proc->thumb_mode;
	proc->thumb_mode = 0;
#endif
	sbp->enabled++;
	if (sbp->enabled == 1 && proc->pid)
		enable_breakpoint(proc->pid, sbp);
}
Example #3
0
const char *
my_demangle(const char *function_name) {
	const char *tmp, *fn_copy;
#ifdef USE_CXA_DEMANGLE
	extern char *__cxa_demangle(const char *, char *, size_t *, int *);
#endif

	debug(DEBUG_FUNCTION, "my_demangle(name=%s)", function_name);

	if (!d)
		d = dict_init(dict_key2hash_string, dict_key_cmp_string);

	tmp = dict_find_entry(d, (void *)function_name);
	if (!tmp) {
		fn_copy = strdup(function_name);
#ifdef HAVE_LIBIBERTY
		tmp = cplus_demangle(function_name, DMGL_ANSI | DMGL_PARAMS);
#elif defined USE_CXA_DEMANGLE
		int status = 0;
		tmp = __cxa_demangle(function_name, NULL, NULL, &status);
#endif
		if (!tmp)
			tmp = fn_copy;
		if (tmp)
			dict_enter(d, (void *)fn_copy, (void *)tmp);
	}
	return tmp;
}
Example #4
0
void
enable_all_breakpoints(Process *proc) {
	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
	if (proc->breakpoints_enabled <= 0) {
#ifdef __powerpc__
		unsigned long a;

		/*
		 * PPC HACK! (XXX FIXME TODO)
		 * If the dynamic linker hasn't populated the PLT then
		 * dont enable the breakpoints
		 */
		if (options.libcalls) {
			a = ptrace(PTRACE_PEEKTEXT, proc->pid,
				   sym2addr(proc, proc->list_of_symbols),
				   0);
			if (a == 0x0)
				return;
		}
#endif

		debug(1, "Enabling breakpoints for pid %u...", proc->pid);
		if (proc->breakpoints) {
			dict_apply_to_all(proc->breakpoints, enable_bp_cb,
					  proc);
		}
#ifdef __mips__
		{
			/*
			 * I'm sure there is a nicer way to do this. We need to
			 * insert breakpoints _after_ the child has been started.
			 */
			struct library_symbol *sym;
			struct library_symbol *new_sym;
			sym=proc->list_of_symbols;
			while(sym){
				void *addr= sym2addr(proc,sym);
				if(!addr){
					sym=sym->next;
					continue;
				}
				if(dict_find_entry(proc->breakpoints,addr)){
					sym=sym->next;
					continue;
				}
				debug(2,"inserting bp %p %s",addr,sym->name);
				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
				new_sym->next=proc->list_of_symbols;
				proc->list_of_symbols=new_sym;
				insert_breakpoint(proc, addr, new_sym);
				sym=sym->next;
			}
		}
#endif
	}
	proc->breakpoints_enabled = 1;
}
Example #5
0
struct breakpoint *
address2bpstruct(struct process *proc, void *addr)
{
	assert(proc != NULL);
	assert(proc->breakpoints != NULL);
	assert(proc->leader == proc);
	debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr);
	return dict_find_entry(proc->breakpoints, addr);
}
Example #6
0
void
delete_breakpoint(Process *proc, void *addr) {
	Breakpoint *sbp;

	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);

	sbp = dict_find_entry(proc->breakpoints, addr);
	assert(sbp);		/* FIXME: remove after debugging has been done. */
	/* This should only happen on out-of-memory conditions. */
	if (sbp == NULL)
		return;

	sbp->enabled--;
	if (sbp->enabled == 0)
		disable_breakpoint(proc->pid, sbp);
	assert(sbp->enabled >= 0);
}
Example #7
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;
}
Example #8
0
int
proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
{
	debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)",
	      proc->pid, breakpoint_name(bp), bp->addr);
	check_leader(proc);

	/* XXX We might merge bp->libsym instead of the following
	 * assert, but that's not necessary right now.  Read the
	 * comment in breakpoint_for_symbol.  */
	assert(dict_find_entry(proc->breakpoints, bp->addr) == NULL);

	if (dict_enter(proc->breakpoints, bp->addr, bp) < 0) {
		fprintf(stderr,
			"couldn't enter breakpoint %s@%p to dictionary: %s\n",
			breakpoint_name(bp), bp->addr, strerror(errno));
		return -1;
	}

	return 0;
}
Example #9
0
static void *
breakpoint_clone(void * bp, void * data)
{
	Breakpoint * b;
	Dict * map = data;
	debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
	b = malloc(sizeof(Breakpoint));
	if (!b) {
		perror("malloc()");
		exit(1);
	}
	memcpy(b, bp, sizeof(Breakpoint));
	if (b->libsym != NULL) {
		struct library_symbol * sym = dict_find_entry(map, b->libsym);
		if (b->libsym == NULL) {
			fprintf(stderr, "Can't find cloned symbol %s.\n",
				b->libsym->name);
			return NULL;
		}
		b->libsym = sym;
	}
	return b;
}
Example #10
0
Breakpoint *
address2bpstruct(Process *proc, void *addr) {
	debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr);
	return dict_find_entry(proc->breakpoints, addr);
}
Example #11
0
static void
handle_breakpoint(Event *event) {
	int i, j;
	Breakpoint *sbp;
	Process *leader = event->proc->leader;

	/* The leader has terminated.  */
	if (leader == NULL) {
		continue_process(event->proc->pid);
		return;
	}

	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
	debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);

#ifdef __powerpc__
	/* Need to skip following NOP's to prevent a fake function from being stacked.  */
	long stub_addr = (long) get_count_register(event->proc);
	Breakpoint *stub_bp = NULL;
	char nop_instruction[] = PPC_NOP;

	stub_bp = address2bpstruct(leader, event->e_un.brk_addr);

	if (stub_bp) {
		unsigned char *bp_instruction = stub_bp->orig_value;

		if (memcmp(bp_instruction, nop_instruction,
			    PPC_NOP_LENGTH) == 0) {
			if (stub_addr != (long) event->e_un.brk_addr) {
				set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
				continue_process(event->proc->pid);
				return;
			}
		}
	}
#endif

	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
		if (event->e_un.brk_addr ==
		    event->proc->callstack[i].return_addr) {
#ifdef __powerpc__
			/*
			 * PPC HACK! (XXX FIXME TODO)
			 * The PLT gets modified during the first call,
			 * so be sure to re-enable the breakpoint.
			 */
			unsigned long a;
			struct library_symbol *libsym =
			    event->proc->callstack[i].c_un.libfunc;
			void *addr = sym2addr(event->proc, libsym);

			if (libsym->plt_type != LS_TOPLT_POINT) {
				unsigned char break_insn[] = BREAKPOINT_VALUE;

				sbp = address2bpstruct(leader, addr);
				assert(sbp);
				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
					   addr);

				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
					sbp->enabled--;
					insert_breakpoint(event->proc, addr,
							  libsym, 1);
				}
			} else {
				sbp = dict_find_entry(leader->breakpoints, addr);
				/* On powerpc, the breakpoint address
				   may end up being actual entry point
				   of the library symbol, not the PLT
				   address we computed.  In that case,
				   sbp is NULL.  */
				if (sbp == NULL || addr != sbp->addr) {
					insert_breakpoint(event->proc, addr,
							  libsym, 1);
				}
			}
#elif defined(__mips__)
			void *addr = NULL;
			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
			struct library_symbol *new_sym;
			assert(sym);
			addr = sym2addr(event->proc, sym);
			sbp = dict_find_entry(leader->breakpoints, addr);
			if (sbp) {
				if (addr != sbp->addr) {
					insert_breakpoint(event->proc, addr, sym, 1);
				}
			} else {
				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
				new_sym->next = leader->list_of_symbols;
				leader->list_of_symbols = new_sym;
				insert_breakpoint(event->proc, addr, new_sym, 1);
			}
#endif
			for (j = event->proc->callstack_depth - 1; j > i; j--) {
				callstack_pop(event->proc);
			}
			if (event->proc->state != STATE_IGNORED) {
				if (opt_T || options.summary) {
					calc_time_spent(event->proc);
				}
			}
			event->proc->return_addr = event->e_un.brk_addr;
			if (event->proc->state != STATE_IGNORED) {
				mock_return(LT_TOF_FUNCTIONR, event->proc,
						event->proc->callstack[i].c_un.libfunc->name);
				output_right(LT_TOF_FUNCTIONR, event->proc,
						event->proc->callstack[i].c_un.libfunc->name);
			}
			callstack_pop(event->proc);
			sbp = address2bpstruct(leader, event->e_un.brk_addr);
			continue_after_breakpoint(event->proc, sbp);
			return;
		}
	}

	if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
		if (sbp->libsym == NULL) {
			continue_after_breakpoint(event->proc, sbp);
			return;
		}

		if (strcmp(sbp->libsym->name, "") == 0) {
			debug(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n");
			arch_check_dbg(leader);
		}

		if (event->proc->state != STATE_IGNORED) {
			event->proc->stack_pointer = get_stack_pointer(event->proc);
			event->proc->return_addr =
				get_return_addr(event->proc, event->proc->stack_pointer);
			callstack_push_symfunc(event->proc, sbp->libsym);
			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
		}
#ifdef PLT_REINITALISATION_BP
		if (event->proc->need_to_reinitialize_breakpoints
		    && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
			0))
			reinitialize_breakpoints(leader);
#endif

		continue_after_breakpoint(event->proc, sbp);
		return;
	}

	if (event->proc->state != STATE_IGNORED && !options.no_plt) {
		output_line(event->proc, "unexpected breakpoint at %p",
				(void *)event->e_un.brk_addr);
	}
	continue_process(event->proc->pid);
}
Example #12
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;
}