Esempio n. 1
0
/* When running a stand-alone SPE executable, we may need to skip one more
   exec event on startup, to get past the binfmt_misc loader.  */
static void
spu_skip_standalone_loader (void)
{
  if (target_has_execution && !current_inferior ()->attach_flag)
    {
      struct target_waitstatus ws;

      /* Only some kernels report an extra SIGTRAP with the binfmt_misc
	 loader; others do not.  In addition, if we have attached to an
	 already running inferior instead of starting a new one, we will
	 not see the extra SIGTRAP -- and we cannot readily distinguish
	 the two cases, in particular with the extended-remote target.

	 Thus we issue a single-step here.  If no extra SIGTRAP was pending,
	 this will step past the first instruction of the stand-alone SPE
	 executable loader, but we don't care about that.  */

      inferior_thread ()->control.in_infcall = 1; /* Suppress MI messages.  */

      target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
      target_wait (minus_one_ptid, &ws, 0);
      set_executing (minus_one_ptid, 0);

      inferior_thread ()->control.in_infcall = 0;
    }
}
static void
osf_solib_create_inferior_hook (void)
{
  /* Nothing to do for statically bound executables.  */

  if (symfile_objfile == NULL
      || symfile_objfile->obfd == NULL
      || ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
    return;

  /* Now run the target.  It will eventually get a SIGTRAP, at
     which point all of the libraries will have been mapped in and we
     can go groveling around in the rld structures to find
     out what we need to know about them. */

  clear_proceed_status ();
  stop_soon = STOP_QUIETLY;
  stop_signal = TARGET_SIGNAL_0;
  do
    {
      target_resume (minus_one_ptid, 0, stop_signal);
      wait_for_inferior (0);
    }
  while (stop_signal != TARGET_SIGNAL_TRAP);

  /*  solib_add will call reinit_frame_cache.
     But we are stopped in the runtime loader and we do not have symbols
     for the runtime loader. So heuristic_proc_start will be called
     and will put out an annoying warning.
     Delaying the resetting of stop_soon until after symbol loading
     suppresses the warning.  */
  solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
  stop_soon = NO_STOP_QUIETLY;
}
Esempio n. 3
0
/* run to exit point. return error if exit point was not reached. */
static int mips32_run_and_wait(struct target *target, uint32_t entry_point,
		int timeout_ms, uint32_t exit_point, struct mips32_common *mips32)
{
	uint32_t pc;
	int retval;
	/* This code relies on the target specific  resume() and  poll()->debug_entry()
	 * sequence to write register values to the processor and the read them back */
	if ((retval = target_resume(target, 0, entry_point, 0, 1)) != ERROR_OK)
	{
		return retval;
	}

	retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
	/* If the target fails to halt due to the breakpoint, force a halt */
	if (retval != ERROR_OK || target->state != TARGET_HALTED)
	{
		if ((retval = target_halt(target)) != ERROR_OK)
			return retval;
		if ((retval = target_wait_state(target, TARGET_HALTED, 500)) != ERROR_OK)
		{
			return retval;
		}
		return ERROR_TARGET_TIMEOUT;
	}

	pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
	if (exit_point && (pc != exit_point))
	{
		LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc);
		return ERROR_TARGET_TIMEOUT;
	}

	return ERROR_OK;
}
Esempio n. 4
0
/* run to exit point. return error if exit point was not reached. */
static int armv7m_run_and_wait(struct target *target, uint32_t entry_point, int timeout_ms, uint32_t exit_point, struct armv7m_common *armv7m)
{
	uint32_t pc;
	int retval;
	/* This code relies on the target specific  resume() and  poll()->debug_entry()
	 * sequence to write register values to the processor and the read them back */
	if ((retval = target_resume(target, 0, entry_point, 1, 1)) != ERROR_OK)
	{
		return retval;
	}

	retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
	/* If the target fails to halt due to the breakpoint, force a halt */
	if (retval != ERROR_OK || target->state != TARGET_HALTED)
	{
		if ((retval = target_halt(target)) != ERROR_OK)
			return retval;
		if ((retval = target_wait_state(target, TARGET_HALTED, 500)) != ERROR_OK)
		{
			return retval;
		}
		return ERROR_TARGET_TIMEOUT;
	}

	armv7m->load_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 15, &pc);
	if (exit_point && (pc != exit_point))
	{
		LOG_DEBUG("failed algoritm halted at 0x%" PRIx32 " ", pc);
		return ERROR_TARGET_TIMEOUT;
	}

	return ERROR_OK;
}
int arc_ocd_assert_reset(struct target *target)
{
	struct arc32_common *arc32 = target_to_arc32(target);

	LOG_DEBUG("target->state: %s", target_state_name(target));

	enum reset_types jtag_reset_config = jtag_get_reset_config();

	if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) {
		/* allow scripts to override the reset event */

		target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
		register_cache_invalidate(arc32->core_cache);
		/* An ARC target might be in halt state after reset, so
		 * if script requested processor to resume, then it must
		 * be manually started to ensure that this request
		 * is satisfied. */
		if (target->state == TARGET_HALTED && !target->reset_halt) {
			/* Resume the target and continue from the current
			 * PC register value. */
			LOG_DEBUG("Starting CPU execution after reset");
			CHECK_RETVAL(target_resume(target, 1, 0, 0, 0));
		}
		target->state = TARGET_RESET;

		return ERROR_OK;
	}

	/* some cores support connecting while srst is asserted
	 * use that mode is it has been configured */

	bool srst_asserted = false;

	if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) &&
			(jtag_reset_config & RESET_SRST_NO_GATING)) {
		jtag_add_reset(0, 1);
		srst_asserted = true;
	}

	if (jtag_reset_config & RESET_HAS_SRST) {
		/* should issue a srst only, but we may have to assert trst as well */
		if (jtag_reset_config & RESET_SRST_PULLS_TRST)
			jtag_add_reset(1, 1);
		else if (!srst_asserted)
			jtag_add_reset(0, 1);
	}

	target->state = TARGET_RESET;
	jtag_add_sleep(50000);

	register_cache_invalidate(arc32->core_cache);

	if (target->reset_halt)
		CHECK_RETVAL(target_halt(target));

	return ERROR_OK;
}
Esempio n. 6
0
static void
osf_solib_create_inferior_hook (int from_tty)
{
    struct inferior *inf;
    struct thread_info *tp;

    inf = current_inferior ();

    /* If we are attaching to the inferior, the shared libraries
       have already been mapped, so nothing more to do.  */
    if (inf->attach_flag)
        return;

    /* Nothing to do for statically bound executables.  */

    if (symfile_objfile == NULL
            || symfile_objfile->obfd == NULL
            || ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
        return;

    /* Now run the target.  It will eventually get a SIGTRAP, at
       which point all of the libraries will have been mapped in and we
       can go groveling around in the rld structures to find
       out what we need to know about them.

       If debugging from a core file, we cannot resume the execution
       of the inferior.  But this is actually not an issue, because
       shared libraries have already been mapped anyways, which means
       we have nothing more to do.  */
    if (!target_can_run (&current_target))
        return;

    tp = inferior_thread ();
    clear_proceed_status ();
    inf->stop_soon = STOP_QUIETLY;
    tp->stop_signal = TARGET_SIGNAL_0;
    do
    {
        target_resume (minus_one_ptid, 0, tp->stop_signal);
        wait_for_inferior (0);
    }
    while (tp->stop_signal != TARGET_SIGNAL_TRAP);

    /*  solib_add will call reinit_frame_cache.
       But we are stopped in the runtime loader and we do not have symbols
       for the runtime loader. So heuristic_proc_start will be called
       and will put out an annoying warning.
       Delaying the resetting of stop_soon until after symbol loading
       suppresses the warning.  */
    solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
    inf->stop_soon = NO_STOP_QUIETLY;
}
Esempio n. 7
0
static int or1k_profiling(struct target *target, uint32_t *samples,
		uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
{
	struct timeval timeout, now;
	struct or1k_common *or1k = target_to_or1k(target);
	struct or1k_du *du_core = or1k_to_du(or1k);
	int retval = ERROR_OK;

	gettimeofday(&timeout, NULL);
	timeval_add_time(&timeout, seconds, 0);

	LOG_INFO("Starting or1k profiling. Sampling npc as fast as we can...");

	/* Make sure the target is running */
	target_poll(target);
	if (target->state == TARGET_HALTED)
		retval = target_resume(target, 1, 0, 0, 0);

	if (retval != ERROR_OK) {
		LOG_ERROR("Error while resuming target");
		return retval;
	}

	uint32_t sample_count = 0;

	for (;;) {
		uint32_t reg_value;
		retval = du_core->or1k_jtag_read_cpu(&or1k->jtag, GROUP0 + 16 /* NPC */, 1, &reg_value);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error while reading NPC");
			return retval;
		}

		samples[sample_count++] = reg_value;

		gettimeofday(&now, NULL);
		if ((sample_count >= max_num_samples) ||
			((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
			LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
			break;
		}
	}

	*num_samples = sample_count;
	return retval;
}
static ptid_t
ia64_hpux_wait (struct target_ops *ops, ptid_t ptid,
		struct target_waitstatus *ourstatus, int options)
{
  ptid_t new_ptid;

  new_ptid = super_to_wait (ops, ptid, ourstatus, options);

  /* If this is a DLD event (hard-coded breakpoint instruction
     that was activated by the solib-ia64-hpux module), we need to
     process it, and then resume the execution as if the event did
     not happen.  */
  if (ourstatus->kind == TARGET_WAITKIND_STOPPED
      && ourstatus->value.sig == TARGET_SIGNAL_TRAP
      && ia64_hpux_at_dld_breakpoint_p (new_ptid))
    {
      ia64_hpux_handle_dld_breakpoint (new_ptid);

      target_resume (new_ptid, 0, TARGET_SIGNAL_0);
      ourstatus->kind = TARGET_WAITKIND_IGNORE;
    }

  return new_ptid;
}
Esempio n. 9
0
/** Starts a Thumb algorithm in the target. */
int armv7m_start_algorithm(struct target *target,
	int num_mem_params, struct mem_param *mem_params,
	int num_reg_params, struct reg_param *reg_params,
	uint32_t entry_point, uint32_t exit_point,
	void *arch_info)
{
	struct armv7m_common *armv7m = target_to_armv7m(target);
	struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
	enum armv7m_mode core_mode = armv7m->core_mode;
	int retval = ERROR_OK;

	/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
	 * at the exit point */

	if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC)
	{
		LOG_ERROR("current target isn't an ARMV7M target");
		return ERROR_TARGET_INVALID;
	}

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

	/* refresh core register cache */
	/* Not needed if core register cache is always consistent with target process state */
	for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++)
	{
		if (!armv7m->core_cache->reg_list[i].valid)
			armv7m->read_core_reg(target, i);
		armv7m_algorithm_info->context[i] = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32);
	}

	for (int i = 0; i < num_mem_params; i++)
	{
		// TODO: Write only out params
		if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK)
			return retval;
	}

	for (int i = 0; i < num_reg_params; i++)
	{
		struct reg *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0);
//		uint32_t regvalue;

		if (!reg)
		{
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
			return ERROR_INVALID_ARGUMENTS;
		}

		if (reg->size != reg_params[i].size)
		{
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
			return ERROR_INVALID_ARGUMENTS;
		}

//		regvalue = buf_get_u32(reg_params[i].value, 0, 32);
		armv7m_set_core_reg(reg, reg_params[i].value);
	}

	if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY)
	{
		LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
		buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value,
				0, 1, armv7m_algorithm_info->core_mode);
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
	}
	armv7m_algorithm_info->core_mode = core_mode;

	retval = target_resume(target, 0, entry_point, 1, 1);

	return retval;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
void
startup_inferior (int ntraps)
{
  int pending_execs = ntraps;
  int terminal_initted = 0;
  ptid_t resume_ptid;

  if (target_supports_multi_process ())
    resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
  else
    resume_ptid = minus_one_ptid;

  /* The process was started by the fork that created it, but it will
     have stopped one instruction after execing the shell.  Here we
     must get it up to actual execution of the real program.  */

  if (exec_wrapper)
    pending_execs++;

  while (1)
    {
      enum target_signal resume_signal = TARGET_SIGNAL_0;
      ptid_t event_ptid;

      struct target_waitstatus ws;
      memset (&ws, 0, sizeof (ws));
      event_ptid = target_wait (resume_ptid, &ws, 0);

      if (ws.kind == TARGET_WAITKIND_IGNORE)
	/* The inferior didn't really stop, keep waiting.  */
	continue;

      switch (ws.kind)
	{
	  case TARGET_WAITKIND_SPURIOUS:
	  case TARGET_WAITKIND_LOADED:
	  case TARGET_WAITKIND_FORKED:
	  case TARGET_WAITKIND_VFORKED:
	  case TARGET_WAITKIND_SYSCALL_ENTRY:
	  case TARGET_WAITKIND_SYSCALL_RETURN:
	    /* Ignore gracefully during startup of the inferior.  */
	    switch_to_thread (event_ptid);
	    break;

	  case TARGET_WAITKIND_SIGNALLED:
	    target_terminal_ours ();
	    target_mourn_inferior ();
	    error (_("During startup program terminated with signal %s, %s."),
		   target_signal_to_name (ws.value.sig),
		   target_signal_to_string (ws.value.sig));
	    return;

	  case TARGET_WAITKIND_EXITED:
	    target_terminal_ours ();
	    target_mourn_inferior ();
	    if (ws.value.integer)
	      error (_("During startup program exited with code %d."),
		     ws.value.integer);
	    else
	      error (_("During startup program exited normally."));
	    return;

	  case TARGET_WAITKIND_EXECD:
	    /* Handle EXEC signals as if they were SIGTRAP signals.  */
	    xfree (ws.value.execd_pathname);
	    resume_signal = TARGET_SIGNAL_TRAP;
	    switch_to_thread (event_ptid);
	    break;

	  case TARGET_WAITKIND_STOPPED:
	    resume_signal = ws.value.sig;
	    switch_to_thread (event_ptid);
	    break;
	}

      if (resume_signal != TARGET_SIGNAL_TRAP)
	{
	  /* Let shell child handle its own signals in its own way.  */
	  target_resume (resume_ptid, 0, resume_signal);
	}
      else
	{
	  /* We handle SIGTRAP, however; it means child did an exec.  */
	  if (!terminal_initted)
	    {
	      /* Now that the child has exec'd we know it has already
	         set its process group.  On POSIX systems, tcsetpgrp
	         will fail with EPERM if we try it before the child's
	         setpgid.  */

	      /* Set up the "saved terminal modes" of the inferior
	         based on what modes we are starting it with.  */
	      target_terminal_init ();

	      /* Install inferior's terminal modes.  */
	      target_terminal_inferior ();

	      terminal_initted = 1;
	    }

	  if (--pending_execs == 0)
	    break;

	  /* Just make it go on.  */
	  target_resume (resume_ptid, 0, TARGET_SIGNAL_0);
	}
    }

  /* Mark all threads non-executing.  */
  set_executing (resume_ptid, 0);
}
Esempio n. 12
0
/** Starts a Thumb algorithm in the target. */
int armv7m_start_algorithm(struct target *target,
	int num_mem_params, struct mem_param *mem_params,
	int num_reg_params, struct reg_param *reg_params,
	target_addr_t entry_point, target_addr_t exit_point,
	void *arch_info)
{
	struct armv7m_common *armv7m = target_to_armv7m(target);
	struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
	enum arm_mode core_mode = armv7m->arm.core_mode;
	int retval = ERROR_OK;

	/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
	 * at the exit point */

	if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) {
		LOG_ERROR("current target isn't an ARMV7M target");
		return ERROR_TARGET_INVALID;
	}

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

	/* refresh core register cache
	 * Not needed if core register cache is always consistent with target process state */
	for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {

		armv7m_algorithm_info->context[i] = buf_get_u32(
				armv7m->arm.core_cache->reg_list[i].value,
				0,
				32);
	}

	for (int i = 0; i < num_mem_params; i++) {
		/* TODO: Write only out params */
		retval = target_write_buffer(target, mem_params[i].address,
				mem_params[i].size,
				mem_params[i].value);
		if (retval != ERROR_OK)
			return retval;
	}

	for (int i = 0; i < num_reg_params; i++) {
		struct reg *reg =
			register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
/*		uint32_t regvalue; */

		if (!reg) {
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

		if (reg->size != reg_params[i].size) {
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
				reg_params[i].reg_name);
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

/*		regvalue = buf_get_u32(reg_params[i].value, 0, 32); */
		armv7m_set_core_reg(reg, reg_params[i].value);
	}

	if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
			armv7m_algorithm_info->core_mode != core_mode) {

		/* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */
		if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) {
			armv7m_algorithm_info->core_mode = ARM_MODE_THREAD;
			LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead");
		}

		LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
		buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
			0, 1, armv7m_algorithm_info->core_mode);
		armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
		armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
	}

	/* save previous core mode */
	armv7m_algorithm_info->core_mode = core_mode;

	retval = target_resume(target, 0, entry_point, 1, 1);

	return retval;
}
Esempio n. 13
0
/**
 * Check for and process a semihosting request using the ARM protocol). This
 * is meant to be called when the target is stopped due to a debug mode entry.
 * If the value 0 is returned then there was nothing to process. A non-zero
 * return value signifies that a request was processed and the target resumed,
 * or an error was encountered, in which case the caller must return
 * immediately.
 *
 * @param target Pointer to the target to process.
 * @param retval Pointer to a location where the return code will be stored
 * @return non-zero value if a request was processed or an error encountered
 */
int riscv_semihosting(struct target *target, int *retval)
{
	struct semihosting *semihosting = target->semihosting;
	if (!semihosting)
		return 0;

	if (!semihosting->is_active)
		return 0;

	riscv_reg_t dpc;
	int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC);
	if (result != ERROR_OK)
		return 0;

	uint8_t tmp[12];

	/* Read the current instruction, including the bracketing */
	*retval = target_read_memory(target, dpc - 4, 2, 6, tmp);
	if (*retval != ERROR_OK)
		return 0;

	/*
	 * The instructions that trigger a semihosting call,
	 * always uncompressed, should look like:
	 *
	 * 01f01013              slli    zero,zero,0x1f
	 * 00100073              ebreak
	 * 40705013              srai    zero,zero,0x7
	 */
	uint32_t pre = target_buffer_get_u32(target, tmp);
	uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
	uint32_t post = target_buffer_get_u32(target, tmp + 8);
	LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc);

	if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {

		/* Not the magic sequence defining semihosting. */
		return 0;
	}

	/*
	 * Perform semihosting call if we are not waiting on a fileio
	 * operation to complete.
	 */
	if (!semihosting->hit_fileio) {

		/* RISC-V uses A0 and A1 to pass function arguments */
		riscv_reg_t r0;
		riscv_reg_t r1;

		result = riscv_get_register(target, &r0, GDB_REGNO_A0);
		if (result != ERROR_OK)
			return 0;

		result = riscv_get_register(target, &r1, GDB_REGNO_A1);
		if (result != ERROR_OK)
			return 0;

		semihosting->op = r0;
		semihosting->param = r1;
		semihosting->word_size_bytes = riscv_xlen(target) / 8;

		/* Check for ARM operation numbers. */
		if (0 <= semihosting->op && semihosting->op <= 0x31) {
			*retval = semihosting_common(target);
			if (*retval != ERROR_OK) {
				LOG_ERROR("Failed semihosting operation");
				return 0;
			}
		} else {
			/* Unknown operation number, not a semihosting call. */
			return 0;
		}
	}

	/*
	 * Resume target if we are not waiting on a fileio
	 * operation to complete.
	 */
	if (semihosting->is_resumable && !semihosting->hit_fileio) {
		/* Resume right after the EBREAK 4 bytes instruction. */
		*retval = target_resume(target, 0, dpc+4, 0, 0);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed to resume target");
			return 0;
		}

		return 1;
	}

	return 0;
}
ptid_t
child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
  int save_errno;
  int status;
  char *execd_pathname = NULL;
  int exit_status;
  int related_pid;
  int syscall_id;
  enum target_waitkind kind;
  int pid;

  if (saved_vfork_state == STATE_FAKE_EXEC)
    {
      saved_vfork_state = STATE_NONE;
      ourstatus->kind = TARGET_WAITKIND_EXECD;
      ourstatus->value.execd_pathname = saved_child_execd_pathname;
      return inferior_ptid;
    }

  do
    {
      set_sigint_trap ();	/* Causes SIGINT to be passed on to the
				   attached process. */
      set_sigio_trap ();

      pid = ptrace_wait (inferior_ptid, &status);

      save_errno = errno;

      clear_sigio_trap ();

      clear_sigint_trap ();

      if (pid == -1)
	{
	  if (save_errno == EINTR)
	    continue;

	  fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
			      safe_strerror (save_errno));

	  /* Claim it exited with unknown signal.  */
	  ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
	  ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
	  return pid_to_ptid (-1);
	}

      /* Did it exit?
       */
      if (target_has_exited (pid, status, &exit_status))
	{
	  /* ??rehrauer: For now, ignore this. */
	  continue;
	}

      if (!target_thread_alive (pid_to_ptid (pid)))
	{
	  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
	  return pid_to_ptid (pid);
	}

      if (hpux_has_forked (pid, &related_pid))
	{
	  /* Ignore the parent's fork event.  */
	  if (pid == PIDGET (inferior_ptid))
	    {
	      ourstatus->kind = TARGET_WAITKIND_IGNORE;
	      return inferior_ptid;
	    }

	  /* If this is the child's fork event, report that the
	     process has forked.  */
	  if (related_pid == PIDGET (inferior_ptid))
	    {
	      ourstatus->kind = TARGET_WAITKIND_FORKED;
	      ourstatus->value.related_pid = pid;
	      return inferior_ptid;
	    }
	}

      if (hpux_has_vforked (pid, &related_pid))
	{
	  if (pid == PIDGET (inferior_ptid))
	    {
	      if (saved_vfork_state == STATE_GOT_CHILD)
		saved_vfork_state = STATE_GOT_PARENT;
	      else if (saved_vfork_state == STATE_GOT_EXEC)
		saved_vfork_state = STATE_FAKE_EXEC;
	      else
		fprintf_unfiltered (gdb_stdout,
				    "hppah: parent vfork: confused\n");
	    }
	  else if (related_pid == PIDGET (inferior_ptid))
	    {
	      if (saved_vfork_state == STATE_NONE)
		saved_vfork_state = STATE_GOT_CHILD;
	      else
		fprintf_unfiltered (gdb_stdout,
				    "hppah: child vfork: confused\n");
	    }
	  else
	    fprintf_unfiltered (gdb_stdout,
				"hppah: unknown vfork: confused\n");

	  if (saved_vfork_state == STATE_GOT_CHILD)
	    {
	      child_post_startup_inferior (pid_to_ptid (pid));
	      detach_breakpoints (pid);
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
	      SOLIB_REMOVE_INFERIOR_HOOK (pid);
#endif
	      child_resume (pid_to_ptid (pid), 0, TARGET_SIGNAL_0);
	      ourstatus->kind = TARGET_WAITKIND_IGNORE;
	      return pid_to_ptid (related_pid);
	    }
	  else if (saved_vfork_state == STATE_FAKE_EXEC)
	    {
	      ourstatus->kind = TARGET_WAITKIND_VFORKED;
	      ourstatus->value.related_pid = related_pid;
	      return pid_to_ptid (pid);
	    }
	  else
	    {
	      /* We saw the parent's vfork, but we haven't seen the exec yet.
		 Wait for it, for simplicity's sake.  It should be pending.  */
	      saved_vfork_pid = related_pid;
	      ourstatus->kind = TARGET_WAITKIND_IGNORE;
	      return pid_to_ptid (pid);
	    }
	}

      if (hpux_has_execd (pid, &execd_pathname))
	{
	  /* On HP-UX, events associated with a vforking inferior come in
	     threes: a vfork event for the child (always first), followed
	     a vfork event for the parent and an exec event for the child.
	     The latter two can come in either order.  Make sure we get
	     both.  */
	  if (saved_vfork_state != STATE_NONE)
	    {
	      if (saved_vfork_state == STATE_GOT_CHILD)
		{
		  saved_vfork_state = STATE_GOT_EXEC;
		  /* On HP/UX with ptrace, the child must be resumed before
		     the parent vfork event is delivered.  A single-step
		     suffices.  */
		  if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ())
		    target_resume (pid_to_ptid (pid), 1, TARGET_SIGNAL_0);
		  ourstatus->kind = TARGET_WAITKIND_IGNORE;
		}
	      else if (saved_vfork_state == STATE_GOT_PARENT)
		{
		  saved_vfork_state = STATE_FAKE_EXEC;
		  ourstatus->kind = TARGET_WAITKIND_VFORKED;
		  ourstatus->value.related_pid = saved_vfork_pid;
		}
	      else
		fprintf_unfiltered (gdb_stdout,
				    "hppa: exec: unexpected state\n");

	      saved_child_execd_pathname = execd_pathname;

	      return inferior_ptid;
	    }
	  
	  /* Are we ignoring initial exec events?  (This is likely because
	     we're in the process of starting up the inferior, and another
	     (older) mechanism handles those.)  If so, we'll report this
	     as a regular stop, not an exec.
	   */
	  if (inferior_ignoring_startup_exec_events)
	    {
	      inferior_ignoring_startup_exec_events--;
	    }
	  else
	    {
	      ourstatus->kind = TARGET_WAITKIND_EXECD;
	      ourstatus->value.execd_pathname = execd_pathname;
	      return pid_to_ptid (pid);
	    }
	}

      /* All we must do with these is communicate their occurrence
         to wait_for_inferior...
       */
      if (hpux_has_syscall_event (pid, &kind, &syscall_id))
	{
	  ourstatus->kind = kind;
	  ourstatus->value.syscall_id = syscall_id;
	  return pid_to_ptid (pid);
	}

      /*##  } while (pid != PIDGET (inferior_ptid)); ## *//* Some other child died or stopped */
/* hack for thread testing */
    }
  while ((pid != PIDGET (inferior_ptid)) && not_same_real_pid);
/*## */

  store_waitstatus (ourstatus, status);
  return pid_to_ptid (pid);
}
Esempio n. 15
0
int armv4_5_run_algorithm_inner(struct target *target,
	int num_mem_params, struct mem_param *mem_params,
	int num_reg_params, struct reg_param *reg_params,
	uint32_t entry_point, uint32_t exit_point,
	int timeout_ms, void *arch_info,
	int (*run_it)(struct target *target, uint32_t exit_point,
	int timeout_ms, void *arch_info))
{
	struct arm *arm = target_to_arm(target);
	struct arm_algorithm *arm_algorithm_info = arch_info;
	enum arm_state core_state = arm->core_state;
	uint32_t context[17];
	uint32_t cpsr;
	int exit_breakpoint_size = 0;
	int i;
	int retval = ERROR_OK;

	LOG_DEBUG("Running algorithm");

	if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) {
		LOG_ERROR("current target isn't an ARMV4/5 target");
		return ERROR_TARGET_INVALID;
	}

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

	if (!is_arm_mode(arm->core_mode)) {
		LOG_ERROR("not a valid arm core mode - communication failure?");
		return ERROR_FAIL;
	}

	/* armv5 and later can terminate with BKPT instruction; less overhead */
	if (!exit_point && arm->is_armv4) {
		LOG_ERROR("ARMv4 target needs HW breakpoint location");
		return ERROR_FAIL;
	}

	/* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure;
	 * they'll be restored later.
	 */
	for (i = 0; i <= 16; i++) {
		struct reg *r;

		r = &ARMV4_5_CORE_REG_MODE(arm->core_cache,
				arm_algorithm_info->core_mode, i);
		if (!r->valid)
			arm->read_core_reg(target, r, i,
				arm_algorithm_info->core_mode);
		context[i] = buf_get_u32(r->value, 0, 32);
	}
	cpsr = buf_get_u32(arm->cpsr->value, 0, 32);

	for (i = 0; i < num_mem_params; i++) {
		retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size,
				mem_params[i].value);
		if (retval != ERROR_OK)
			return retval;
	}

	for (i = 0; i < num_reg_params; i++) {
		struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0);
		if (!reg) {
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

		if (reg->size != reg_params[i].size) {
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size",
				reg_params[i].reg_name);
			return ERROR_COMMAND_SYNTAX_ERROR;
		}

		retval = armv4_5_set_core_reg(reg, reg_params[i].value);
		if (retval != ERROR_OK)
			return retval;
	}

	arm->core_state = arm_algorithm_info->core_state;
	if (arm->core_state == ARM_STATE_ARM)
		exit_breakpoint_size = 4;
	else if (arm->core_state == ARM_STATE_THUMB)
		exit_breakpoint_size = 2;
	else {
		LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state");
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	if (arm_algorithm_info->core_mode != ARM_MODE_ANY) {
		LOG_DEBUG("setting core_mode: 0x%2.2x",
			arm_algorithm_info->core_mode);
		buf_set_u32(arm->cpsr->value, 0, 5,
			arm_algorithm_info->core_mode);
		arm->cpsr->dirty = 1;
		arm->cpsr->valid = 1;
	}

	/* terminate using a hardware or (ARMv5+) software breakpoint */
	if (exit_point) {
		retval = breakpoint_add(target, exit_point,
				exit_breakpoint_size, BKPT_HARD);
		if (retval != ERROR_OK) {
			LOG_ERROR("can't add HW breakpoint to terminate algorithm");
			return ERROR_TARGET_FAILURE;
		}
	}

	retval = target_resume(target, 0, entry_point, 1, 1);
	if (retval != ERROR_OK)
		return retval;
	retval = run_it(target, exit_point, timeout_ms, arch_info);

	if (exit_point)
		breakpoint_remove(target, exit_point);

	if (retval != ERROR_OK)
		return retval;

	for (i = 0; i < num_mem_params; i++) {
		if (mem_params[i].direction != PARAM_OUT) {
			int retvaltemp = target_read_buffer(target, mem_params[i].address,
					mem_params[i].size,
					mem_params[i].value);
			if (retvaltemp != ERROR_OK)
				retval = retvaltemp;
		}
	}

	for (i = 0; i < num_reg_params; i++) {
		if (reg_params[i].direction != PARAM_OUT) {

			struct reg *reg = register_get_by_name(arm->core_cache,
					reg_params[i].reg_name,
					0);
			if (!reg) {
				LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
				retval = ERROR_COMMAND_SYNTAX_ERROR;
				continue;
			}

			if (reg->size != reg_params[i].size) {
				LOG_ERROR(
					"BUG: register '%s' size doesn't match reg_params[i].size",
					reg_params[i].reg_name);
				retval = ERROR_COMMAND_SYNTAX_ERROR;
				continue;
			}

			buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
		}
	}

	/* restore everything we saved before (17 or 18 registers) */
	for (i = 0; i <= 16; i++) {
		uint32_t regvalue;
		regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache,
				arm_algorithm_info->core_mode, i).value, 0, 32);
		if (regvalue != context[i]) {
			LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "",
				ARMV4_5_CORE_REG_MODE(arm->core_cache,
				arm_algorithm_info->core_mode, i).name, context[i]);
			buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache,
				arm_algorithm_info->core_mode, i).value, 0, 32, context[i]);
			ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode,
				i).valid = 1;
			ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode,
				i).dirty = 1;
		}
	}

	arm_set_cpsr(arm, cpsr);
	arm->cpsr->dirty = 1;

	arm->core_state = core_state;

	return retval;
}
/**
 * Checks for and processes an ARM semihosting request.  This is meant
 * to be called when the target is stopped due to a debug mode entry.
 * If the value 0 is returned then there was nothing to process. A non-zero
 * return value signifies that a request was processed and the target resumed,
 * or an error was encountered, in which case the caller must return
 * immediately.
 *
 * @param target Pointer to the ARM target to process.  This target must
 *	not represent an ARMv6-M or ARMv7-M processor.
 * @param retval Pointer to a location where the return code will be stored
 * @return non-zero value if a request was processed or an error encountered
 */
int arm_semihosting(struct target *target, int *retval)
{
	struct arm *arm = target_to_arm(target);
	struct armv7a_common *armv7a = target_to_armv7a(target);
	uint32_t pc, lr, spsr;
	struct reg *r;

	if (!arm->is_semihosting)
		return 0;

	if (is_arm7_9(target_to_arm7_9(target)) ||
	    is_armv7a(armv7a)) {
		uint32_t vbar = 0x00000000;

		if (arm->core_mode != ARM_MODE_SVC)
			return 0;

		if (is_armv7a(armv7a)) {
			struct arm_dpm *dpm = armv7a->arm.dpm;

			*retval = dpm->prepare(dpm);
			if (*retval == ERROR_OK) {
				*retval = dpm->instr_read_data_r0(dpm,
								 ARMV4_5_MRC(15, 0, 0, 12, 0, 0),
								 &vbar);

				dpm->finish(dpm);

				if (*retval != ERROR_OK)
					return 1;
			} else {
				return 1;
			}
		}

		/* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
		r = arm->pc;
		pc = buf_get_u32(r->value, 0, 32);
		if (pc != (vbar + 0x00000008) && pc != 0xffff0008)
			return 0;

		r = arm_reg_current(arm, 14);
		lr = buf_get_u32(r->value, 0, 32);

		/* Core-specific code should make sure SPSR is retrieved
		 * when the above checks pass...
		 */
		if (!arm->spsr->valid) {
			LOG_ERROR("SPSR not valid!");
			*retval = ERROR_FAIL;
			return 1;
		}

		spsr = buf_get_u32(arm->spsr->value, 0, 32);

		/* check instruction that triggered this trap */
		if (spsr & (1 << 5)) {
			/* was in Thumb (or ThumbEE) mode */
			uint8_t insn_buf[2];
			uint16_t insn;

			*retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
			if (*retval != ERROR_OK)
				return 1;
			insn = target_buffer_get_u16(target, insn_buf);

			/* SVC 0xab */
			if (insn != 0xDFAB)
				return 0;
		} else if (spsr & (1 << 24)) {
			/* was in Jazelle mode */
			return 0;
		} else {
			/* was in ARM mode */
			uint8_t insn_buf[4];
			uint32_t insn;

			*retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
			if (*retval != ERROR_OK)
				return 1;
			insn = target_buffer_get_u32(target, insn_buf);

			/* SVC 0x123456 */
			if (insn != 0xEF123456)
				return 0;
		}
	} else if (is_armv7m(target_to_armv7m(target))) {
		uint16_t insn;

		if (target->debug_reason != DBG_REASON_BREAKPOINT)
			return 0;

		r = arm->pc;
		pc = buf_get_u32(r->value, 0, 32);

		pc &= ~1;
		*retval = target_read_u16(target, pc, &insn);
		if (*retval != ERROR_OK)
			return 1;

		/* bkpt 0xAB */
		if (insn != 0xBEAB)
			return 0;
	} else {
		LOG_ERROR("Unsupported semi-hosting Target");
		return 0;
	}

	/* Perform semihosting if we are not waiting on a fileio
	 * operation to complete.
	 */
	if (!arm->semihosting_hit_fileio) {
		*retval = do_semihosting(target);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed semihosting operation");
			return 0;
		}
	}

	/* Post result to target if we are not waiting on a fileio
	 * operation to complete:
	 */
	if (!arm->semihosting_hit_fileio) {
		*retval = post_result(target);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed to post semihosting result");
			return 0;
		}

		*retval = target_resume(target, 1, 0, 0, 0);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed to resume target");
			return 0;
		}

		return 1;
	}

	return 0;
}
Esempio n. 17
0
int
agent_run_command (int pid, const char *cmd, int len)
{
  int fd;
  int tid = agent_get_helper_thread_id ();
  ptid_t ptid = ptid_build (pid, tid, 0);

#ifdef GDBSERVER
  int ret = write_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
				   (const unsigned char *) cmd, len);
#else
  int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, cmd, len);
#endif

  if (ret != 0)
    {
      warning (_("unable to write"));
      return -1;
    }

  DEBUG_AGENT ("agent: resumed helper thread\n");

  /* Resume helper thread.  */
#ifdef GDBSERVER
{
  struct thread_resume resume_info;

  resume_info.thread = ptid;
  resume_info.kind = resume_continue;
  resume_info.sig = GDB_SIGNAL_0;
  (*the_target->resume) (&resume_info, 1);
}
#else
 target_resume (ptid, 0, GDB_SIGNAL_0);
#endif

  fd = gdb_connect_sync_socket (pid);
  if (fd >= 0)
    {
      char buf[1] = "";
      int ret;

      DEBUG_AGENT ("agent: signalling helper thread\n");

      do
	{
	  ret = write (fd, buf, 1);
	} while (ret == -1 && errno == EINTR);

	DEBUG_AGENT ("agent: waiting for helper thread's response\n");

      do
	{
	  ret = read (fd, buf, 1);
	} while (ret == -1 && errno == EINTR);

      close (fd);

      DEBUG_AGENT ("agent: helper thread's response received\n");
    }
  else
    return -1;

  /* Need to read response with the inferior stopped.  */
  if (!ptid_equal (ptid, null_ptid))
    {
      struct target_waitstatus status;
      int was_non_stop = non_stop;
      /* Stop thread PTID.  */
      DEBUG_AGENT ("agent: stop helper thread\n");
#ifdef GDBSERVER
      {
	struct thread_resume resume_info;

	resume_info.thread = ptid;
	resume_info.kind = resume_stop;
	resume_info.sig = GDB_SIGNAL_0;
	(*the_target->resume) (&resume_info, 1);
      }

      non_stop = 1;
      mywait (ptid, &status, 0, 0);
#else
      non_stop = 1;
      target_stop (ptid);

      memset (&status, 0, sizeof (status));
      target_wait (ptid, &status, 0);
#endif
      non_stop = was_non_stop;
    }

  if (fd >= 0)
    {
#ifdef GDBSERVER
      if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
				(unsigned char *) cmd, IPA_CMD_BUF_SIZE))
#else
      if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd,
			      IPA_CMD_BUF_SIZE))
#endif
	{
	  warning (_("Error reading command response"));
	  return -1;
	}
    }

  return 0;
}