> What do you believe other OpenOCD users could use such file IO for?
>
> I have used it in the past when running test suites that
> require test large vectors & writing back test results 
> that don't fit/should not be stored on the target but 
> rather the GDB host. Not the sort of thing that I expect
> the vast hordes to do, but definitely the savvy 
> OpenOCD hacker could do such a thing.

That's a good example. I mainly use it so that the output from debug printf
statements appears on the GDB console (stdin/stdout get mapped to the GDB
console). You might also have an application that needs to save some data
that it generates on to a PC. This is a very simple way to do that, without
requiring much to be implemented on the target.

> W.r.t. the patch, I haven't looked at it yet, 
> but I'm intrigued. I recall that the whole 
> debug_reason scheme in OpenOCD didn't leave 
> me with a warm fuzzy feeling though.

If it helps to explain it, I've attached some example code showing how the
target specific code could be implemented.

Cheers,
Jon
/* Map target system call numbers to OpenOCD enums. Target O/S is 
newlib/libgloss. */
static enum target_syscall cpu_map_syscall(uint32_t target_syscall)
{
    switch (target_syscall)
    {
    case 5:   return TARGET_SYSCALL_OPEN;
    case 6:   return TARGET_SYSCALL_CLOSE;
    case 3:   return TARGET_SYSCALL_READ;
    case 4:   return TARGET_SYSCALL_WRITE;
    case 19:  return TARGET_SYSCALL_LSEEK;
    case 38:  return TARGET_SYSCALL_RENAME;
    case 10:  return TARGET_SYSCALL_UNLINK;
    case 106: return TARGET_SYSCALL_STAT;
    case 28:  return TARGET_SYSCALL_FSTAT;
    case 78:  return TARGET_SYSCALL_GETTIMEOFDAY;
    case 256: return TARGET_SYSCALL_ISATTY;
    case 260: return TARGET_SYSCALL_SYSTEM;
    default:  return TARGET_SYSCALL_UNSUPPORTED;
    }
}

/* Extract system call number and parameters. */
static void cpu_get_syscall_params(target_t *target)
{
        cpu_common_t *cpu = target->arch_info;
        cpu_jtag_t *jtag_info = &cpu->jtag_info;
    int a0 = 8, sc = 1;

    target->syscall = 
cpu_map_syscall(buf_get_u32(cpu->core_cache->reg_list[sc].value, 0, 32));
    target->syscall_params[0] = 
(uint64_t)buf_get_u32(cpu->core_cache->reg_list[a0].value, 0, 32);
    target->syscall_params[1] = 
(uint64_t)buf_get_u32(cpu->core_cache->reg_list[a0+1].value, 0, 32);
    target->syscall_params[2] = 
(uint64_t)buf_get_u32(cpu->core_cache->reg_list[a0+2].value, 0, 32);
} 

/* Determine if we halted due to a breakpoint or watchpoint or something else.  
*/
int cpu_examine_debug_reason(target_t *target)
{
        cpu_common_t *cpu = target->arch_info;
    int retval = ERROR_OK;
    uint32_t eid;
    
        if ((target->debug_reason != DBG_REASON_DBGRQ)
                && (target->debug_reason != DBG_REASON_SINGLESTEP))
        {
        eid = buf_get_u32(cpu->core_cache->reg_list[CPU_THREAD_EID].value, 0, 
32);
        switch (eid)
        {
        case CPU_EID_NMI:
            target->debug_reason = DBG_REASON_SIGNAL;
            target->signal = TARGET_SIGNAL_INT;
            break;                
        case CPU_EID_INST_BREAKPOINT:
            target->debug_reason = DBG_REASON_BREAKPOINT;
            break;
        case CPU_EID_DATA_BREAKPOINT:
            target->debug_reason = DBG_REASON_WATCHPOINT;
            break;
        case CPU_EID_UNSUPPORTED:   
        case CPU_EID_PRIVILEGE_VIOLATION:
            target->debug_reason = DBG_REASON_SIGNAL;
            target->signal = TARGET_SIGNAL_ILL;
            break;
        case CPU_EID_INST_BUS_ERROR:
        case CPU_EID_DATA_BUS_ERROR:
            target->debug_reason = DBG_REASON_SIGNAL;
            target->signal = TARGET_SIGNAL_SEGV;
            break;
        case CPU_EID_ALIGNMENT_ERROR:
            target->debug_reason = DBG_REASON_SIGNAL;
            target->signal = TARGET_SIGNAL_BUS;
            break;    
        case CPU_EID_ARITHMETIC:
            target->debug_reason = DBG_REASON_SIGNAL;
            target->signal = TARGET_SIGNAL_FPE;
            break;
        case CPU_EID_SYSTEM_CALL:
            target->debug_reason = DBG_REASON_SYSCALL;
            cpu_get_syscall_params(target);
            break;                             
        default:
            if ((eid >= CPU_EID_INTERRUPT_0) && (eid <= CPU_EID_INTERRUPT_15))
            {
                target->debug_reason = DBG_REASON_SIGNAL;
                target->signal = SIGINT;
            }
            else
            {
                LOG_ERROR("Broke for reason other than breakpoint/watchpoint. 
EID = %ld\n", eid);
                target->debug_reason = DBG_REASON_UNDEFINED;
            }
            break;
        }
        }
        
        return retval;
}

int cpu_syscall_resume(struct target_s *target, int64_t retcode, uint32_t 
err_no, uint32_t ctrl_c)
{
        /* get pointers to arch-specific information */
        cpu_common_t *cpu = target->arch_info;
        cpu_jtag_t *jtag_info = &cpu->jtag_info;
    int a0 = 8;

        if (target->state != TARGET_HALTED)
        {
                LOG_WARNING("target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }

    /* Increment PC over system call instruction */
        buf_set_u32(cpu->core_cache->reg_list[CPU_PC].value, 0, 32, 
                buf_get_u32(cpu->core_cache->reg_list[CPU_PC].value, 0, 32) + 
1);       
        cpu->core_cache->reg_list[CPU_PC].dirty = 1;
        cpu->core_cache->reg_list[CPU_PC].valid = 1;

    /* If an error occurs, the return value is -errno.
       No need to map value as GDB prototcol values are the same as for the 
target. */
    if (retcode == -1)
        retcode = -err_no;

    /* Set return value. */
    buf_set_u32(cpu->core_cache->reg_list[a0].value, 0, 32, (uint32_t)(retcode 
& 0xffffffff));
        cpu->core_cache->reg_list[a0].dirty = 1;
        cpu->core_cache->reg_list[a0].valid = 1;

        /* restore context */
        cpu_restore_context(target);

        target_call_event_callbacks(target, TARGET_EVENT_RESUMED);

        /* exit debug mode */
        cpu_jtag_exit_debug(jtag_info, 1);
        target->debug_reason = DBG_REASON_NOTHALTED;

        /* registers are now invalid */
        cpu_invalidate_core_regs(target);

    target->state = TARGET_RUNNING;
        target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
        LOG_DEBUG("target resumed after syscall ");

    return ERROR_OK;
}
_______________________________________________
Openocd-development mailing list
Openocd-development@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to