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 }
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 }