Esempio n. 1
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;
}
Esempio n. 2
0
static enum callback_status
cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
{
	struct Process *proc = data;
	arch_addr_t bp_addr;

	if (!libsym->arch.gotonly)
		return CBS_CONT;

	/* Update state.  */
	bp_addr = sym2addr(proc, libsym);
	/* XXX The cast to uintptr_t should be removed when
	 * arch_addr_t becomes integral type.  keywords: double cast.  */
	libsym->arch.resolved_addr = (uintptr_t) bp_addr;

	if (libsym->arch.resolved_addr == 0)
		/* FIXME: What does this mean?  */
		return CBS_CONT;

	libsym->arch.type = MIPS_PLT_RESOLVED;

	/* Now, activate the symbol causing a breakpoint to be added.  */
	if (proc_activate_delayed_symbol(proc, libsym) < 0) {
		fprintf(stderr, "Failed to activate delayed sym %s\n",
			libsym->name);
	}
	return CBS_CONT;
}
Esempio n. 3
0
int
linkmap_init(Process *proc, struct ltelf *lte) {
	void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr);
	struct r_debug *rdbg = NULL;
	struct cb_data data;

	debug(DEBUG_FUNCTION, "linkmap_init()");

	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
		debug(2, "Couldn't find debug structure!");
		return -1;
	}

	proc->debug = dbg_addr;

	if (!(rdbg = load_debug_struct(proc))) {
		debug(2, "No debug structure or no memory to allocate one!");
		return -1;
	}

	data.lte = lte;

	add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
	insert_breakpoint(proc, sym2addr(proc, library_symbols),
			  library_symbols, 1);

	crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);

	free(rdbg);
	return 0;
}
Esempio n. 4
0
enum plt_status
arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
                       const char *a_name, GElf_Rela *rela, size_t ndx,
                       struct library_symbol **ret)
{
	char *name = NULL;
	int sym_index = ndx + lte->arch.mips_gotsym;

	struct library_symbol *libsym = malloc(sizeof(*libsym));
	if (libsym == NULL)
		return plt_fail;

	GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);

	name = strdup(a_name);
	if (name == NULL) {
		fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__,
			name, addr, strerror(errno));
		goto fail;
	}

	/* XXX The double cast should be removed when
	 * arch_addr_t becomes integral type.  */
	if (library_symbol_init(libsym,
				(arch_addr_t) (uintptr_t) addr,
				name, 1, LS_TOPLT_EXEC) < 0) {
		fprintf(stderr, "%s: failed %s : %llx\n", __func__, name, addr);
		goto fail;
	}

	arch_addr_t bp_addr = sym2addr(proc, libsym);
	/* XXX This cast should be removed when
	 * arch_addr_t becomes integral type.  keywords: double cast. */
	libsym->arch.stub_addr = (uintptr_t) bp_addr;

	if (bp_addr == 0) {
		/* Function pointers without PLT entries.  */
		libsym->plt_type = LS_TOPLT_NONE;
		libsym->arch.gotonly = 1;
		libsym->arch.type = MIPS_PLT_UNRESOLVED;

		/* Delay breakpoint activation until the symbol gets
		 * resolved.  */
		libsym->delayed = 1;
	} else if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
		libsym->arch.pltalways = 1;
	}

	*ret = libsym;
	return plt_ok;

fail:
	free(name);
	free(libsym);
	return plt_fail;
}
Esempio n. 5
0
static void
linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
	size_t i = 0;
	struct cb_data *lm_add = data;
	struct ltelf lte;
	struct opt_x_t *xptr;

	debug(DEBUG_FUNCTION, "linkmap_add_cb");

	/*
		XXX
		iterate through library[i]'s to see if this lib is in the list.
		if not, add it
	 */
	for(;i < library_num;i++) {
		if (strcmp(library[i], lm_add->lib_name) == 0) {
			/* found it, so its not new */
			return;
		}
	}

	/* new library linked! */
	debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);

	if (library_num < MAX_LIBRARIES) {
		library[library_num++] = strdup(lm_add->lib_name);
		memset(&lte, 0, sizeof(struct ltelf));
		lte.base_addr = lm_add->addr;
		do_init_elf(&lte, library[library_num-1]);
		/* add bps */
		for (xptr = opt_x; xptr; xptr = xptr->next) {
			if (xptr->found)
				continue;

			GElf_Sym sym;
			GElf_Addr addr;

			if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
				debug(2, "found symbol %s @ %#" PRIx64
						", adding it.",
						xptr->name, sym.st_value);
				addr = sym.st_value;
				add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
				xptr->found = 1;
				insert_breakpoint(lm_add->proc,
						  sym2addr(lm_add->proc,
							   library_symbols),
						  library_symbols, 1);
			}
		}
		do_close_elf(&lte);
	}
}
Esempio n. 6
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);
}
Esempio n. 7
0
void
breakpoints_init(Process *proc) {
	struct library_symbol *sym;

	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
	if (proc->breakpoints) {	/* let's remove that struct */
		dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
		dict_clear(proc->breakpoints);
		proc->breakpoints = NULL;
	}
	proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);

	if (options.libcalls && proc->filename) {
		/* FIXME: memory leak when called by exec(): */
		proc->list_of_symbols = read_elf(proc);
		if (opt_e) {
			struct library_symbol **tmp1 = &(proc->list_of_symbols);
			while (*tmp1) {
				struct opt_e_t *tmp2 = opt_e;
				int keep = !opt_e_enable;

				while (tmp2) {
					if (!strcmp((*tmp1)->name, tmp2->name)) {
						keep = opt_e_enable;
					}
					tmp2 = tmp2->next;
				}
				if (!keep) {
					*tmp1 = (*tmp1)->next;
				} else {
					tmp1 = &((*tmp1)->next);
				}
			}
		}
	} else {
		proc->list_of_symbols = NULL;
	}
	for (sym = proc->list_of_symbols; sym; sym = sym->next) {
		/* proc->pid==0 delays enabling. */
		insert_breakpoint(proc, sym2addr(proc, sym), sym);
	}
	proc->callstack_depth = 0;
	proc->breakpoints_enabled = -1;
}
Esempio n. 8
0
void
reinitialize_breakpoints(Process *proc) {
	struct library_symbol *sym;

	debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid);

	sym = proc->list_of_symbols;

	while (sym) {
		if (sym->needs_init) {
			insert_breakpoint(proc, sym2addr(proc, sym),
					  sym);
			if (sym->needs_init && !sym->is_weak) {
				fprintf(stderr,
					"could not re-initialize breakpoint for \"%s\" in file \"%s\"\n",
					sym->name, proc->filename);
				exit(1);
			}
		}
		sym = sym->next;
	}
}
Esempio n. 9
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);
}
Esempio n. 10
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;
}