示例#1
0
文件: trap.c 项目: Jarlene/ADBI-1
bool thread_trap(thread_t * thread) {

    pt_regs regs;
    address_t ip, jump_target;
    
    if (unlikely(!thread_get_regs(thread, &regs))) {
        /* Thread died while reading registers. Consider this case as handled. */
        return true;
    }
    
    ip = regs.pc;
    jump_target = jump_get(thread->process, ip);
    
    debug("Thread %s hit a break at %s.", str_thread(thread), str_address(thread->process, ip));
    
    #if 0   /* enable to see full context on each hit */
    dump_thread(thread);
    #endif
    
    if (likely(jump_target)) {
        /* Thread hit a tracepoint. Change the PC and let it continue. */
        if (likely(!thread->process->stabilizing)) {
            debug("Thread %s jumping to %s.", str_thread(thread), str_address(thread->process, jump_target));
            regs.pc = jump_target;
            if (likely(thread_set_regs(thread, &regs))) {
                thread_continue_or_stop(thread, 0);
            }
        } else {
            /* The process is currently stabilizing threads.  The current thread just hit a tracepoint, but we don't
             * change its address to the trampoline, we just leave it stopped.  If we continue the thread now, it
             * will hit the tracepoint again. */
            info("Thread %s is stabilizing, deferring jump to %s.", str_thread(thread),
                 str_address(thread->process, jump_target));
        }
        return true;
    }
    
    /* Linker breakpoint */
    if (likely(ip == thread->process->linker.bkpt)) {
        /* Linker breakpoint */
        linker_notify(thread);
        regs.pc = regs.regs[30];
        if (likely(thread_set_regs(thread, &regs))) {
            thread_continue_or_stop(thread, 0);
        }
        return true;
    }
    
    return false;
}
示例#2
0
文件: thread.c 项目: rohsaini/mkunity
thread_port_t 
tgdb_thread_create(vm_offset_t entry)
{
	kern_return_t	rc;
	mach_thread_t th;
	int i;

	for (th = &threads[0], i=0; i<MAX_THREADS; i++, th++)
		if (th->thread == MACH_PORT_NULL)
			break;

	if((rc = thread_create(mach_task_self(), &th->thread)) != KERN_SUCCESS) {
		printf("tgdb: thread_create returned %d\n", rc);
		return 0;
	}

	th->stack = stack_alloc(STACK_SIZE);
	set_thread_self(th);

	thread_set_regs(entry, th);

	return th->thread;
}
示例#3
0
文件: fncall.c 项目: Jarlene/ADBI-1
/* Start a stopped thread and stop it again immediately. The function replaces
 * the instruction at the PC to a breakpoint instruction, starts the thread and
 * waits for the thread to receive a SIGTRAP (or SIGILL) signal. After the
 * thread stops, the patched instruction is reverted.
 *
 * The function checks if the address pointed by the PC is actually inside an
 * executable memory segment. If it isn't, the function restarts the thread
 * without patching any instructions. The address pointed by the PC is
 * illegal, so the thread should receive a SIGSEGV signal in this case.
 *
 * The function must be called with all threads of the process stopped.
 * Moreover, the given process must still be alive (i.e. not a zombie).
 */
static bool fncall_restop(thread_t * thread) {

    int patch;
    int signo;
    struct pt_regs regs[2];
    
    /* Original instruction. */
    insn_t          insn;
    insn_kind_t     kind;
    address_t       address;
    
    assert(!thread->state.slavemode);
    thread->state.slavemode = true;
    
    info("Restopping thread %s...", str_thread(thread));
    
    /* Save current register values. */
    if (!thread_get_regs(thread, &regs[0]))
        goto fail;
        
    /* Get the current PC. */
    address = instruction_pointer(&regs[0]);
    
    patch = procfs_address_executable(thread, address);
    
    if (patch) {
        /* Read the original instruction. */
        kind = is_thumb_mode(&regs[0]) ? INSN_KIND_THUMB : INSN_KIND_ARM;
        if (!patch_read_insn_detect_kind(thread, address, &insn, &kind))
            goto fail;
            
        verbose("The PC register in thread %s points at address %p, "
                "which contains %s instruction '%s'. It will "
                "be temporary replaced by a breakpoint instruction. The thread "
                "will then be restarted. A SIGILL or SIGTRAP signal should be "
                "received immediately after thread restart.",
                str_thread(thread), (void *) address, insn_kind_str(kind), arm_disassemble(insn, kind));
                
        /* Patch instruction. */
        if (!patch_insn(thread, address, kind, get_breakpoint_insn(kind)))
            goto fail;
            
    } else {
        /* The address pointed by the PC is invalid. Running the thread should
         * cause a SIGSEGV. */
        verbose("The PC register in thread %s points at address %p, "
                "which is invalid (not inside a executable memory segment). "
                "It will be restarted without any patching. A SIGSEGV signal "
                "should be received immediately after thread restart.",
                str_thread(thread), (void *) address);
    }
    
    thread_continue(thread, 0);
    
    /* Wait until the program is stopped by a signal. */
    while (1) {
        thread_wait(thread, false);
        
        if (thread->state.dead)
            goto fail;
            
        if ((thread->state.signo == SIGSEGV) || (thread->state.signo == SIGTRAP) || (thread->state.signo == SIGBUS)) {
            break;
        }
        
        warning("Unexpected signal %s received during restopping of thread %s. The signal will be delivered.",
                str_signal(thread->state.signo), str_thread(thread));
                
        /* Deliver the signal. */
        thread_continue(thread, 0);
    }
    
    signo = thread->state.signo;
    thread->state.signo = 0;
    
    /* The process stopped, read new register values. */
    if (!thread_get_regs(thread, &regs[1]))
        goto fail;
        
    /* Warn about any abnormalities. */
    if (regs[1].ARM_pc != regs[0].ARM_pc) {
        warning("Unexpected change of PC register during restopping of %s.", str_thread(thread));
    }
    if (regs[1].ARM_lr != regs[0].ARM_lr) {
        warning("Unexpected change of LR register during restopping of %s.", str_thread(thread));
    }
    if (regs[1].ARM_sp != regs[0].ARM_sp) {
        warning("Unexpected change of SP register during restopping of %s.", str_thread(thread));
    }
    
    /* Restore old register values. */
    if (!thread_set_regs(thread, &regs[0]))
        goto fail;
        
    if (patch) {
        if ((signo != SIGILL) && (signo != SIGTRAP)) {
            warning("Thread %s was stopped by unexpected signal %s. Ignoring.",
                    str_thread(thread), str_signal(signo));
        }
        /* Revert original instruction */
        patch_insn(thread, address, kind, insn);
    } else {
        if ((signo != SIGSEGV)) {
            warning("%s was stopped by unexpected signal %s. Ignoring.",
                    str_thread(thread), str_signal(signo));
        }
    }
    
    info("Finished restop of %s.", str_thread(thread));
    
    thread->state.slavemode = false;
    if (!thread->state.dead)
        return true;
        
fail:
    assert(thread->state.dead);
    error("Thread %s died during restop operation.", str_thread(thread));
    return false;
}