semihosting: improve semihosting opcode debug messages
[openocd.git] / src / target / semihosting_common.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2018 by Liviu Ionescu *
5 * <ilg@livius.net> *
6 * *
7 * Copyright (C) 2018 by Marvell Technology Group Ltd. *
8 * Written by Nicolas Pitre <nico@marvell.com> *
9 * *
10 * Copyright (C) 2010 by Spencer Oliver *
11 * spen@spen-soft.co.uk *
12 * *
13 * Copyright (C) 2016 by Square, Inc. *
14 * Steven Stallion <stallion@squareup.com> *
15 ***************************************************************************/
16
17 /**
18 * @file
19 * Common ARM semihosting support.
20 *
21 * Semihosting enables code running on a target to use some of the I/O
22 * facilities on the host computer. The target application must be linked
23 * against a library that forwards operation requests by using an
24 * instruction trapped by the debugger.
25 *
26 * Details can be found in
27 * "Semihosting for AArch32 and AArch64, Release 2.0"
28 * https://static.docs.arm.com/100863/0200/semihosting.pdf
29 * from ARM Ltd.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include "target.h"
37 #include "target_type.h"
38 #include "semihosting_common.h"
39
40 #include <helper/binarybuffer.h>
41 #include <helper/log.h>
42 #include <server/gdb_server.h>
43 #include <sys/stat.h>
44
45 /**
46 * It is not possible to use O_... flags defined in sys/stat.h because they
47 * are not guaranteed to match the values defined by the GDB Remote Protocol.
48 * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags
49 */
50 enum {
51 TARGET_O_RDONLY = 0x000,
52 TARGET_O_WRONLY = 0x001,
53 TARGET_O_RDWR = 0x002,
54 TARGET_O_APPEND = 0x008,
55 TARGET_O_CREAT = 0x200,
56 TARGET_O_TRUNC = 0x400,
57 /* O_EXCL=0x800 is not required in this implementation. */
58 };
59
60 /* GDB remote protocol does not differentiate between text and binary open modes. */
61 static const int open_gdb_modeflags[12] = {
62 TARGET_O_RDONLY,
63 TARGET_O_RDONLY,
64 TARGET_O_RDWR,
65 TARGET_O_RDWR,
66 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
67 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC,
68 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
69 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC,
70 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
71 TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND,
72 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND,
73 TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND
74 };
75
76 static const int open_host_modeflags[12] = {
77 O_RDONLY,
78 O_RDONLY | O_BINARY,
79 O_RDWR,
80 O_RDWR | O_BINARY,
81 O_WRONLY | O_CREAT | O_TRUNC,
82 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
83 O_RDWR | O_CREAT | O_TRUNC,
84 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
85 O_WRONLY | O_CREAT | O_APPEND,
86 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
87 O_RDWR | O_CREAT | O_APPEND,
88 O_RDWR | O_CREAT | O_APPEND | O_BINARY
89 };
90
91 static int semihosting_common_fileio_info(struct target *target,
92 struct gdb_fileio_info *fileio_info);
93 static int semihosting_common_fileio_end(struct target *target, int result,
94 int fileio_errno, bool ctrl_c);
95
96 /**
97 * Initialize common semihosting support.
98 *
99 * @param target Pointer to the target to initialize.
100 * @param setup
101 * @param post_result
102 * @return An error status if there is a problem during initialization.
103 */
104 int semihosting_common_init(struct target *target, void *setup,
105 void *post_result)
106 {
107 LOG_DEBUG(" ");
108
109 target->fileio_info = malloc(sizeof(*target->fileio_info));
110 if (!target->fileio_info) {
111 LOG_ERROR("out of memory");
112 return ERROR_FAIL;
113 }
114 memset(target->fileio_info, 0, sizeof(*target->fileio_info));
115
116 struct semihosting *semihosting;
117 semihosting = malloc(sizeof(*target->semihosting));
118 if (!semihosting) {
119 LOG_ERROR("out of memory");
120 return ERROR_FAIL;
121 }
122
123 semihosting->is_active = false;
124 semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
125 semihosting->tcp_connection = NULL;
126 semihosting->stdin_fd = -1;
127 semihosting->stdout_fd = -1;
128 semihosting->stderr_fd = -1;
129 semihosting->is_fileio = false;
130 semihosting->hit_fileio = false;
131 semihosting->is_resumable = false;
132 semihosting->has_resumable_exit = false;
133 semihosting->word_size_bytes = 0;
134 semihosting->op = -1;
135 semihosting->param = 0;
136 semihosting->result = -1;
137 semihosting->sys_errno = -1;
138 semihosting->cmdline = NULL;
139 semihosting->basedir = NULL;
140
141 /* If possible, update it in setup(). */
142 semihosting->setup_time = clock();
143
144 semihosting->setup = setup;
145 semihosting->post_result = post_result;
146 semihosting->user_command_extension = NULL;
147
148 target->semihosting = semihosting;
149
150 target->type->get_gdb_fileio_info = semihosting_common_fileio_info;
151 target->type->gdb_fileio_end = semihosting_common_fileio_end;
152
153 return ERROR_OK;
154 }
155
156 struct semihosting_tcp_service {
157 struct semihosting *semihosting;
158 char *name;
159 int error;
160 };
161
162 static bool semihosting_is_redirected(struct semihosting *semihosting, int fd)
163 {
164 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE)
165 return false;
166
167 bool is_read_op = false;
168
169 switch (semihosting->op) {
170 /* check debug semihosting operations: READC, WRITEC and WRITE0 */
171 case SEMIHOSTING_SYS_READC:
172 is_read_op = true;
173 /* fall through */
174 case SEMIHOSTING_SYS_WRITEC:
175 case SEMIHOSTING_SYS_WRITE0:
176 /* debug operations are redirected when CFG is either DEBUG or ALL */
177 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO)
178 return false;
179 break;
180
181 /* check stdio semihosting operations: READ and WRITE */
182 case SEMIHOSTING_SYS_READ:
183 is_read_op = true;
184 /* fall through */
185 case SEMIHOSTING_SYS_WRITE:
186 /* stdio operations are redirected when CFG is either STDIO or ALL */
187 if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG)
188 return false;
189 break;
190
191 default:
192 return false;
193 }
194
195 if (is_read_op)
196 return fd == semihosting->stdin_fd;
197
198 /* write operation */
199 return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd;
200 }
201
202 static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size)
203 {
204 if (!semihosting->tcp_connection) {
205 LOG_ERROR("No connected TCP client for semihosting");
206 semihosting->sys_errno = EBADF; /* Bad file number */
207 return -1;
208 }
209
210 struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv;
211
212 int retval = connection_write(semihosting->tcp_connection, buf, size);
213
214 if (retval < 0)
215 log_socket_error(service->name);
216
217 return retval;
218 }
219
220 static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size)
221 {
222 if (semihosting_is_redirected(semihosting, fd))
223 return semihosting_redirect_write(semihosting, buf, size);
224
225 /* default write */
226 return write(fd, buf, size);
227 }
228
229 static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size)
230 {
231 if (!semihosting->tcp_connection) {
232 LOG_ERROR("No connected TCP client for semihosting");
233 semihosting->sys_errno = EBADF; /* Bad file number */
234 return -1;
235 }
236
237 struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv;
238
239 service->error = ERROR_OK;
240 semihosting->tcp_connection->input_pending = true;
241
242 int retval = connection_read(semihosting->tcp_connection, buf, size);
243
244 if (retval <= 0)
245 service->error = ERROR_SERVER_REMOTE_CLOSED;
246
247 if (retval < 0)
248 log_socket_error(service->name);
249
250 semihosting->tcp_connection->input_pending = false;
251
252 return retval;
253 }
254
255 static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c)
256 {
257 if (semihosting_is_redirected(semihosting, fd))
258 return semihosting_redirect_write(semihosting, &c, 1);
259
260 /* default putchar */
261 return putchar(c);
262 }
263
264 static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size)
265 {
266 if (semihosting_is_redirected(semihosting, fd))
267 return semihosting_redirect_read(semihosting, buf, size);
268
269 /* default read */
270 ssize_t result = read(fd, buf, size);
271 semihosting->sys_errno = errno;
272
273 return result;
274 }
275
276 static inline int semihosting_getchar(struct semihosting *semihosting, int fd)
277 {
278 if (semihosting_is_redirected(semihosting, fd)) {
279 unsigned char c;
280
281 if (semihosting_redirect_read(semihosting, &c, 1) > 0)
282 return c;
283
284 return EOF;
285 }
286
287 /* default getchar */
288 return getchar();
289 }
290
291 /**
292 * User operation parameter string storage buffer. Contains valid data when the
293 * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running.
294 */
295 static char *semihosting_user_op_params;
296
297 const char *semihosting_opcode_to_str(const uint64_t opcode)
298 {
299 switch (opcode) {
300 case SEMIHOSTING_SYS_CLOSE:
301 return "CLOSE";
302 case SEMIHOSTING_SYS_CLOCK:
303 return "CLOCK";
304 case SEMIHOSTING_SYS_ELAPSED:
305 return "ELAPSED";
306 case SEMIHOSTING_SYS_ERRNO:
307 return "ERRNO";
308 case SEMIHOSTING_SYS_EXIT:
309 return "EXIT";
310 case SEMIHOSTING_SYS_EXIT_EXTENDED:
311 return "EXIT_EXTENDED";
312 case SEMIHOSTING_SYS_FLEN:
313 return "FLEN";
314 case SEMIHOSTING_SYS_GET_CMDLINE:
315 return "GET_CMDLINE";
316 case SEMIHOSTING_SYS_HEAPINFO:
317 return "HEAPINFO";
318 case SEMIHOSTING_SYS_ISERROR:
319 return "ISERROR";
320 case SEMIHOSTING_SYS_ISTTY:
321 return "ISTTY";
322 case SEMIHOSTING_SYS_OPEN:
323 return "OPEN";
324 case SEMIHOSTING_SYS_READ:
325 return "READ";
326 case SEMIHOSTING_SYS_READC:
327 return "READC";
328 case SEMIHOSTING_SYS_REMOVE:
329 return "REMOVE";
330 case SEMIHOSTING_SYS_RENAME:
331 return "RENAME";
332 case SEMIHOSTING_SYS_SEEK:
333 return "SEEK";
334 case SEMIHOSTING_SYS_SYSTEM:
335 return "SYSTEM";
336 case SEMIHOSTING_SYS_TICKFREQ:
337 return "TICKFREQ";
338 case SEMIHOSTING_SYS_TIME:
339 return "TIME";
340 case SEMIHOSTING_SYS_TMPNAM:
341 return "TMPNAM";
342 case SEMIHOSTING_SYS_WRITE:
343 return "WRITE";
344 case SEMIHOSTING_SYS_WRITEC:
345 return "WRITEC";
346 case SEMIHOSTING_SYS_WRITE0:
347 return "WRITE0";
348 case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF:
349 return "USER_CMD";
350 case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END:
351 return "ARM_RESERVED_CMD";
352 default:
353 return "<unknown>";
354 }
355 }
356
357 /**
358 * Portable implementation of ARM semihosting calls.
359 * Performs the currently pending semihosting operation
360 * encoded in target->semihosting.
361 */
362 int semihosting_common(struct target *target)
363 {
364 struct semihosting *semihosting = target->semihosting;
365 if (!semihosting) {
366 /* Silently ignore if the semihosting field was not set. */
367 return ERROR_OK;
368 }
369
370 struct gdb_fileio_info *fileio_info = target->fileio_info;
371
372 /*
373 * By default return an error.
374 * The actual result must be set by each function
375 */
376 semihosting->result = -1;
377
378 /* Most operations are resumable, except the two exit calls. */
379 semihosting->is_resumable = true;
380
381 int retval;
382
383 /* Enough space to hold 4 long words. */
384 uint8_t fields[4*8];
385
386 LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op,
387 semihosting_opcode_to_str(semihosting->op),
388 semihosting->param);
389
390 switch (semihosting->op) {
391
392 case SEMIHOSTING_SYS_CLOCK: /* 0x10 */
393 /*
394 * Returns the number of centiseconds (hundredths of a second)
395 * since the execution started.
396 *
397 * Values returned can be of limited use for some benchmarking
398 * purposes because of communication overhead or other
399 * agent-specific factors. For example, with a debug hardware
400 * unit the request is passed back to the host for execution.
401 * This can lead to unpredictable delays in transmission and
402 * process scheduling.
403 *
404 * Use this function to calculate time intervals, by calculating
405 * differences between intervals with and without the code
406 * sequence to be timed.
407 *
408 * Entry
409 * The PARAMETER REGISTER must contain 0. There are no other
410 * parameters.
411 *
412 * Return
413 * On exit, the RETURN REGISTER contains:
414 * - The number of centiseconds since some arbitrary start
415 * point, if the call is successful.
416 * - –1 if the call is not successful. For example, because
417 * of a communications error.
418 */
419 {
420 clock_t delta = clock() - semihosting->setup_time;
421
422 semihosting->result = delta / (CLOCKS_PER_SEC / 100);
423 }
424 break;
425
426 case SEMIHOSTING_SYS_CLOSE: /* 0x02 */
427 /*
428 * Closes a file on the host system. The handle must reference
429 * a file that was opened with SYS_OPEN.
430 *
431 * Entry
432 * On entry, the PARAMETER REGISTER contains a pointer to a
433 * one-field argument block:
434 * - field 1 Contains a handle for an open file.
435 *
436 * Return
437 * On exit, the RETURN REGISTER contains:
438 * - 0 if the call is successful
439 * - –1 if the call is not successful.
440 */
441 retval = semihosting_read_fields(target, 1, fields);
442 if (retval != ERROR_OK)
443 return retval;
444 else {
445 int fd = semihosting_get_field(target, 0, fields);
446 /* Do not allow to close OpenOCD's own standard streams */
447 if (fd == 0 || fd == 1 || fd == 2) {
448 LOG_DEBUG("ignoring semihosting attempt to close %s",
449 (fd == 0) ? "stdin" :
450 (fd == 1) ? "stdout" : "stderr");
451 /* Just pretend success */
452 if (semihosting->is_fileio) {
453 semihosting->result = 0;
454 } else {
455 semihosting->result = 0;
456 semihosting->sys_errno = 0;
457 }
458 break;
459 }
460 /* Close the descriptor */
461 if (semihosting->is_fileio) {
462 semihosting->hit_fileio = true;
463 fileio_info->identifier = "close";
464 fileio_info->param_1 = fd;
465 } else {
466 semihosting->result = close(fd);
467 semihosting->sys_errno = errno;
468 LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result);
469 }
470 }
471 break;
472
473 case SEMIHOSTING_SYS_ERRNO: /* 0x13 */
474 /*
475 * Returns the value of the C library errno variable that is
476 * associated with the semihosting implementation. The errno
477 * variable can be set by a number of C library semihosted
478 * functions, including:
479 * - SYS_REMOVE
480 * - SYS_OPEN
481 * - SYS_CLOSE
482 * - SYS_READ
483 * - SYS_WRITE
484 * - SYS_SEEK.
485 *
486 * Whether errno is set or not, and to what value, is entirely
487 * host-specific, except where the ISO C standard defines the
488 * behavior.
489 *
490 * Entry
491 * There are no parameters. The PARAMETER REGISTER must be 0.
492 *
493 * Return
494 * On exit, the RETURN REGISTER contains the value of the C
495 * library errno variable.
496 */
497 semihosting->result = semihosting->sys_errno;
498 break;
499
500 case SEMIHOSTING_SYS_EXIT: /* 0x18 */
501 /*
502 * Note: SYS_EXIT was called angel_SWIreason_ReportException in
503 * previous versions of the documentation.
504 *
505 * An application calls this operation to report an exception
506 * to the debugger directly. The most common use is to report
507 * that execution has completed, using ADP_Stopped_ApplicationExit.
508 *
509 * Note: This semihosting operation provides no means for 32-bit
510 * callers to indicate an application exit with a specified exit
511 * code. Semihosting callers may prefer to check for the presence
512 * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use
513 * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it
514 * is available.
515 *
516 * Entry (32-bit)
517 * On entry, the PARAMETER register is set to a reason code
518 * describing the cause of the trap. Not all semihosting client
519 * implementations will necessarily trap every corresponding
520 * event. Important reason codes are:
521 *
522 * - ADP_Stopped_ApplicationExit 0x20026
523 * - ADP_Stopped_RunTimeErrorUnknown 0x20023
524 *
525 * Entry (64-bit)
526 * On entry, the PARAMETER REGISTER contains a pointer to a
527 * two-field argument block:
528 * - field 1 The exception type, which is one of the set of
529 * reason codes in the above tables.
530 * - field 2 A subcode, whose meaning depends on the reason
531 * code in field 1.
532 * In particular, if field 1 is ADP_Stopped_ApplicationExit
533 * then field 2 is an exit status code, as passed to the C
534 * standard library exit() function. A simulator receiving
535 * this request must notify a connected debugger, if present,
536 * and then exit with the specified status.
537 *
538 * Return
539 * No return is expected from these calls. However, it is
540 * possible for the debugger to request that the application
541 * continues by performing an RDI_Execute request or equivalent.
542 * In this case, execution continues with the registers as they
543 * were on entry to the operation, or as subsequently modified
544 * by the debugger.
545 */
546 if (semihosting->word_size_bytes == 8) {
547 retval = semihosting_read_fields(target, 2, fields);
548 if (retval != ERROR_OK)
549 return retval;
550 else {
551 int type = semihosting_get_field(target, 0, fields);
552 int code = semihosting_get_field(target, 1, fields);
553
554 if (type == ADP_STOPPED_APPLICATION_EXIT) {
555 if (!gdb_get_actual_connections())
556 exit(code);
557 else {
558 fprintf(stderr,
559 "semihosting: *** application exited with %d ***\n",
560 code);
561 }
562 } else {
563 fprintf(stderr,
564 "semihosting: application exception %#x\n",
565 type);
566 }
567 }
568 } else {
569 if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
570 if (!gdb_get_actual_connections())
571 exit(0);
572 else {
573 fprintf(stderr,
574 "semihosting: *** application exited normally ***\n");
575 }
576 } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
577 /* Chosen more or less arbitrarily to have a nicer message,
578 * otherwise all other return the same exit code 1. */
579 if (!gdb_get_actual_connections())
580 exit(1);
581 else {
582 fprintf(stderr,
583 "semihosting: *** application exited with error ***\n");
584 }
585 } else {
586 if (!gdb_get_actual_connections())
587 exit(1);
588 else {
589 fprintf(stderr,
590 "semihosting: application exception %#x\n",
591 (unsigned) semihosting->param);
592 }
593 }
594 }
595 if (!semihosting->has_resumable_exit) {
596 semihosting->is_resumable = false;
597 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
598 }
599 break;
600
601 case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */
602 /*
603 * This operation is only supported if the semihosting extension
604 * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is
605 * reported using feature byte 0, bit 0. If this extension is
606 * supported, then the implementation provides a means to
607 * report a normal exit with a nonzero exit status in both 32-bit
608 * and 64-bit semihosting APIs.
609 *
610 * The implementation must provide the semihosting call
611 * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs.
612 *
613 * SYS_EXIT_EXTENDED is used by an application to report an
614 * exception or exit to the debugger directly. The most common
615 * use is to report that execution has completed, using
616 * ADP_Stopped_ApplicationExit.
617 *
618 * Entry
619 * On entry, the PARAMETER REGISTER contains a pointer to a
620 * two-field argument block:
621 * - field 1 The exception type, which should be one of the set
622 * of reason codes that are documented for the SYS_EXIT
623 * (0x18) call. For example, ADP_Stopped_ApplicationExit.
624 * - field 2 A subcode, whose meaning depends on the reason
625 * code in field 1. In particular, if field 1 is
626 * ADP_Stopped_ApplicationExit then field 2 is an exit status
627 * code, as passed to the C standard library exit() function.
628 * A simulator receiving this request must notify a connected
629 * debugger, if present, and then exit with the specified status.
630 *
631 * Return
632 * No return is expected from these calls.
633 *
634 * For the A64 API, this call is identical to the behavior of
635 * the mandatory SYS_EXIT (0x18) call. If this extension is
636 * supported, then both calls must be implemented.
637 */
638 retval = semihosting_read_fields(target, 2, fields);
639 if (retval != ERROR_OK)
640 return retval;
641 else {
642 int type = semihosting_get_field(target, 0, fields);
643 int code = semihosting_get_field(target, 1, fields);
644
645 if (type == ADP_STOPPED_APPLICATION_EXIT) {
646 if (!gdb_get_actual_connections())
647 exit(code);
648 else {
649 fprintf(stderr,
650 "semihosting: *** application exited with %d ***\n",
651 code);
652 }
653 } else {
654 fprintf(stderr, "semihosting: exception %#x\n",
655 type);
656 }
657 }
658 if (!semihosting->has_resumable_exit) {
659 semihosting->is_resumable = false;
660 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
661 }
662 break;
663
664 case SEMIHOSTING_SYS_FLEN: /* 0x0C */
665 /*
666 * Returns the length of a specified file.
667 *
668 * Entry
669 * On entry, the PARAMETER REGISTER contains a pointer to a
670 * one-field argument block:
671 * - field 1 A handle for a previously opened, seekable file
672 * object.
673 *
674 * Return
675 * On exit, the RETURN REGISTER contains:
676 * - The current length of the file object, if the call is
677 * successful.
678 * - –1 if an error occurs.
679 */
680 if (semihosting->is_fileio) {
681 semihosting->result = -1;
682 semihosting->sys_errno = EINVAL;
683 }
684 retval = semihosting_read_fields(target, 1, fields);
685 if (retval != ERROR_OK)
686 return retval;
687 else {
688 int fd = semihosting_get_field(target, 0, fields);
689 struct stat buf;
690 semihosting->result = fstat(fd, &buf);
691 if (semihosting->result == -1) {
692 semihosting->sys_errno = errno;
693 LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result);
694 break;
695 }
696 LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result);
697 semihosting->result = buf.st_size;
698 }
699 break;
700
701 case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */
702 /*
703 * Returns the command line that is used for the call to the
704 * executable, that is, argc and argv.
705 *
706 * Entry
707 * On entry, the PARAMETER REGISTER points to a two-field data
708 * block to be used for returning the command string and its length:
709 * - field 1 A pointer to a buffer of at least the size that is
710 * specified in field 2.
711 * - field 2 The length of the buffer in bytes.
712 *
713 * Return
714 * On exit:
715 * If the call is successful, then the RETURN REGISTER contains 0,
716 * the PARAMETER REGISTER is unchanged, and the data block is
717 * updated as follows:
718 * - field 1 A pointer to a null-terminated string of the command
719 * line.
720 * - field 2 The length of the string in bytes.
721 * If the call is not successful, then the RETURN REGISTER
722 * contains -1.
723 *
724 * Note: The semihosting implementation might impose limits on
725 * the maximum length of the string that can be transferred.
726 * However, the implementation must be able to support a
727 * command-line length of at least 80 bytes.
728 */
729 retval = semihosting_read_fields(target, 2, fields);
730 if (retval != ERROR_OK)
731 return retval;
732 else {
733 uint64_t addr = semihosting_get_field(target, 0, fields);
734 size_t size = semihosting_get_field(target, 1, fields);
735
736 char *arg = semihosting->cmdline ?
737 semihosting->cmdline : "";
738 uint32_t len = strlen(arg) + 1;
739 if (len > size)
740 semihosting->result = -1;
741 else {
742 semihosting_set_field(target, len, 1, fields);
743 retval = target_write_buffer(target, addr, len,
744 (uint8_t *)arg);
745 if (retval != ERROR_OK)
746 return retval;
747 semihosting->result = 0;
748
749 retval = semihosting_write_fields(target, 2, fields);
750 if (retval != ERROR_OK)
751 return retval;
752 }
753 LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result);
754 }
755 break;
756
757 case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */
758 /*
759 * Returns the system stack and heap parameters.
760 *
761 * Entry
762 * On entry, the PARAMETER REGISTER contains the address of a
763 * pointer to a four-field data block. The contents of the data
764 * block are filled by the function. The following C-like
765 * pseudocode describes the layout of the block:
766 * struct block {
767 * void* heap_base;
768 * void* heap_limit;
769 * void* stack_base;
770 * void* stack_limit;
771 * };
772 *
773 * Return
774 * On exit, the PARAMETER REGISTER is unchanged and the data
775 * block has been updated.
776 */
777 retval = semihosting_read_fields(target, 1, fields);
778 if (retval != ERROR_OK)
779 return retval;
780 else {
781 uint64_t addr = semihosting_get_field(target, 0, fields);
782 /* tell the remote we have no idea */
783 memset(fields, 0, 4 * semihosting->word_size_bytes);
784 retval = target_write_memory(target, addr, 4,
785 semihosting->word_size_bytes,
786 fields);
787 if (retval != ERROR_OK)
788 return retval;
789 semihosting->result = 0;
790 }
791 break;
792
793 case SEMIHOSTING_SYS_ISERROR: /* 0x08 */
794 /*
795 * Determines whether the return code from another semihosting
796 * call is an error status or not.
797 *
798 * This call is passed a parameter block containing the error
799 * code to examine.
800 *
801 * Entry
802 * On entry, the PARAMETER REGISTER contains a pointer to a
803 * one-field data block:
804 * - field 1 The required status word to check.
805 *
806 * Return
807 * On exit, the RETURN REGISTER contains:
808 * - 0 if the status field is not an error indication
809 * - A nonzero value if the status field is an error indication.
810 */
811 retval = semihosting_read_fields(target, 1, fields);
812 if (retval != ERROR_OK)
813 return retval;
814
815 uint64_t code = semihosting_get_field(target, 0, fields);
816 semihosting->result = (code != 0);
817 break;
818
819 case SEMIHOSTING_SYS_ISTTY: /* 0x09 */
820 /*
821 * Checks whether a file is connected to an interactive device.
822 *
823 * Entry
824 * On entry, the PARAMETER REGISTER contains a pointer to a
825 * one-field argument block:
826 * field 1 A handle for a previously opened file object.
827 *
828 * Return
829 * On exit, the RETURN REGISTER contains:
830 * - 1 if the handle identifies an interactive device.
831 * - 0 if the handle identifies a file.
832 * - A value other than 1 or 0 if an error occurs.
833 */
834 if (semihosting->is_fileio) {
835 semihosting->hit_fileio = true;
836 fileio_info->identifier = "isatty";
837 fileio_info->param_1 = semihosting->param;
838 } else {
839 retval = semihosting_read_fields(target, 1, fields);
840 if (retval != ERROR_OK)
841 return retval;
842 int fd = semihosting_get_field(target, 0, fields);
843 // isatty() on Windows may return any non-zero value if fd is a terminal
844 semihosting->result = isatty(fd) ? 1 : 0;
845 semihosting->sys_errno = errno;
846 LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
847 }
848 break;
849
850 case SEMIHOSTING_SYS_OPEN: /* 0x01 */
851 /*
852 * Opens a file on the host system.
853 *
854 * The file path is specified either as relative to the current
855 * directory of the host process, or absolute, using the path
856 * conventions of the host operating system.
857 *
858 * Semihosting implementations must support opening the special
859 * path name :semihosting-features as part of the semihosting
860 * extensions reporting mechanism.
861 *
862 * ARM targets interpret the special path name :tt as meaning
863 * the console input stream, for an open-read or the console
864 * output stream, for an open-write. Opening these streams is
865 * performed as part of the standard startup code for those
866 * applications that reference the C stdio streams. The
867 * semihosting extension SH_EXT_STDOUT_STDERR allows the
868 * semihosting caller to open separate output streams
869 * corresponding to stdout and stderr. This extension is
870 * reported using feature byte 0, bit 1. Use SYS_OPEN with
871 * the special path name :semihosting-features to access the
872 * feature bits.
873 *
874 * If this extension is supported, the implementation must
875 * support the following additional semantics to SYS_OPEN:
876 * - If the special path name :tt is opened with an fopen
877 * mode requesting write access (w, wb, w+, or w+b), then
878 * this is a request to open stdout.
879 * - If the special path name :tt is opened with a mode
880 * requesting append access (a, ab, a+, or a+b), then this is
881 * a request to open stderr.
882 *
883 * Entry
884 * On entry, the PARAMETER REGISTER contains a pointer to a
885 * three-field argument block:
886 * - field 1 A pointer to a null-terminated string containing
887 * a file or device name.
888 * - field 2 An integer that specifies the file opening mode.
889 * - field 3 An integer that gives the length of the string
890 * pointed to by field 1.
891 *
892 * The length does not include the terminating null character
893 * that must be present.
894 *
895 * Return
896 * On exit, the RETURN REGISTER contains:
897 * - A nonzero handle if the call is successful.
898 * - –1 if the call is not successful.
899 */
900 retval = semihosting_read_fields(target, 3, fields);
901 if (retval != ERROR_OK)
902 return retval;
903 else {
904 uint64_t addr = semihosting_get_field(target, 0, fields);
905 uint32_t mode = semihosting_get_field(target, 1, fields);
906 size_t len = semihosting_get_field(target, 2, fields);
907
908 if (mode > 11) {
909 semihosting->result = -1;
910 semihosting->sys_errno = EINVAL;
911 break;
912 }
913 size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0;
914 uint8_t *fn = malloc(basedir_len + len + 2);
915 if (!fn) {
916 semihosting->result = -1;
917 semihosting->sys_errno = ENOMEM;
918 } else {
919 if (basedir_len > 0) {
920 strcpy((char *)fn, semihosting->basedir);
921 if (fn[basedir_len - 1] != '/')
922 fn[basedir_len++] = '/';
923 }
924 retval = target_read_memory(target, addr, 1, len, fn + basedir_len);
925 if (retval != ERROR_OK) {
926 free(fn);
927 return retval;
928 }
929 fn[basedir_len + len] = 0;
930 /* TODO: implement the :semihosting-features special file.
931 * */
932 if (semihosting->is_fileio) {
933 if (strcmp((char *)fn, ":semihosting-features") == 0) {
934 semihosting->result = -1;
935 semihosting->sys_errno = EINVAL;
936 } else if (strcmp((char *)fn, ":tt") == 0) {
937 if (mode == 0)
938 semihosting->result = 0;
939 else if (mode == 4)
940 semihosting->result = 1;
941 else if (mode == 8)
942 semihosting->result = 2;
943 else
944 semihosting->result = -1;
945 } else {
946 semihosting->hit_fileio = true;
947 fileio_info->identifier = "open";
948 fileio_info->param_1 = addr;
949 fileio_info->param_2 = len;
950 fileio_info->param_3 = open_gdb_modeflags[mode];
951 fileio_info->param_4 = 0644;
952 }
953 } else {
954 if (strcmp((char *)fn, ":tt") == 0) {
955 /* Mode is:
956 * - 0-3 ("r") for stdin,
957 * - 4-7 ("w") for stdout,
958 * - 8-11 ("a") for stderr */
959 if (mode < 4) {
960 int fd = dup(STDIN_FILENO);
961 semihosting->result = fd;
962 semihosting->stdin_fd = fd;
963 semihosting->sys_errno = errno;
964 LOG_DEBUG("dup(STDIN)=%" PRId64, semihosting->result);
965 } else if (mode < 8) {
966 int fd = dup(STDOUT_FILENO);
967 semihosting->result = fd;
968 semihosting->stdout_fd = fd;
969 semihosting->sys_errno = errno;
970 LOG_DEBUG("dup(STDOUT)=%" PRId64, semihosting->result);
971 } else {
972 int fd = dup(STDERR_FILENO);
973 semihosting->result = fd;
974 semihosting->stderr_fd = fd;
975 semihosting->sys_errno = errno;
976 LOG_DEBUG("dup(STDERR)=%" PRId64, semihosting->result);
977 }
978 } else {
979 /* cygwin requires the permission setting
980 * otherwise it will fail to reopen a previously
981 * written file */
982 semihosting->result = open((char *)fn,
983 open_host_modeflags[mode],
984 0644);
985 semihosting->sys_errno = errno;
986 LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result);
987 }
988 }
989 free(fn);
990 }
991 }
992 break;
993
994 case SEMIHOSTING_SYS_READ: /* 0x06 */
995 /*
996 * Reads the contents of a file into a buffer. The file position
997 * is specified either:
998 * - Explicitly by a SYS_SEEK.
999 * - Implicitly one byte beyond the previous SYS_READ or
1000 * SYS_WRITE request.
1001 *
1002 * The file position is at the start of the file when it is
1003 * opened, and is lost when the file is closed. Perform the
1004 * file operation as a single action whenever possible. For
1005 * example, do not split a read of 16KB into four 4KB chunks
1006 * unless there is no alternative.
1007 *
1008 * Entry
1009 * On entry, the PARAMETER REGISTER contains a pointer to a
1010 * three-field data block:
1011 * - field 1 Contains a handle for a file previously opened
1012 * with SYS_OPEN.
1013 * - field 2 Points to a buffer.
1014 * - field 3 Contains the number of bytes to read to the buffer
1015 * from the file.
1016 *
1017 * Return
1018 * On exit, the RETURN REGISTER contains the number of bytes not
1019 * filled in the buffer (buffer_length - bytes_read) as follows:
1020 * - If the RETURN REGISTER is 0, the entire buffer was
1021 * successfully filled.
1022 * - If the RETURN REGISTER is the same as field 3, no bytes
1023 * were read (EOF can be assumed).
1024 * - If the RETURN REGISTER contains a value smaller than
1025 * field 3, the read succeeded but the buffer was only partly
1026 * filled. For interactive devices, this is the most common
1027 * return value.
1028 */
1029 retval = semihosting_read_fields(target, 3, fields);
1030 if (retval != ERROR_OK)
1031 return retval;
1032 else {
1033 int fd = semihosting_get_field(target, 0, fields);
1034 uint64_t addr = semihosting_get_field(target, 1, fields);
1035 size_t len = semihosting_get_field(target, 2, fields);
1036 if (semihosting->is_fileio) {
1037 semihosting->hit_fileio = true;
1038 fileio_info->identifier = "read";
1039 fileio_info->param_1 = fd;
1040 fileio_info->param_2 = addr;
1041 fileio_info->param_3 = len;
1042 } else {
1043 uint8_t *buf = malloc(len);
1044 if (!buf) {
1045 semihosting->result = -1;
1046 semihosting->sys_errno = ENOMEM;
1047 } else {
1048 semihosting->result = semihosting_read(semihosting, fd, buf, len);
1049 LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
1050 fd,
1051 addr,
1052 len,
1053 semihosting->result);
1054 if (semihosting->result >= 0) {
1055 retval = target_write_buffer(target, addr,
1056 semihosting->result,
1057 buf);
1058 if (retval != ERROR_OK) {
1059 free(buf);
1060 return retval;
1061 }
1062 /* the number of bytes NOT filled in */
1063 semihosting->result = len -
1064 semihosting->result;
1065 }
1066 free(buf);
1067 }
1068 }
1069 }
1070 break;
1071
1072 case SEMIHOSTING_SYS_READC: /* 0x07 */
1073 /*
1074 * Reads a byte from the console.
1075 *
1076 * Entry
1077 * The PARAMETER REGISTER must contain 0. There are no other
1078 * parameters or values possible.
1079 *
1080 * Return
1081 * On exit, the RETURN REGISTER contains the byte read from
1082 * the console.
1083 */
1084 if (semihosting->is_fileio) {
1085 LOG_ERROR("SYS_READC not supported by semihosting fileio");
1086 return ERROR_FAIL;
1087 }
1088 semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd);
1089 LOG_DEBUG("getchar()=%" PRId64, semihosting->result);
1090 break;
1091
1092 case SEMIHOSTING_SYS_REMOVE: /* 0x0E */
1093 /*
1094 * Deletes a specified file on the host filing system.
1095 *
1096 * Entry
1097 * On entry, the PARAMETER REGISTER contains a pointer to a
1098 * two-field argument block:
1099 * - field 1 Points to a null-terminated string that gives the
1100 * path name of the file to be deleted.
1101 * - field 2 The length of the string.
1102 *
1103 * Return
1104 * On exit, the RETURN REGISTER contains:
1105 * - 0 if the delete is successful
1106 * - A nonzero, host-specific error code if the delete fails.
1107 */
1108 retval = semihosting_read_fields(target, 2, fields);
1109 if (retval != ERROR_OK)
1110 return retval;
1111 else {
1112 uint64_t addr = semihosting_get_field(target, 0, fields);
1113 size_t len = semihosting_get_field(target, 1, fields);
1114 if (semihosting->is_fileio) {
1115 semihosting->hit_fileio = true;
1116 fileio_info->identifier = "unlink";
1117 fileio_info->param_1 = addr;
1118 fileio_info->param_2 = len;
1119 } else {
1120 uint8_t *fn = malloc(len+1);
1121 if (!fn) {
1122 semihosting->result = -1;
1123 semihosting->sys_errno = ENOMEM;
1124 } else {
1125 retval =
1126 target_read_memory(target, addr, 1, len,
1127 fn);
1128 if (retval != ERROR_OK) {
1129 free(fn);
1130 return retval;
1131 }
1132 fn[len] = 0;
1133 semihosting->result = remove((char *)fn);
1134 semihosting->sys_errno = errno;
1135 LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result);
1136
1137 free(fn);
1138 }
1139 }
1140 }
1141 break;
1142
1143 case SEMIHOSTING_SYS_RENAME: /* 0x0F */
1144 /*
1145 * Renames a specified file.
1146 *
1147 * Entry
1148 * On entry, the PARAMETER REGISTER contains a pointer to a
1149 * four-field data block:
1150 * - field 1 A pointer to the name of the old file.
1151 * - field 2 The length of the old filename.
1152 * - field 3 A pointer to the new filename.
1153 * - field 4 The length of the new filename. Both strings are
1154 * null-terminated.
1155 *
1156 * Return
1157 * On exit, the RETURN REGISTER contains:
1158 * - 0 if the rename is successful.
1159 * - A nonzero, host-specific error code if the rename fails.
1160 */
1161 retval = semihosting_read_fields(target, 4, fields);
1162 if (retval != ERROR_OK)
1163 return retval;
1164 else {
1165 uint64_t addr1 = semihosting_get_field(target, 0, fields);
1166 size_t len1 = semihosting_get_field(target, 1, fields);
1167 uint64_t addr2 = semihosting_get_field(target, 2, fields);
1168 size_t len2 = semihosting_get_field(target, 3, fields);
1169 if (semihosting->is_fileio) {
1170 semihosting->hit_fileio = true;
1171 fileio_info->identifier = "rename";
1172 fileio_info->param_1 = addr1;
1173 fileio_info->param_2 = len1;
1174 fileio_info->param_3 = addr2;
1175 fileio_info->param_4 = len2;
1176 } else {
1177 uint8_t *fn1 = malloc(len1+1);
1178 uint8_t *fn2 = malloc(len2+1);
1179 if (!fn1 || !fn2) {
1180 free(fn1);
1181 free(fn2);
1182 semihosting->result = -1;
1183 semihosting->sys_errno = ENOMEM;
1184 } else {
1185 retval = target_read_memory(target, addr1, 1, len1,
1186 fn1);
1187 if (retval != ERROR_OK) {
1188 free(fn1);
1189 free(fn2);
1190 return retval;
1191 }
1192 retval = target_read_memory(target, addr2, 1, len2,
1193 fn2);
1194 if (retval != ERROR_OK) {
1195 free(fn1);
1196 free(fn2);
1197 return retval;
1198 }
1199 fn1[len1] = 0;
1200 fn2[len2] = 0;
1201 semihosting->result = rename((char *)fn1,
1202 (char *)fn2);
1203 semihosting->sys_errno = errno;
1204 LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno);
1205 free(fn1);
1206 free(fn2);
1207 }
1208 }
1209 }
1210 break;
1211
1212 case SEMIHOSTING_SYS_SEEK: /* 0x0A */
1213 /*
1214 * Seeks to a specified position in a file using an offset
1215 * specified from the start of the file. The file is assumed
1216 * to be a byte array and the offset is given in bytes.
1217 *
1218 * Entry
1219 * On entry, the PARAMETER REGISTER contains a pointer to a
1220 * two-field data block:
1221 * - field 1 A handle for a seekable file object.
1222 * - field 2 The absolute byte position to seek to.
1223 *
1224 * Return
1225 * On exit, the RETURN REGISTER contains:
1226 * - 0 if the request is successful.
1227 * - A negative value if the request is not successful.
1228 * Use SYS_ERRNO to read the value of the host errno variable
1229 * describing the error.
1230 *
1231 * Note: The effect of seeking outside the current extent of
1232 * the file object is undefined.
1233 */
1234 retval = semihosting_read_fields(target, 2, fields);
1235 if (retval != ERROR_OK)
1236 return retval;
1237 else {
1238 int fd = semihosting_get_field(target, 0, fields);
1239 off_t pos = semihosting_get_field(target, 1, fields);
1240 if (semihosting->is_fileio) {
1241 semihosting->hit_fileio = true;
1242 fileio_info->identifier = "lseek";
1243 fileio_info->param_1 = fd;
1244 fileio_info->param_2 = pos;
1245 fileio_info->param_3 = SEEK_SET;
1246 } else {
1247 semihosting->result = lseek(fd, pos, SEEK_SET);
1248 semihosting->sys_errno = errno;
1249 LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result);
1250 if (semihosting->result == pos)
1251 semihosting->result = 0;
1252 }
1253 }
1254 break;
1255
1256 case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */
1257 /*
1258 * Passes a command to the host command-line interpreter.
1259 * This enables you to execute a system command such as dir,
1260 * ls, or pwd. The terminal I/O is on the host, and is not
1261 * visible to the target.
1262 *
1263 * Entry
1264 * On entry, the PARAMETER REGISTER contains a pointer to a
1265 * two-field argument block:
1266 * - field 1 Points to a string to be passed to the host
1267 * command-line interpreter.
1268 * - field 2 The length of the string.
1269 *
1270 * Return
1271 * On exit, the RETURN REGISTER contains the return status.
1272 */
1273
1274 /* Provide SYS_SYSTEM functionality. Uses the
1275 * libc system command, there may be a reason *NOT*
1276 * to use this, but as I can't think of one, I
1277 * implemented it this way.
1278 */
1279 retval = semihosting_read_fields(target, 2, fields);
1280 if (retval != ERROR_OK)
1281 return retval;
1282 else {
1283 uint64_t addr = semihosting_get_field(target, 0, fields);
1284 size_t len = semihosting_get_field(target, 1, fields);
1285 if (semihosting->is_fileio) {
1286 semihosting->hit_fileio = true;
1287 fileio_info->identifier = "system";
1288 fileio_info->param_1 = addr;
1289 fileio_info->param_2 = len;
1290 } else {
1291 uint8_t *cmd = malloc(len+1);
1292 if (!cmd) {
1293 semihosting->result = -1;
1294 semihosting->sys_errno = ENOMEM;
1295 } else {
1296 retval = target_read_memory(target,
1297 addr,
1298 1,
1299 len,
1300 cmd);
1301 if (retval != ERROR_OK) {
1302 free(cmd);
1303 return retval;
1304 } else {
1305 cmd[len] = 0;
1306 semihosting->result = system(
1307 (const char *)cmd);
1308 LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result);
1309 }
1310
1311 free(cmd);
1312 }
1313 }
1314 }
1315 break;
1316
1317 case SEMIHOSTING_SYS_TIME: /* 0x11 */
1318 /*
1319 * Returns the number of seconds since 00:00 January 1, 1970.
1320 * This value is real-world time, regardless of any debug agent
1321 * configuration.
1322 *
1323 * Entry
1324 * There are no parameters.
1325 *
1326 * Return
1327 * On exit, the RETURN REGISTER contains the number of seconds.
1328 */
1329 semihosting->result = time(NULL);
1330 break;
1331
1332 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1333 /*
1334 * Writes the contents of a buffer to a specified file at the
1335 * current file position. The file position is specified either:
1336 * - Explicitly, by a SYS_SEEK.
1337 * - Implicitly as one byte beyond the previous SYS_READ or
1338 * SYS_WRITE request.
1339 *
1340 * The file position is at the start of the file when the file
1341 * is opened, and is lost when the file is closed.
1342 *
1343 * Perform the file operation as a single action whenever
1344 * possible. For example, do not split a write of 16KB into
1345 * four 4KB chunks unless there is no alternative.
1346 *
1347 * Entry
1348 * On entry, the PARAMETER REGISTER contains a pointer to a
1349 * three-field data block:
1350 * - field 1 Contains a handle for a file previously opened
1351 * with SYS_OPEN.
1352 * - field 2 Points to the memory containing the data to be written.
1353 * - field 3 Contains the number of bytes to be written from
1354 * the buffer to the file.
1355 *
1356 * Return
1357 * On exit, the RETURN REGISTER contains:
1358 * - 0 if the call is successful.
1359 * - The number of bytes that are not written, if there is an error.
1360 */
1361 retval = semihosting_read_fields(target, 3, fields);
1362 if (retval != ERROR_OK)
1363 return retval;
1364 else {
1365 int fd = semihosting_get_field(target, 0, fields);
1366 uint64_t addr = semihosting_get_field(target, 1, fields);
1367 size_t len = semihosting_get_field(target, 2, fields);
1368 if (semihosting->is_fileio) {
1369 semihosting->hit_fileio = true;
1370 fileio_info->identifier = "write";
1371 fileio_info->param_1 = fd;
1372 fileio_info->param_2 = addr;
1373 fileio_info->param_3 = len;
1374 } else {
1375 uint8_t *buf = malloc(len);
1376 if (!buf) {
1377 semihosting->result = -1;
1378 semihosting->sys_errno = ENOMEM;
1379 } else {
1380 retval = target_read_buffer(target, addr, len, buf);
1381 if (retval != ERROR_OK) {
1382 free(buf);
1383 return retval;
1384 }
1385 semihosting->result = semihosting_write(semihosting, fd, buf, len);
1386 semihosting->sys_errno = errno;
1387 LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
1388 fd,
1389 addr,
1390 len,
1391 semihosting->result);
1392 if (semihosting->result >= 0) {
1393 /* The number of bytes that are NOT written.
1394 * */
1395 semihosting->result = len -
1396 semihosting->result;
1397 }
1398
1399 free(buf);
1400 }
1401 }
1402 }
1403 break;
1404
1405 case SEMIHOSTING_SYS_WRITEC: /* 0x03 */
1406 /*
1407 * Writes a character byte, pointed to by the PARAMETER REGISTER,
1408 * to the debug channel. When executed under a semihosting
1409 * debugger, the character appears on the host debugger console.
1410 *
1411 * Entry
1412 * On entry, the PARAMETER REGISTER contains a pointer to the
1413 * character.
1414 *
1415 * Return
1416 * None. The RETURN REGISTER is corrupted.
1417 */
1418 if (semihosting->is_fileio) {
1419 semihosting->hit_fileio = true;
1420 fileio_info->identifier = "write";
1421 fileio_info->param_1 = 1;
1422 fileio_info->param_2 = semihosting->param;
1423 fileio_info->param_3 = 1;
1424 } else {
1425 uint64_t addr = semihosting->param;
1426 unsigned char c;
1427 retval = target_read_memory(target, addr, 1, 1, &c);
1428 if (retval != ERROR_OK)
1429 return retval;
1430 semihosting_putchar(semihosting, semihosting->stdout_fd, c);
1431 semihosting->result = 0;
1432 }
1433 break;
1434
1435 case SEMIHOSTING_SYS_WRITE0: /* 0x04 */
1436 /*
1437 * Writes a null-terminated string to the debug channel.
1438 * When executed under a semihosting debugger, the characters
1439 * appear on the host debugger console.
1440 *
1441 * Entry
1442 * On entry, the PARAMETER REGISTER contains a pointer to the
1443 * first byte of the string.
1444 *
1445 * Return
1446 * None. The RETURN REGISTER is corrupted.
1447 */
1448 if (semihosting->is_fileio) {
1449 size_t count = 0;
1450 uint64_t addr = semihosting->param;
1451 for (;; addr++) {
1452 unsigned char c;
1453 retval = target_read_memory(target, addr, 1, 1, &c);
1454 if (retval != ERROR_OK)
1455 return retval;
1456 if (c == '\0')
1457 break;
1458 count++;
1459 }
1460 semihosting->hit_fileio = true;
1461 fileio_info->identifier = "write";
1462 fileio_info->param_1 = 1;
1463 fileio_info->param_2 = semihosting->param;
1464 fileio_info->param_3 = count;
1465 } else {
1466 uint64_t addr = semihosting->param;
1467 do {
1468 unsigned char c;
1469 retval = target_read_memory(target, addr++, 1, 1, &c);
1470 if (retval != ERROR_OK)
1471 return retval;
1472 if (!c)
1473 break;
1474 semihosting_putchar(semihosting, semihosting->stdout_fd, c);
1475 } while (1);
1476 semihosting->result = 0;
1477 }
1478 break;
1479
1480 case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107:
1481 /**
1482 * This is a user defined operation (while user cmds 0x100-0x1ff
1483 * are possible, only 0x100-0x107 are currently implemented).
1484 *
1485 * Reads the user operation parameters from target, then fires the
1486 * corresponding target event. When the target callbacks returned,
1487 * cleans up the command parameter buffer.
1488 *
1489 * Entry
1490 * On entry, the PARAMETER REGISTER contains a pointer to a
1491 * two-field data block:
1492 * - field 1 Contains a pointer to the bound command parameter
1493 * string
1494 * - field 2 Contains the command parameter string length
1495 *
1496 * Return
1497 * On exit, the RETURN REGISTER contains the return status.
1498 */
1499 if (semihosting->user_command_extension) {
1500 retval = semihosting->user_command_extension(target);
1501 if (retval != ERROR_NOT_IMPLEMENTED)
1502 break;
1503 /* If custom user command not handled, we are looking for the TCL handler */
1504 }
1505
1506 assert(!semihosting_user_op_params);
1507 retval = semihosting_read_fields(target, 2, fields);
1508 if (retval != ERROR_OK) {
1509 LOG_ERROR("Failed to read fields for user defined command"
1510 " op=0x%x", semihosting->op);
1511 return retval;
1512 }
1513
1514 uint64_t addr = semihosting_get_field(target, 0, fields);
1515
1516 size_t len = semihosting_get_field(target, 1, fields);
1517 if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) {
1518 LOG_ERROR("The maximum length for user defined command "
1519 "parameter is %u, received length is %zu (op=0x%x)",
1520 SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH,
1521 len,
1522 semihosting->op);
1523 return ERROR_FAIL;
1524 }
1525
1526 semihosting_user_op_params = malloc(len + 1);
1527 if (!semihosting_user_op_params)
1528 return ERROR_FAIL;
1529 semihosting_user_op_params[len] = 0;
1530
1531 retval = target_read_buffer(target, addr, len,
1532 (uint8_t *)(semihosting_user_op_params));
1533 if (retval != ERROR_OK) {
1534 LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)",
1535 semihosting->op,
1536 semihosting_opcode_to_str(semihosting->op));
1537 free(semihosting_user_op_params);
1538 semihosting_user_op_params = NULL;
1539 return retval;
1540 }
1541
1542 target_handle_event(target, semihosting->op);
1543 free(semihosting_user_op_params);
1544 semihosting_user_op_params = NULL;
1545 semihosting->result = 0;
1546 break;
1547
1548 case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */
1549 /*
1550 * Returns the number of elapsed target ticks since execution
1551 * started.
1552 * Use SYS_TICKFREQ to determine the tick frequency.
1553 *
1554 * Entry (32-bit)
1555 * On entry, the PARAMETER REGISTER points to a two-field data
1556 * block to be used for returning the number of elapsed ticks:
1557 * - field 1 The least significant field and is at the low address.
1558 * - field 2 The most significant field and is at the high address.
1559 *
1560 * Entry (64-bit)
1561 * On entry the PARAMETER REGISTER points to a one-field data
1562 * block to be used for returning the number of elapsed ticks:
1563 * - field 1 The number of elapsed ticks as a 64-bit value.
1564 *
1565 * Return
1566 * On exit:
1567 * - On success, the RETURN REGISTER contains 0, the PARAMETER
1568 * REGISTER is unchanged, and the data block pointed to by the
1569 * PARAMETER REGISTER is filled in with the number of elapsed
1570 * ticks.
1571 * - On failure, the RETURN REGISTER contains -1, and the
1572 * PARAMETER REGISTER contains -1.
1573 *
1574 * Note: Some semihosting implementations might not support this
1575 * semihosting operation, and they always return -1 in the
1576 * RETURN REGISTER.
1577 */
1578
1579 case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */
1580 /*
1581 * Returns the tick frequency.
1582 *
1583 * Entry
1584 * The PARAMETER REGISTER must contain 0 on entry to this routine.
1585 *
1586 * Return
1587 * On exit, the RETURN REGISTER contains either:
1588 * - The number of ticks per second.
1589 * - –1 if the target does not know the value of one tick.
1590 *
1591 * Note: Some semihosting implementations might not support
1592 * this semihosting operation, and they always return -1 in the
1593 * RETURN REGISTER.
1594 */
1595
1596 case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */
1597 /*
1598 * Returns a temporary name for a file identified by a system
1599 * file identifier.
1600 *
1601 * Entry
1602 * On entry, the PARAMETER REGISTER contains a pointer to a
1603 * three-word argument block:
1604 * - field 1 A pointer to a buffer.
1605 * - field 2 A target identifier for this filename. Its value
1606 * must be an integer in the range 0-255.
1607 * - field 3 Contains the length of the buffer. The length must
1608 * be at least the value of L_tmpnam on the host system.
1609 *
1610 * Return
1611 * On exit, the RETURN REGISTER contains:
1612 * - 0 if the call is successful.
1613 * - –1 if an error occurs.
1614 *
1615 * The buffer pointed to by the PARAMETER REGISTER contains
1616 * the filename, prefixed with a suitable directory name.
1617 * If you use the same target identifier again, the same
1618 * filename is returned.
1619 *
1620 * Note: The returned string must be null-terminated.
1621 */
1622
1623 default:
1624 fprintf(stderr, "semihosting: unsupported call %#x\n",
1625 (unsigned) semihosting->op);
1626 semihosting->result = -1;
1627 semihosting->sys_errno = ENOTSUP;
1628 }
1629
1630 if (!semihosting->hit_fileio) {
1631 retval = semihosting->post_result(target);
1632 if (retval != ERROR_OK) {
1633 LOG_ERROR("Failed to post semihosting result");
1634 return retval;
1635 }
1636 }
1637
1638 return ERROR_OK;
1639 }
1640
1641 /* -------------------------------------------------------------------------
1642 * Local functions. */
1643
1644 static int semihosting_common_fileio_info(struct target *target,
1645 struct gdb_fileio_info *fileio_info)
1646 {
1647 struct semihosting *semihosting = target->semihosting;
1648 if (!semihosting)
1649 return ERROR_FAIL;
1650
1651 /*
1652 * To avoid unnecessary duplication, semihosting prepares the
1653 * fileio_info structure out-of-band when the target halts. See
1654 * do_semihosting for more detail.
1655 */
1656 if (!semihosting->is_fileio || !semihosting->hit_fileio)
1657 return ERROR_FAIL;
1658
1659 return ERROR_OK;
1660 }
1661
1662 static int semihosting_common_fileio_end(struct target *target, int result,
1663 int fileio_errno, bool ctrl_c)
1664 {
1665 struct gdb_fileio_info *fileio_info = target->fileio_info;
1666 struct semihosting *semihosting = target->semihosting;
1667 if (!semihosting)
1668 return ERROR_FAIL;
1669
1670 /* clear pending status */
1671 semihosting->hit_fileio = false;
1672
1673 semihosting->result = result;
1674 semihosting->sys_errno = fileio_errno;
1675
1676 /*
1677 * Some fileio results do not match up with what the semihosting
1678 * operation expects; for these operations, we munge the results
1679 * below:
1680 */
1681 switch (semihosting->op) {
1682 case SEMIHOSTING_SYS_WRITE: /* 0x05 */
1683 case SEMIHOSTING_SYS_READ: /* 0x06 */
1684 if (result < 0)
1685 semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */
1686 else
1687 semihosting->result = (int64_t)fileio_info->param_3 - result;
1688 break;
1689
1690 case SEMIHOSTING_SYS_SEEK: /* 0x0a */
1691 if (result > 0)
1692 semihosting->result = 0;
1693 break;
1694 }
1695
1696 return semihosting->post_result(target);
1697 }
1698
1699 /* -------------------------------------------------------------------------
1700 * Utility functions. */
1701
1702 /**
1703 * Read all fields of a command from target to buffer.
1704 */
1705 int semihosting_read_fields(struct target *target, size_t number,
1706 uint8_t *fields)
1707 {
1708 struct semihosting *semihosting = target->semihosting;
1709 /* Use 4-byte multiples to trigger fast memory access. */
1710 return target_read_memory(target, semihosting->param, 4,
1711 number * (semihosting->word_size_bytes / 4), fields);
1712 }
1713
1714 /**
1715 * Write all fields of a command from buffer to target.
1716 */
1717 int semihosting_write_fields(struct target *target, size_t number,
1718 uint8_t *fields)
1719 {
1720 struct semihosting *semihosting = target->semihosting;
1721 /* Use 4-byte multiples to trigger fast memory access. */
1722 return target_write_memory(target, semihosting->param, 4,
1723 number * (semihosting->word_size_bytes / 4), fields);
1724 }
1725
1726 /**
1727 * Extract a field from the buffer, considering register size and endianness.
1728 */
1729 uint64_t semihosting_get_field(struct target *target, size_t index,
1730 uint8_t *fields)
1731 {
1732 struct semihosting *semihosting = target->semihosting;
1733 if (semihosting->word_size_bytes == 8)
1734 return target_buffer_get_u64(target, fields + (index * 8));
1735 else
1736 return target_buffer_get_u32(target, fields + (index * 4));
1737 }
1738
1739 /**
1740 * Store a field in the buffer, considering register size and endianness.
1741 */
1742 void semihosting_set_field(struct target *target, uint64_t value,
1743 size_t index,
1744 uint8_t *fields)
1745 {
1746 struct semihosting *semihosting = target->semihosting;
1747 if (semihosting->word_size_bytes == 8)
1748 target_buffer_set_u64(target, fields + (index * 8), value);
1749 else
1750 target_buffer_set_u32(target, fields + (index * 4), value);
1751 }
1752
1753 /* -------------------------------------------------------------------------
1754 * Semihosting redirect over TCP structs and functions */
1755
1756 static int semihosting_service_new_connection_handler(struct connection *connection)
1757 {
1758 struct semihosting_tcp_service *service = connection->service->priv;
1759 service->semihosting->tcp_connection = connection;
1760
1761 return ERROR_OK;
1762 }
1763
1764 static int semihosting_service_input_handler(struct connection *connection)
1765 {
1766 struct semihosting_tcp_service *service = connection->service->priv;
1767
1768 if (!connection->input_pending) {
1769 /* consume received data, not for semihosting IO */
1770 const int buf_len = 100;
1771 char buf[buf_len];
1772 int bytes_read = connection_read(connection, buf, buf_len);
1773
1774 if (bytes_read == 0) {
1775 return ERROR_SERVER_REMOTE_CLOSED;
1776 } else if (bytes_read == -1) {
1777 LOG_ERROR("error during read: %s", strerror(errno));
1778 return ERROR_SERVER_REMOTE_CLOSED;
1779 }
1780 } else if (service->error != ERROR_OK) {
1781 return ERROR_SERVER_REMOTE_CLOSED;
1782 }
1783
1784 return ERROR_OK;
1785 }
1786
1787 static int semihosting_service_connection_closed_handler(struct connection *connection)
1788 {
1789 struct semihosting_tcp_service *service = connection->service->priv;
1790 if (service) {
1791 free(service->name);
1792 free(service);
1793 }
1794
1795 return ERROR_OK;
1796 }
1797
1798 static void semihosting_tcp_close_cnx(struct semihosting *semihosting)
1799 {
1800 if (!semihosting->tcp_connection)
1801 return;
1802
1803 struct service *service = semihosting->tcp_connection->service;
1804 remove_service(service->name, service->port);
1805 semihosting->tcp_connection = NULL;
1806
1807 }
1808
1809 static const struct service_driver semihosting_service_driver = {
1810 .name = "semihosting",
1811 .new_connection_during_keep_alive_handler = NULL,
1812 .new_connection_handler = semihosting_service_new_connection_handler,
1813 .input_handler = semihosting_service_input_handler,
1814 .connection_closed_handler = semihosting_service_connection_closed_handler,
1815 .keep_client_alive_handler = NULL,
1816 };
1817
1818 /* -------------------------------------------------------------------------
1819 * Common semihosting commands handlers. */
1820
1821 COMMAND_HANDLER(handle_common_semihosting_command)
1822 {
1823 struct target *target = get_current_target(CMD_CTX);
1824
1825 if (!target) {
1826 LOG_ERROR("No target selected");
1827 return ERROR_FAIL;
1828 }
1829
1830 struct semihosting *semihosting = target->semihosting;
1831 if (!semihosting) {
1832 command_print(CMD, "semihosting not supported for current target");
1833 return ERROR_FAIL;
1834 }
1835
1836 if (CMD_ARGC > 0) {
1837 int is_active;
1838
1839 COMMAND_PARSE_ENABLE(CMD_ARGV[0], is_active);
1840
1841 if (!target_was_examined(target)) {
1842 LOG_ERROR("Target not examined yet");
1843 return ERROR_FAIL;
1844 }
1845
1846 if (semihosting && semihosting->setup(target, is_active) != ERROR_OK) {
1847 LOG_ERROR("Failed to Configure semihosting");
1848 return ERROR_FAIL;
1849 }
1850
1851 /* FIXME never let that "catch" be dropped! (???) */
1852 semihosting->is_active = is_active;
1853 }
1854
1855 command_print(CMD, "semihosting is %s",
1856 semihosting->is_active
1857 ? "enabled" : "disabled");
1858
1859 return ERROR_OK;
1860 }
1861
1862 COMMAND_HANDLER(handle_common_semihosting_redirect_command)
1863 {
1864 struct target *target = get_current_target(CMD_CTX);
1865
1866 if (!target) {
1867 LOG_ERROR("No target selected");
1868 return ERROR_FAIL;
1869 }
1870
1871 struct semihosting *semihosting = target->semihosting;
1872 if (!semihosting) {
1873 command_print(CMD, "semihosting not supported for current target");
1874 return ERROR_FAIL;
1875 }
1876
1877 if (!semihosting->is_active) {
1878 command_print(CMD, "semihosting not yet enabled for current target");
1879 return ERROR_FAIL;
1880 }
1881
1882 enum semihosting_redirect_config cfg;
1883 const char *port;
1884
1885 if (CMD_ARGC < 1)
1886 return ERROR_COMMAND_SYNTAX_ERROR;
1887
1888 if (strcmp(CMD_ARGV[0], "disable") == 0) {
1889 cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
1890 if (CMD_ARGC > 1)
1891 return ERROR_COMMAND_SYNTAX_ERROR;
1892 } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
1893 if (CMD_ARGC < 2 || CMD_ARGC > 3)
1894 return ERROR_COMMAND_SYNTAX_ERROR;
1895
1896 port = CMD_ARGV[1];
1897
1898 cfg = SEMIHOSTING_REDIRECT_CFG_ALL;
1899 if (CMD_ARGC == 3) {
1900 if (strcmp(CMD_ARGV[2], "debug") == 0)
1901 cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG;
1902 else if (strcmp(CMD_ARGV[2], "stdio") == 0)
1903 cfg = SEMIHOSTING_REDIRECT_CFG_STDIO;
1904 else if (strcmp(CMD_ARGV[2], "all") != 0)
1905 return ERROR_COMMAND_SYNTAX_ERROR;
1906 }
1907 } else {
1908 return ERROR_COMMAND_SYNTAX_ERROR;
1909 }
1910
1911 semihosting_tcp_close_cnx(semihosting);
1912 semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE;
1913
1914 if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) {
1915 struct semihosting_tcp_service *service =
1916 calloc(1, sizeof(struct semihosting_tcp_service));
1917 if (!service) {
1918 LOG_ERROR("Failed to allocate semihosting TCP service.");
1919 return ERROR_FAIL;
1920 }
1921
1922 service->semihosting = semihosting;
1923
1924 service->name = alloc_printf("%s semihosting service", target_name(target));
1925 if (!service->name) {
1926 LOG_ERROR("Out of memory");
1927 free(service);
1928 return ERROR_FAIL;
1929 }
1930
1931 int ret = add_service(&semihosting_service_driver,
1932 port, 1, service);
1933
1934 if (ret != ERROR_OK) {
1935 LOG_ERROR("failed to initialize %s", service->name);
1936 free(service->name);
1937 free(service);
1938 return ERROR_FAIL;
1939 }
1940 }
1941
1942 semihosting->redirect_cfg = cfg;
1943
1944 return ERROR_OK;
1945 }
1946
1947 COMMAND_HANDLER(handle_common_semihosting_fileio_command)
1948 {
1949 struct target *target = get_current_target(CMD_CTX);
1950
1951 if (!target) {
1952 LOG_ERROR("No target selected");
1953 return ERROR_FAIL;
1954 }
1955
1956 struct semihosting *semihosting = target->semihosting;
1957 if (!semihosting) {
1958 command_print(CMD, "semihosting not supported for current target");
1959 return ERROR_FAIL;
1960 }
1961
1962 if (!semihosting->is_active) {
1963 command_print(CMD, "semihosting not yet enabled for current target");
1964 return ERROR_FAIL;
1965 }
1966
1967 if (CMD_ARGC > 0)
1968 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_fileio);
1969
1970 command_print(CMD, "semihosting fileio is %s",
1971 semihosting->is_fileio
1972 ? "enabled" : "disabled");
1973
1974 return ERROR_OK;
1975 }
1976
1977 COMMAND_HANDLER(handle_common_semihosting_cmdline)
1978 {
1979 struct target *target = get_current_target(CMD_CTX);
1980 unsigned int i;
1981
1982 if (!target) {
1983 LOG_ERROR("No target selected");
1984 return ERROR_FAIL;
1985 }
1986
1987 struct semihosting *semihosting = target->semihosting;
1988 if (!semihosting) {
1989 command_print(CMD, "semihosting not supported for current target");
1990 return ERROR_FAIL;
1991 }
1992
1993 free(semihosting->cmdline);
1994 semihosting->cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
1995
1996 for (i = 1; i < CMD_ARGC; i++) {
1997 char *cmdline = alloc_printf("%s %s", semihosting->cmdline, CMD_ARGV[i]);
1998 if (!cmdline)
1999 break;
2000 free(semihosting->cmdline);
2001 semihosting->cmdline = cmdline;
2002 }
2003
2004 command_print(CMD, "semihosting command line is [%s]",
2005 semihosting->cmdline);
2006
2007 return ERROR_OK;
2008 }
2009
2010 COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
2011 {
2012 struct target *target = get_current_target(CMD_CTX);
2013
2014 if (!target) {
2015 LOG_ERROR("No target selected");
2016 return ERROR_FAIL;
2017 }
2018
2019 struct semihosting *semihosting = target->semihosting;
2020 if (!semihosting) {
2021 command_print(CMD, "semihosting not supported for current target");
2022 return ERROR_FAIL;
2023 }
2024
2025 if (!semihosting->is_active) {
2026 command_print(CMD, "semihosting not yet enabled for current target");
2027 return ERROR_FAIL;
2028 }
2029
2030 if (CMD_ARGC > 0)
2031 COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->has_resumable_exit);
2032
2033 command_print(CMD, "semihosting resumable exit is %s",
2034 semihosting->has_resumable_exit
2035 ? "enabled" : "disabled");
2036
2037 return ERROR_OK;
2038 }
2039
2040 COMMAND_HANDLER(handle_common_semihosting_read_user_param_command)
2041 {
2042 struct target *target = get_current_target(CMD_CTX);
2043 struct semihosting *semihosting = target->semihosting;
2044
2045 if (CMD_ARGC)
2046 return ERROR_COMMAND_SYNTAX_ERROR;
2047
2048 if (!semihosting->is_active) {
2049 LOG_ERROR("semihosting not yet enabled for current target");
2050 return ERROR_FAIL;
2051 }
2052
2053 if (!semihosting_user_op_params) {
2054 LOG_ERROR("This command is usable only from a registered user "
2055 "semihosting event callback.");
2056 return ERROR_FAIL;
2057 }
2058
2059 command_print_sameline(CMD, "%s", semihosting_user_op_params);
2060
2061 return ERROR_OK;
2062 }
2063
2064 COMMAND_HANDLER(handle_common_semihosting_basedir_command)
2065 {
2066 struct target *target = get_current_target(CMD_CTX);
2067
2068 if (CMD_ARGC > 1)
2069 return ERROR_COMMAND_SYNTAX_ERROR;
2070
2071 if (!target) {
2072 LOG_ERROR("No target selected");
2073 return ERROR_FAIL;
2074 }
2075
2076 struct semihosting *semihosting = target->semihosting;
2077 if (!semihosting) {
2078 command_print(CMD, "semihosting not supported for current target");
2079 return ERROR_FAIL;
2080 }
2081
2082 if (!semihosting->is_active) {
2083 command_print(CMD, "semihosting not yet enabled for current target");
2084 return ERROR_FAIL;
2085 }
2086
2087 if (CMD_ARGC > 0) {
2088 free(semihosting->basedir);
2089 semihosting->basedir = strdup(CMD_ARGV[0]);
2090 if (!semihosting->basedir) {
2091 command_print(CMD, "semihosting failed to allocate memory for basedir!");
2092 return ERROR_FAIL;
2093 }
2094 }
2095
2096 command_print(CMD, "semihosting base dir: %s",
2097 semihosting->basedir ? semihosting->basedir : "");
2098
2099 return ERROR_OK;
2100 }
2101
2102 const struct command_registration semihosting_common_handlers[] = {
2103 {
2104 .name = "semihosting",
2105 .handler = handle_common_semihosting_command,
2106 .mode = COMMAND_EXEC,
2107 .usage = "['enable'|'disable']",
2108 .help = "activate support for semihosting operations",
2109 },
2110 {
2111 .name = "semihosting_redirect",
2112 .handler = handle_common_semihosting_redirect_command,
2113 .mode = COMMAND_EXEC,
2114 .usage = "(disable | tcp <port> ['debug'|'stdio'|'all'])",
2115 .help = "redirect semihosting IO",
2116 },
2117 {
2118 .name = "semihosting_cmdline",
2119 .handler = handle_common_semihosting_cmdline,
2120 .mode = COMMAND_EXEC,
2121 .usage = "arguments",
2122 .help = "command line arguments to be passed to program",
2123 },
2124 {
2125 .name = "semihosting_fileio",
2126 .handler = handle_common_semihosting_fileio_command,
2127 .mode = COMMAND_EXEC,
2128 .usage = "['enable'|'disable']",
2129 .help = "activate support for semihosting fileio operations",
2130 },
2131 {
2132 .name = "semihosting_resexit",
2133 .handler = handle_common_semihosting_resumable_exit_command,
2134 .mode = COMMAND_EXEC,
2135 .usage = "['enable'|'disable']",
2136 .help = "activate support for semihosting resumable exit",
2137 },
2138 {
2139 .name = "semihosting_read_user_param",
2140 .handler = handle_common_semihosting_read_user_param_command,
2141 .mode = COMMAND_EXEC,
2142 .usage = "",
2143 .help = "read parameters in semihosting-user-cmd-0x10X callbacks",
2144 },
2145 {
2146 .name = "semihosting_basedir",
2147 .handler = handle_common_semihosting_basedir_command,
2148 .mode = COMMAND_EXEC,
2149 .usage = "[dir]",
2150 .help = "set the base directory for semihosting I/O operations",
2151 },
2152 COMMAND_REGISTRATION_DONE
2153 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)