static int avr32_ap7k_poll(struct target *target) { uint32_t ds; int retval; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); if (retval != ERROR_OK) return retval; /* check for processor halted */ if (ds & OCDREG_DS_DBA) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else target->state = TARGET_RUNNING; return ERROR_OK; }
int arc_ocd_poll(struct target *target) { uint32_t status; struct arc32_common *arc32 = target_to_arc32(target); /* gdb calls continuously through this arc_poll() function */ CHECK_RETVAL(arc_jtag_status(&arc32->jtag_info, &status)); /* check for processor halted */ if (status & ARC_JTAG_STAT_RU) { target->state = TARGET_RUNNING; } else { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; LOG_DEBUG("ARC core is halted or in reset."); CHECK_RETVAL(arc_dbg_debug_entry(target)); target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; LOG_DEBUG("ARC core is in debug running mode"); CHECK_RETVAL(arc_dbg_debug_entry(target)); target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } return ERROR_OK; }
/* poll current target status */ static int arm11_poll(struct target *target) { int retval; struct arm11_common *arm11 = target_to_arm11(target); CHECK_RETVAL(arm11_check_init(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) { if (target->state != TARGET_HALTED) { enum target_state old_state = target->state; LOG_DEBUG("enter TARGET_HALTED"); retval = arm11_debug_entry(arm11); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, (old_state == TARGET_DEBUG_RUNNING) ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED); } } else { if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { LOG_DEBUG("enter TARGET_RUNNING"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } } return ERROR_OK; }
int arm926ejs_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm926ejs_common *arm926ejs = target_to_arm926(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; retval = target_halt(target); if (retval != ERROR_OK) return retval; int64_t then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 1) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = 1; arm->pc->valid = 1; retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; arm926ejs->armv4_5_mmu.mmu_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); }
/* target execution control */ static int arm11_halt(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_UNKNOWN) { arm11->simulate_reset_on_next_halt = true; } if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } arm11_add_IR(arm11, ARM11_HALT, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_DSCR(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } enum target_state old_state = target->state; CHECK_RETVAL(arm11_debug_entry(arm11)); CHECK_RETVAL( target_call_event_callbacks(target, old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED)); return ERROR_OK; }
/* we need to expose the update to be able to complete the reset at SoC level */ int lakemont_update_after_probemode_entry(struct target *t) { if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; return target_call_event_callbacks(t, TARGET_EVENT_HALTED); }
static int do_resume(struct target *t) { /* needs proper handling later */ t->state = TARGET_DEBUG_RUNNING; if (restore_context(t) != ERROR_OK) return ERROR_FAIL; if (exit_probemode(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_RUNNING; t->debug_reason = DBG_REASON_NOTHALTED; LOG_USER("target running"); return target_call_event_callbacks(t, TARGET_EVENT_RESUMED); }
static int xtensa_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct xtensa_common *xtensa = target_to_xtensa(target); uint8_t buf[4]; int res; LOG_DEBUG("%s current=%d address=%04" PRIx32, __func__, current, address); if (target->state != TARGET_HALTED) { LOG_WARNING("%s: target not halted", __func__); return ERROR_TARGET_NOT_HALTED; } if(address && !current) { buf_set_u32(buf, 0, 32, address); xtensa_set_core_reg(&xtensa->core_cache->reg_list[XT_REG_IDX_PC], buf); } xtensa_restore_context(target); register_cache_invalidate(xtensa->core_cache); res = xtensa_tap_queue_cpu_inst(target, XT_INS_ISYNC); if (res != ERROR_OK) return res; res = jtag_execute_queue(); if (res != ERROR_OK) return res; res = xtensa_tap_exec(target, TAP_INS_LOAD_DI, XT_INS_RFDO_1, 0); if(res != ERROR_OK) { LOG_ERROR("Failed to issue LoadDI instruction. Can't resume."); return ERROR_FAIL; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; res = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return res; }
static int or1k_resume_or_step(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution, int step) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM]; LOG_DEBUG("Addr: 0x%" PRIx32 ", stepping: %s, handle breakpoints %s\n", address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no"); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* current ? continue on current pc : continue at <address> */ if (!current) buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32, address); int retval = or1k_restore_context(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_restore_context"); return retval; } /* read debug registers (starting from DMR1 register) */ retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); if (retval != ERROR_OK) { LOG_ERROR("Error while reading debug registers"); return retval; } /* Clear Debug Reason Register (DRR) */ debug_reg_list[OR1K_DEBUG_REG_DRR] = 0; /* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */ debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB; if (step) /* Set the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT; else /* Clear the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT); /* Set traps to be handled by the debug unit in the Debug Stop Register (DSR). Check if we have any software breakpoints in place before setting this value - the kernel, for instance, relies on l.trap instructions not stalling the processor ! */ if (is_any_soft_breakpoint(target) == true) debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE; /* Write debug registers (starting from DMR1 register) */ retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); if (retval != ERROR_OK) { LOG_ERROR("Error while writing back debug registers"); return retval; } resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32); /* The front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("Unset breakpoint at 0x%08" PRIx32, breakpoint->address); retval = or1k_remove_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } } /* Unstall time */ retval = du_core->or1k_cpu_stall(&or1k->jtag, CPU_UNSTALL); if (retval != ERROR_OK) { LOG_ERROR("Error while unstalling the CPU"); return retval; } if (step) target->debug_reason = DBG_REASON_SINGLESTEP; else target->debug_reason = DBG_REASON_NOTHALTED; /* Registers are now invalid */ register_cache_invalidate(or1k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("Target resumed at 0x%08" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("Target debug resumed at 0x%08" PRIx32, resume_pc); } return ERROR_OK; }
static int or1k_poll(struct target *target) { int retval; int running; retval = or1k_is_cpu_running(target, &running); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_is_cpu_running"); return retval; } /* check for processor halted */ if (!running) { /* It's actually stalled, so update our software's state */ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else { /* ... target is running */ /* If target was supposed to be stalled, stall it again */ if (target->state == TARGET_HALTED) { target->state = TARGET_RUNNING; retval = or1k_halt(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_halt"); return retval; } retval = or1k_debug_entry(target); if (retval != ERROR_OK) { LOG_ERROR("Error while calling or1k_debug_entry"); return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } target->state = TARGET_RUNNING; } return ERROR_OK; }
static int xtensa_poll(struct target *target) { struct xtensa_common *xtensa = target_to_xtensa(target); struct reg *reg; uint32_t dosr; int res; /* OCD guide 2.9.2 points out no reliable way to detect core reset. So, even though this ENABLE_OCD is nearly always a No-Op, we send it on every poll just in case the target has reset and gone back to Running state (in which case this moves it to OCD Run State. */ res = xtensa_tap_queue(target, TAP_INS_ENABLE_OCD, NULL, NULL); if(res != ERROR_OK) { LOG_ERROR("Failed to queue EnableOCD instruction."); return ERROR_FAIL; } res = xtensa_tap_exec(target, TAP_INS_READ_DOSR, 0, &dosr); if(res != ERROR_OK) { LOG_ERROR("Failed to read DOSR. Not Xtensa OCD?"); return ERROR_FAIL; } if(dosr & (DOSR_IN_OCD_MODE)) { if (target->state != TARGET_HALTED) { if (target->state != TARGET_UNKNOWN && (dosr & DOSR_EXCEPTION) == 0) { LOG_WARNING("%s: DOSR has set InOCDMode without the Exception flag. Unexpected. DOSR=0x%02x", __func__, dosr); } int state = target->state; xtensa->state = XT_OCD_HALT; target->state = TARGET_HALTED; register_cache_invalidate(xtensa->core_cache); xtensa_save_context(target); if (state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { //target->debug_reason is checked in gdb_last_signal() that is invoked as a result of calling target_call_event_callbacks() below. //Unless we specify it, GDB will get confused and report the stop to the user on its internal breakpoints. uint32_t dbgcause = buf_get_u32(xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].value, 0, 32); if (dbgcause & 0x20) //Debug interrupt target->debug_reason = DBG_REASON_DBGRQ; else if (dbgcause & 0x01) //ICOUNT match target->debug_reason = DBG_REASON_SINGLESTEP; else target->debug_reason = DBG_REASON_BREAKPOINT; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } LOG_DEBUG("target->state: %s", target_state_name(target)); reg = &xtensa->core_cache->reg_list[XT_REG_IDX_PC]; LOG_INFO("halted: PC: 0x%" PRIx32, buf_get_u32(reg->value, 0, 32)); reg = &xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE]; LOG_INFO("debug cause: 0x%" PRIx32, buf_get_u32(reg->value, 0, 32)); } else { if (s_FeedWatchdogDuringStops) xtensa_feed_esp8266_watchdog(target); } } else if(target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING){ xtensa->state = XT_OCD_RUN; target->state = TARGET_RUNNING; } return ERROR_OK; }
static int arm11_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { // LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", // current, address, handle_breakpoints, debug_execution); struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } address = arm11_nextpc(arm11, current, address); LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : ""); /* clear breakpoints/watchpoints and VCR*/ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); if (!debug_execution) target_free_all_working_areas(target); /* Should we skip over breakpoints matching the PC? */ if (handle_breakpoints) { struct breakpoint *bp; for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { LOG_DEBUG("must step over %08" PRIx32 "", bp->address); arm11_step(target, 1, 0, 0); break; } } } /* activate all breakpoints */ if (true) { struct breakpoint *bp; unsigned brp_num = 0; for (bp = target->breakpoints; bp; bp = bp->next) { struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0 + brp_num; brp[0].value = bp->address; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0 + brp_num; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); LOG_DEBUG("Add BP %d at %08" PRIx32, brp_num, bp->address); brp_num++; } if (arm11->vcr) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); } /* activate all watchpoints and breakpoints */ CHECK_RETVAL(arm11_leave_debug_state(arm11, true)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); if (arm11->dscr & DSCR_CORE_RESTARTED) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); return ERROR_OK; }
int lakemont_step(struct target *t, int current, uint32_t address, int handle_breakpoints) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t pmcr = buf_get_u32(x86_32->cache->reg_list[PMCR].value, 0, 32); struct breakpoint *bp = NULL; int retval = ERROR_OK; uint32_t tapstatus = 0; if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; bp = breakpoint_find(t, eip); if (retval == ERROR_OK && bp != NULL/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_remove_breakpoint(t, bp); } /* Set EFLAGS[TF] and PMCR[IR], exit pm and wait for PRDY# */ LOG_DEBUG("modifying PMCR = 0x%08" PRIx32 " and EFLAGS = 0x%08" PRIx32, pmcr, eflags); eflags = eflags | (EFLAGS_TF | EFLAGS_RF); buf_set_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32, eflags); buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); LOG_DEBUG("EFLAGS [TF] [RF] bits set=0x%08" PRIx32 ", PMCR=0x%08" PRIx32 ", EIP=0x%08" PRIx32, eflags, pmcr, eip); tapstatus = get_tapstatus(t); t->debug_reason = DBG_REASON_SINGLESTEP; t->state = TARGET_DEBUG_RUNNING; if (restore_context(t) != ERROR_OK) return ERROR_FAIL; if (exit_probemode(t) != ERROR_OK) return ERROR_FAIL; target_call_event_callbacks(t, TARGET_EVENT_RESUMED); tapstatus = get_tapstatus(t); if (tapstatus & (TS_PM_BIT | TS_EN_PM_BIT | TS_PRDY_BIT | TS_PMCR_BIT)) { /* target has stopped */ if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; LOG_USER("step done from EIP 0x%08" PRIx32 " to 0x%08" PRIx32, eip, buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32)); target_call_event_callbacks(t, TARGET_EVENT_HALTED); } else { /* target didn't stop * I hope the poll() will catch it, but the deleted breakpoint is gone */ LOG_ERROR("%s target didn't stop after executing a single step", __func__); t->state = TARGET_RUNNING; return ERROR_FAIL; } /* try to re-apply the breakpoint, even of step failed * TODO: When a bp was set, we should try to stop the target - fix the return above */ if (bp != NULL/*&& bp->type == BKPT_SOFT*/) { /* TODO: This should only be done for software breakpoints. * Stepping from hardware breakpoints should be possible with the resume flag * Needs testing. */ retval = x86_32_common_add_breakpoint(t, bp); } return retval; }
static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval, result; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: explore mapping requests to GDB's "File-I/O Remote * Protocol Extension" ... when GDB is active. */ switch (r0) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); if (l <= 255 && m <= 11) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) result = dup(STDIN_FILENO); else result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); result = close(fd); arm->semihosting_errno = errno; } break; case 0x03: /* SYS_WRITEC */ { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); result = 0; } break; case 0x04: /* SYS_WRITE0 */ do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); result = 0; break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = write(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) result = l - result; free(buf); } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { result = read(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) { retval = target_write_buffer(target, a, result, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = l - result; } free(buf); } } break; case 0x07: /* SYS_READC */ result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = isatty(target_buffer_get_u32(target, params+0)); break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (result == pos) result = 0; } break; case 0x0c: /* SYS_FLEN */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; result = fstat(fd, &buf); if (result == -1) { arm->semihosting_errno = errno; result = -1; break; } result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; result = remove((char *)fn); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x11: /* SYS_TIME */ result = time(NULL); break; case 0x13: /* SYS_ERRNO */ result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = "foobar"; uint32_t s = strlen(arg) + 1; if (l < s) result = -1; else { retval = target_write_buffer(target, a, s, (uint8_t *)arg); if (retval != ERROR_OK) return retval; result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x12: /* SYS_SYSTEM */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t len = target_buffer_get_u32(target, params+4); uint32_t c_ptr = target_buffer_get_u32(target, params); uint8_t cmd[256]; if (len > 255) { result = -1; arm->semihosting_errno = EINVAL; } else { memset(cmd, 0x0, 256); retval = target_read_memory(target, c_ptr, 1, len, cmd); if (retval != ERROR_OK) return retval; else result = system((const char *)cmd); } } break; case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); result = -1; arm->semihosting_errno = ENOTSUP; } /* resume execution to the original mode */ /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = 1; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = 1; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; } return target_resume(target, 1, 0, 0, 0); }
static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); struct gdb_fileio_info *fileio_info = target->fileio_info; uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: unsupported semihosting fileio operations could be * implemented if we had a small working area at our disposal. */ switch ((arm->semihosting_op = r0)) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (arm->is_semihosting_fileio) { if (strcmp((char *)fn, ":tt") == 0) arm->semihosting_result = 0; else { arm->semihosting_hit_fileio = true; fileio_info->identifier = "open"; fileio_info->param_1 = a; fileio_info->param_2 = l; fileio_info->param_3 = open_modeflags[m]; fileio_info->param_4 = 0644; } } else { if (l <= 255 && m <= 11) { if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) arm->semihosting_result = dup(STDIN_FILENO); else arm->semihosting_result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "close"; fileio_info->param_1 = fd; } else { arm->semihosting_result = close(fd); arm->semihosting_errno = errno; } } break; case 0x03: /* SYS_WRITEC */ if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = r1; fileio_info->param_3 = 1; } else { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); arm->semihosting_result = 0; } break; case 0x04: /* SYS_WRITE0 */ if (arm->is_semihosting_fileio) { size_t count = 0; for (uint32_t a = r1;; a++) { unsigned char c; retval = target_read_memory(target, a, 1, 1, &c); if (retval != ERROR_OK) return retval; if (c == '\0') break; count++; } arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = r1; fileio_info->param_3 = count; } else { do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); arm->semihosting_result = 0; } break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = fd; fileio_info->param_2 = a; fileio_info->param_3 = l; } else { uint8_t *buf = malloc(l); if (!buf) { arm->semihosting_result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } arm->semihosting_result = write(fd, buf, l); arm->semihosting_errno = errno; if (arm->semihosting_result >= 0) arm->semihosting_result = l - arm->semihosting_result; free(buf); } } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "read"; fileio_info->param_1 = fd; fileio_info->param_2 = a; fileio_info->param_3 = l; } else { uint8_t *buf = malloc(l); if (!buf) { arm->semihosting_result = -1; arm->semihosting_errno = ENOMEM; } else { arm->semihosting_result = read(fd, buf, l); arm->semihosting_errno = errno; if (arm->semihosting_result >= 0) { retval = target_write_buffer(target, a, arm->semihosting_result, buf); if (retval != ERROR_OK) { free(buf); return retval; } arm->semihosting_result = l - arm->semihosting_result; } free(buf); } } } break; case 0x07: /* SYS_READC */ if (arm->is_semihosting_fileio) { LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } arm->semihosting_result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "isatty"; fileio_info->param_1 = r1; } else { retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0)); } break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "lseek"; fileio_info->param_1 = fd; fileio_info->param_2 = pos; fileio_info->param_3 = SEEK_SET; } else { arm->semihosting_result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (arm->semihosting_result == pos) arm->semihosting_result = 0; } } break; case 0x0c: /* SYS_FLEN */ if (arm->is_semihosting_fileio) { LOG_ERROR("SYS_FLEN not supported by semihosting fileio"); return ERROR_FAIL; } retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; arm->semihosting_result = fstat(fd, &buf); if (arm->semihosting_result == -1) { arm->semihosting_errno = errno; arm->semihosting_result = -1; break; } arm->semihosting_result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "unlink"; fileio_info->param_1 = a; fileio_info->param_2 = l; } else { if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; arm->semihosting_result = remove((char *)fn); arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "rename"; fileio_info->param_1 = a1; fileio_info->param_2 = l1; fileio_info->param_3 = a2; fileio_info->param_4 = l2; } else { if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; arm->semihosting_result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x11: /* SYS_TIME */ arm->semihosting_result = time(NULL); break; case 0x13: /* SYS_ERRNO */ arm->semihosting_result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : ""; uint32_t s = strlen(arg) + 1; if (l < s) arm->semihosting_result = -1; else { retval = target_write_buffer(target, a, s, (uint8_t *)arg); if (retval != ERROR_OK) return retval; arm->semihosting_result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x12: /* SYS_SYSTEM */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t len = target_buffer_get_u32(target, params+4); uint32_t c_ptr = target_buffer_get_u32(target, params); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "system"; fileio_info->param_1 = c_ptr; fileio_info->param_2 = len; } else { uint8_t cmd[256]; if (len > 255) { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } else { memset(cmd, 0x0, 256); retval = target_read_memory(target, c_ptr, 1, len, cmd); if (retval != ERROR_OK) return retval; else arm->semihosting_result = system((const char *)cmd); } } } break; case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); arm->semihosting_result = -1; arm->semihosting_errno = ENOTSUP; } return ERROR_OK; }
static int avr32_ap7k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); /* avr32_ap7k_enable_breakpoints(target); avr32_ap7k_enable_watchpoints(target); */ } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { #if 0 if (retval != ERROR_OK) return retval; #endif } resume_pc = buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32); avr32_ap7k_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); avr32_ap7k_set_breakpoint(target, breakpoint); #endif } } #if 0 /* enable interrupts if we are running */ avr32_ap7k_enable_interrupts(target, !debug_execution); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); #endif retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); if (retval != ERROR_OK) return retval; retval = avr32_jtag_exec(&ap7k->jtag, RETD); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(ap7k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; }
int lakemont_poll(struct target *t) { /* LMT1 PMCR register currently allows code breakpoints, data breakpoints, * single stepping and shutdowns to be redirected to PM but does not allow * redirecting into PM as a result of SMM enter and SMM exit */ uint32_t ts = get_tapstatus(t); if (ts == 0xFFFFFFFF && t->state != TARGET_DEBUG_RUNNING) { /* something is wrong here */ LOG_ERROR("tapstatus invalid - scan_chain serialization or locked JTAG access issues"); /* TODO: Give a hint that unlocking is wrong or maybe a * 'jtag arp_init' helps */ t->state = TARGET_DEBUG_RUNNING; return ERROR_OK; } if ((!(ts & TS_PM_BIT))) { if (t->state == TARGET_HALTED) { LOG_USER("target running for unknown reason"); } else if (t->state == TARGET_DEBUG_RUNNING) { LOG_USER("Debug running tapstatus=0x%08" PRIx32, ts); } LOG_DEBUG("tapstatus=0x%08" PRIx32, ts); t->state = TARGET_RUNNING; } if (t->state == TARGET_RUNNING || t->state == TARGET_DEBUG_RUNNING) { if (ts & TS_PM_BIT) { LOG_USER("redirect to PM, tapstatus=0x%08" PRIx32, get_tapstatus(t)); t->state = TARGET_DEBUG_RUNNING; if (save_context(t) != ERROR_OK) return ERROR_FAIL; if (halt_prep(t) != ERROR_OK) return ERROR_FAIL; t->state = TARGET_HALTED; t->debug_reason = DBG_REASON_UNDEFINED; struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eip = buf_get_u32(x86_32->cache->reg_list[EIP].value, 0, 32); uint32_t dr6 = buf_get_u32(x86_32->cache->reg_list[DR6].value, 0, 32); uint32_t hwbreakpoint = (uint32_t)-1; if (dr6 & DR6_BRKDETECT_0) hwbreakpoint = 0; if (dr6 & DR6_BRKDETECT_1) hwbreakpoint = 1; if (dr6 & DR6_BRKDETECT_2) hwbreakpoint = 2; if (dr6 & DR6_BRKDETECT_3) hwbreakpoint = 3; if (hwbreakpoint != (uint32_t)-1) { uint32_t dr7 = buf_get_u32(x86_32->cache->reg_list[DR7].value, 0, 32); uint32_t type = dr7 & (0x03 << (DR7_RW_SHIFT + hwbreakpoint*DR7_RW_LEN_SIZE)); if (type == DR7_BP_EXECUTE) { LOG_USER("hit hardware breakpoint (hwreg=%" PRIu32 ") at 0x%08" PRIx32, hwbreakpoint, eip); } else { uint32_t address = 0; switch (hwbreakpoint) { default: case 0: address = buf_get_u32(x86_32->cache->reg_list[DR0].value, 0, 32); break; case 1: address = buf_get_u32(x86_32->cache->reg_list[DR1].value, 0, 32); break; case 2: address = buf_get_u32(x86_32->cache->reg_list[DR2].value, 0, 32); break; case 3: address = buf_get_u32(x86_32->cache->reg_list[DR3].value, 0, 32); break; } LOG_USER("hit '%s' watchpoint for 0x%08" PRIx32 " (hwreg=%" PRIu32 ") at 0x%08" PRIx32, type == DR7_BP_WRITE ? "write" : "access", address, hwbreakpoint, eip); } t->debug_reason = DBG_REASON_BREAKPOINT; } else { /* Check if the target hit a software breakpoint. * ! Watch out: EIP is currently pointing after the breakpoint opcode */ struct breakpoint *bp = NULL; bp = breakpoint_find(t, eip-1); if (bp != NULL) { t->debug_reason = DBG_REASON_BREAKPOINT; if (bp->type == BKPT_SOFT) { /* The EIP is now pointing the the next byte after the * breakpoint instruction. This needs to be corrected. */ buf_set_u32(x86_32->cache->reg_list[EIP].value, 0, 32, eip-1); x86_32->cache->reg_list[EIP].dirty = 1; x86_32->cache->reg_list[EIP].valid = 1; LOG_USER("hit software breakpoint at 0x%08" PRIx32, eip-1); } else { /* it's not a hardware breakpoint (checked already in DR6 state) * and it's also not a software breakpoint ... */ LOG_USER("hit unknown breakpoint at 0x%08" PRIx32, eip); } } else { /* There is also the case that we hit an breakpoint instruction, * which was not set by us. This needs to be handled be the * application that introduced the breakpoint. */ LOG_USER("unknown break reason at 0x%08" PRIx32, eip); } } return target_call_event_callbacks(t, TARGET_EVENT_HALTED); } } return ERROR_OK; }
int armv7m_trace_tpiu_config(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_trace_config *trace_config = &armv7m->trace_config; int prescaler; int retval; target_unregister_timer_callback(armv7m_poll_trace, target); retval = adapter_config_trace(trace_config->config_type == INTERNAL, trace_config->pin_protocol, trace_config->port_size, &trace_config->trace_freq); if (retval != ERROR_OK) return retval; if (!trace_config->trace_freq) { LOG_ERROR("Trace port frequency is 0, can't enable TPIU"); return ERROR_FAIL; } prescaler = trace_config->traceclkin_freq / trace_config->trace_freq; if (trace_config->traceclkin_freq % trace_config->trace_freq) { prescaler++; int trace_freq = trace_config->traceclkin_freq / prescaler; LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead", trace_config->trace_freq, trace_config->traceclkin_freq, trace_freq); trace_config->trace_freq = trace_freq; retval = adapter_config_trace(trace_config->config_type == INTERNAL, trace_config->pin_protocol, trace_config->port_size, &trace_config->trace_freq); if (retval != ERROR_OK) return retval; } retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, TPIU_ACPR, prescaler - 1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol); if (retval != ERROR_OK) return retval; uint32_t ffcr; retval = target_read_u32(target, TPIU_FFCR, &ffcr); if (retval != ERROR_OK) return retval; if (trace_config->formatter) ffcr |= (1 << 1); else ffcr &= ~(1 << 1); retval = target_write_u32(target, TPIU_FFCR, ffcr); if (retval != ERROR_OK) return retval; if (trace_config->config_type == INTERNAL) target_register_timer_callback(armv7m_poll_trace, 1, 1, target); target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG); return ERROR_OK; }
static int arm11_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } struct arm11_common *arm11 = target_to_arm11(target); address = arm11_nextpc(arm11, current, address); LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : ""); /** \todo TODO: Thumb not supported here */ uint32_t next_instruction; CHECK_RETVAL(arm11_read_memory_word(arm11, address, &next_instruction)); /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping BKPT"); } /* skip over Wait for interrupt / Standby */ /* mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping WFI"); } /* ignore B to self */ else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe) { LOG_DEBUG("Not stepping jump to self"); } else { /** \todo TODO: check if break-/watchpoints make any sense at all in combination * with this. */ /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively * the VCR might be something worth looking into. */ /* Set up breakpoint for stepping */ struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0; if (arm11->hardware_step) { /* Hardware single stepping ("instruction address * mismatch") is used if enabled. It's not quite * exactly "run one instruction"; "branch to here" * loops won't break, neither will some other cases, * but it's probably the best default. * * Hardware single stepping isn't supported on v6 * debug modules. ARM1176 and v7 can support it... * * FIXME Thumb stepping likely needs to use 0x03 * or 0xc0 byte masks, not 0x0f. */ brp[0].value = address; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); } else { /* Sets a breakpoint on the next PC, as calculated * by instruction set simulation. * * REVISIT stepping Thumb on ARM1156 requires Thumb2 * support from the simulator. */ uint32_t next_pc; int retval; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) return retval; brp[0].value = next_pc; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); } CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); /* resume */ if (arm11->step_irq_enable) /* this disable should be redundant ... */ arm11->dscr &= ~DSCR_INT_DIS; else arm11->dscr |= DSCR_INT_DIS; CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* wait for halt */ int i = 0; while (1) { const uint32_t mask = DSCR_CORE_RESTARTED | DSCR_CORE_HALTED; CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); if ((arm11->dscr & mask) == mask) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } /* clear breakpoint */ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); /* save state */ CHECK_RETVAL(arm11_debug_entry(arm11)); /* restore default state */ arm11->dscr &= ~DSCR_INT_DIS; } target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; }
static int or1k_resume_or_step(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution, int step) { struct or1k_common *or1k = target_to_or1k(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; int retval; LOG_DEBUG(" - "); LOG_DEBUG(" addr: 0x%x, stepping: %d, handle breakpoints %d\n", address, step, handle_breakpoints); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); } /* current ? continue on current pc : continue at <address> */ if (!current) { buf_set_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32, address); } if (!step) { or1k_restore_context(target); } uint32_t debug_reg_list[OR1K_DEBUG_REG_NUM]; /* read debug registers (starting from DMR1 register) */ or1k_jtag_read_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); /* Clear Debug Reason Register (DRR) */ debug_reg_list[OR1K_DEBUG_REG_DRR] = 0; /* Clear watchpoint break generation in Debug Mode Register 2 (DMR2) */ debug_reg_list[OR1K_DEBUG_REG_DMR2] &= ~OR1K_DMR2_WGB; if (step) /* Set the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] |= OR1K_DMR1_ST | OR1K_DMR1_BT; else /* Clear the single step trigger in Debug Mode Register 1 (DMR1) */ debug_reg_list[OR1K_DEBUG_REG_DMR1] &= ~(OR1K_DMR1_ST | OR1K_DMR1_BT); /* Set traps to be handled by the debug unit in the Debug Stop Register (DSR) */ /* TODO - check if we have any software breakpoints in place before setting this value - the kernel, for instance, relies on l.trap instructions not stalling the processor! */ debug_reg_list[OR1K_DEBUG_REG_DSR] |= OR1K_DSR_TE; /* write debug registers (starting from DMR1 register) */ or1k_jtag_write_cpu(&or1k->jtag, OR1K_DMR1_CPU_REG_ADD, OR1K_DEBUG_REG_NUM, debug_reg_list); resume_pc = buf_get_u32(or1k->core_cache->reg_list[OR1K_REG_NPC].value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ if ((breakpoint = breakpoint_find(target, resume_pc))) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); #if 0 /* Do appropriate things here to remove breakpoint. */ #endif } } /* Unstall time */ /* Mohor debug if, clearing control register unstalls */ retval = or1k_jtag_write_cpu_cr(&or1k->jtag, 0, 0); if (retval != ERROR_OK) return retval; if (step) target->debug_reason = DBG_REASON_SINGLESTEP; else target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(or1k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; }