> 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
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development