Exemplo n.º 1
0
bool
vm_interrupt(VMState *state, VMInterruptType type, ...)
{
    va_list args;
    VMInterruptItem *item;
    unsigned int cycles;

    if (state->interrupt_policy == VM_POLICY_INTERRUPT_NEVER)
        return true;

    va_start(args, type);
    item = NULL;

    switch (type) {
    case VM_INTERRUPT_TIMER:
        cycles = va_arg(args, unsigned int);
        item = vm_new_interrupt_item(VM_INTERRUPT_TIMER,
                                     state->cycles + cycles);
        break;
    default:
        vm_seterrno(VM_NO_SUCH_INTERRUPT_TYPE_SUPPORT_ERROR);
        return false;
    }
    if(!item)
        return false;

    item->next = state->interrupts;
    state->interrupts = item;
    va_end(args);
    return true;
}
Exemplo n.º 2
0
static OPCODE_TYPE *
_get_location(VMState *state, VMInfoType type, size_t addr)
{
    OPCODE_TYPE *location = NULL;

    switch (type) {
    case VM_INFO_REGISTER:
        location = state->registers;
        if (addr >= nregisters)
            goto error;
        break;
    case VM_INFO_RAM:
        location = state->ram;
        if (addr >= ramsize)
            goto error;
        break;
    case VM_INFO_PIN:
        location = state->pins + pinoffset;
        if (addr >= npins)
            goto error;
        break;
    }

    return location + addr;

error:
    vm_seterrno(VM_OUT_OF_BOUNDS_ERROR);
    return NULL;
}
Exemplo n.º 3
0
Opcode *
get_opcode(VMState *state, PC_TYPE pc)
{
    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 NULL;
    }

    return state->instructions + pc;
}
Exemplo n.º 4
0
static char *
_get_location(VMState *state, VMInfoType type, size_t addr, int *nbytes)
{
    struct _mapping *mapping = get_info_type_mapping(type);
   
    if (addr < 0 ||addr >= mapping->end) {
#       ifdef VM_DEBUG
            printf("address: %lu, type: %s\n", addr, mapping->name);
#       endif
        vm_seterrno(VM_OUT_OF_BOUNDS_ERROR);
        return NULL;
    }

    /* Address within indicated address space. */
    if (nbytes)
        *nbytes = mapping->size;
    return state->chunk + mapping->offset + addr; 
}
Exemplo n.º 5
0
/* Parse an ELF file.
See http://www.skyfree.org/linux/references/ELF_Format.pdf for a description
of the ELF format. */
static bool
_read_elf(VMState *state, char *program, size_t program_size)
{
    Elf32_Ehdr *ehdr;
    char elfclass;

    ehdr = (Elf32_Ehdr *) program;
    if (ehdr->e_ident[EI_MAG0] == 0x7f &&
            ehdr->e_ident[EI_MAG1] == 'E' &&
            ehdr->e_ident[EI_MAG2] == 'L' &&
            ehdr->e_ident[EI_MAG3] == 'F' &&
            (elfclass = ehdr->e_ident[EI_CLASS]) != ELFCLASSNONE)
    {
        /* valid ELF file */
        if (elfclass == ELFCLASS32)
            return _elf32_read(state, program, program_size);
        else
            return _elf64_read(state, program, program_size);
    } else {
        vm_seterrno(VM_NOT_ELF);
        return false;
    }
}
Exemplo n.º 6
0
/* Load the loadable segments of the program into the VMState. Disassemble
   The Executable Segment. */
static bool
_elf32_read(VMState *state, char *program, size_t program_size)
{
    Elf32_Ehdr *ehdr;
    Elf32_Phdr *phdr;
    char *rom;
    int i;
    struct _mapping *rommapping = get_info_type_mapping(VM_INFO_ROM);

    rom = (char *) state->chunk + rommapping->offset;
    ehdr = (Elf32_Ehdr *) program;
    
    SETPC(state, ehdr->e_entry);

    if (!ehdr->e_phoff) {
        vm_seterrno(VM_NO_SEGMENTS);
        return false;
    }
    
    phdr = (Elf32_Phdr *) (program + ehdr->e_phoff);
    for (i = 0; i < ehdr->e_phnum; i++) {
        if (phdr->p_type & PT_LOAD) {
            char *startaddr;
    
            startaddr = rom + LOAD_ADDRESS;
    
            if (phdr->p_flags & PF_X) {
                /* executable segment, disassemble */
                
                if (state->instructions) {
                    /* Will there ever be multiple executable segments?
                       Text and data segments may both be executable. */
                    vm_seterrno(VM_MULTIPLE_EXECUTABLE_SEGMENTS);
                    return false;
                }
                state->instructions_size = (phdr->p_filesz / 
                                            sizeof(OPCODE_TYPE));
                
                state->instructions = disassemble(
                    (OPCODE_TYPE *) (program + phdr->p_offset),
                    state->instructions_size);
                
                state->executable_segment_offset = LOAD_ADDRESS;
            }
            
            if (LOAD_ADDRESS + phdr->p_memsz > 
                rommapping->end - rommapping->offset) {
                vm_seterrno(VM_ERROR_PROGRAM_TOO_BIG);
                return false;
            }
            
            /* load segment into the ROM of the VM */
            memcpy(startaddr, program + phdr->p_offset, phdr->p_filesz);
            
            /* NUL the rest */
            memset(startaddr + phdr->p_filesz, 0, 
                   phdr->p_memsz - phdr->p_filesz);
        }
        phdr++;
    }
    
    if (!_vm_errno && !state->instructions)
        vm_seterrno(VM_NO_EXECUTABLE_SEGMENT);
    
    return (bool) state->instructions;
}
Exemplo n.º 7
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
}
Exemplo n.º 8
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
}