Exemple #1
0
static bool
_vm_step(VMState *state, int nsteps, VMStateDiff **diff, bool *hit_bp, bool first)
{
    Opcode *opcode;
    opcode_handler *handler;
    VMInterruptCallable *callable;
    VMInterruptItem *interrupt_item, *previous_interrupt_item = NULL;
    VMStateDiff *newdiff = NULL;

#define RETURN(x) do { RELEASE_STATE(state); return (x); } while(0)

    *hit_bp = false;
    while (nsteps > 0) {
        /* acquire and release for every step. This allows for some nice
           contention! */
        ACQUIRE_STATE(state);
        if (state->break_async) {
            RETURN(true);
        }

        callable = state->interrupt_callables;
        while (callable) {
            if (!callable->func(state, callable->argument)) {
                vm_seterrno(VM_INTERRUPT_CALLABLE_ERROR);
                RETURN(false);
            }
            callable = callable->next;
        }


        if (!first && _hit_breakpoint(state)) {
            /* breakpoint */
            *hit_bp = true;
            RETURN(true);
        } else {

            /* PC error checking */
            {
                /* offsets in bytes */
                size_t pc;

                pc = GETPC(state);

                if (pc < state->executable_segment_offset ||
                        pc >= state->instructions_size) {
                    vm_seterrno(VM_PC_OUT_OF_BOUNDS);
#ifdef VM_DEBUG
                    printf(LOCATION " pc: %lu max pc: %lu\n",
                           (unsigned long) pc,
                           (unsigned long) state->instructions_size - 1);
#endif
                    RETURN(false);
                }
            }

            /* Save changes in diff */
            if (diff) {
                if (!(newdiff = vm_newdiff()))
                    RETURN(false);

                newdiff->next = *diff;
                newdiff->pc = state->registers[PC];
                newdiff->cycles = state->cycles;

                *diff = newdiff;
            }

            if (state->interrupt_policy != VM_POLICY_INTERRUPT_NEVER) {
                if (state->interrupts != NULL) {
                    /* There are interrupts specified in the queue, call the
                       user-written set_interrupt callback. */
                    if (!set_interrupt(state, newdiff))
                        RETURN(false);
                }

                /* For every step, handle an interrupt in the debuggee (if present)
                   bytes calling a user-written function (or a default noop). */
                if (!handle_interrupt(state, newdiff)) {
                    RETURN(false);
                }
            }

            /* Execute instruction */
            opcode = (Opcode *) OPCODE(state);
            handler = opcode_handlers[opcode->opcode_index].handler;
            if (!handler(state, newdiff, opcode->instruction)) {
                RETURN(state->stopped_running);
            }
        }
        nsteps--;
        first = false;
        RELEASE_STATE(state);
    }

    return true;
#undef RETURN
}
Exemple #2
0
static bool 
_vm_step(VMState *state, unsigned long nsteps, VMStateDiff **diff, 
         bool *hit_bp, bool first)
{
    VMInterruptCallable *callable;
    VMStateDiff *newdiff = NULL;
    
#define RETURN(x) do { RELEASE_STATE(state); return (x); } while(0)
    
    *hit_bp = false;
    while (nsteps > 0) {
        /* acquire and release for every step. This allows for some nice 
           contention! */
        ACQUIRE_STATE(state);
        if (state->break_async) {
            RETURN(true);
        }
        
        callable = state->interrupt_callables;
        while (callable) {
            if (!callable->func(state, callable->argument)) {
                vm_seterrno(VM_INTERRUPT_CALLABLE_ERROR);
                RETURN(false);
            }
            callable = callable->next;
        }
        
        
        if (!first && _hit_breakpoint(state)) {
            /* breakpoint */
            *hit_bp = true;
            RETURN(true);
        } else {
            Opcode *opcode;
            opcode_handler *handler;

            /* Do the PC validity checks before updating any diffs. */
            if (!(opcode = get_opcode(state, GETPC(state))))
                RETURN(false);
           
            /* Save changes in diff */
            if (diff) {
                if (!(newdiff = vm_newdiff()))
                    RETURN(false);
                
                newdiff->next = *diff;
                newdiff->pc = GETPC(state);
                newdiff->cycles = state->cycles;
                
                *diff = newdiff;
            }
            
            if (state->interrupt_policy != VM_POLICY_INTERRUPT_NEVER) {
                if (state->interrupts != NULL) {
                    /* There are interrupts specified in the queue, call the 
                       user-written set_interrupt callback. */
                    if (!set_interrupt(state, newdiff))
                        RETURN(false);
                }
                
                /* For every step, handle an interrupt in the debuggee (if present)
                   bytes calling a user-written function (or a default noop). */
                if (!handle_interrupt(state, newdiff)) {
                    RETURN(false);
                }
            }
            
            /* Execute instruction */
            handler = opcode_handlers[opcode->opcode_index].handler;
            if (!handler(state, newdiff, opcode->instruction))
                RETURN(state->stopped_running);
        }

        nsteps--;
        first = false;
        RELEASE_STATE(state);
    }
    
    return true;
#undef RETURN
}