-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 = "foobar";
- 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 get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
-{
- struct arm *arm = target_to_arm(target);
-
- /* To avoid uneccessary duplication, semihosting prepares the
- * fileio_info structure out-of-band when the target halts. See
- * do_semihosting for more detail.
- */
- if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
- return ERROR_FAIL;
-
- return ERROR_OK;
-}
-
-static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
-{
- struct arm *arm = target_to_arm(target);
- struct gdb_fileio_info *fileio_info = target->fileio_info;
-
- /* clear pending status */
- arm->semihosting_hit_fileio = false;
-
- arm->semihosting_result = result;
- arm->semihosting_errno = fileio_errno;
-
- /* Some fileio results do not match up with what the semihosting
- * operation expects; for these operations, we munge the results
- * below:
- */
- switch (arm->semihosting_op) {
- case 0x05: /* SYS_WRITE */
- if (result < 0)
- arm->semihosting_result = fileio_info->param_3;
- else
- arm->semihosting_result = 0;
- break;
-
- case 0x06: /* SYS_READ */
- if (result == (int)fileio_info->param_3)
- arm->semihosting_result = 0;
- if (result <= 0)
- arm->semihosting_result = fileio_info->param_3;
- break;
-
- case 0x0a: /* SYS_SEEK */
- if (result > 0)
- arm->semihosting_result = 0;
- break;
- }
-
- return post_result(target);
-}
-