> 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