#What is Semihosting?
For more information on semihosting please refer to [this document](https://developer.arm.com/documentation/dui0471/m/what-is-semihosting-).
#Enabling Semihosting support in Code Composer Studio (CCS)
Semihosting support can be enabled/disabled via the **Program/Memory Load Options** debugger options. It is important to note that any program built with semihosting support will not run correctly when target is detached from the debugger or if semihosting support is disabled.
![](./images/ccs_semihosting_enable_semihosting.png)
#Using the Semihosting Example Template
An example tempate is available for some devices containing Cortex-A8 or Cortex-A9 cores. Note that the below example is for the Project Wizard in CCSv9.x. Other versions may vary slightly. TO use the example template:
- **File** -> **CCS Project**
- Provide a project name
- Select a device with a Cortex A8 or A9 ( **AM3359** as an exmaple )
- Set the **Compiler version** to **GNU**
- Expand the **Project templates and examples** node and select **Hello World** under **Basic Examples**
![](./images/ccs_semihosting_example.png)
#Limitations and Dependencies
### SVC_Handler
For architectures using the SWI/SVC instruction, the `SVC_Handler` symbol is used to determine where to set a breakpoint to intercept semihosting calls. A limitation of the CCS debugger is that when this breakpoint is hit, the debugger assumes that the SWI/SVC reason is semihosting and it does not check the instruction opcode as technically required. As such, if the SWI handler is used for purposes other than semihosting, the `SVC_Handler` symbol should be set to the address in the SWI handler where the reason of SWI/SVC instruction has been determined to be semihosting.
Also, note this is not required ARMv*-M architectures as semihosting is handled via a special `BKPT` instruction. Thus, the text in the dialog related to requiring a breakpoint at `SVC_Handler` may be misleading. However, the option still needs to be enabled, otherwise the debugger will just return without handling the call.
### Supported Calls
- SYS_CLOSE (0x02)
- SYS_ERRNO (0x13)
- SYS_FLEN (0x0C)
- SYS_GET_CMDLINE (0x15)
Use Memory.loadHostedProgram() API to load a program via DSS Scripting and provide command line arguments that should be passed to it.
Alternatively, the GEL function GEL_SetSemihostingMainArgs() could be used to set the argument string to be passed to main.
This semihosting call is generally made during the initialization by the c runtime library before main is reached.
Therefore, the GEL function must be called prior to the initialization code is executed.
- SYS_HEAPINFO (0x16)
In order to support this call(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/CHDJHHDI.html) the following symbols must be defined in the executable
__HeapBase
__HeapLimit
__StackLimit
__StackBase/__StackTop
The address of these symbols is used by the debugger to fulfill the requirements of the SYS_HEAPINFO call.
Note: This call is generally made by the initialization code of the semihosting enabled c library implementation.
- SYS_ISERROR (0x08)
- SYS_ISTTY (0x09)
- SYS_OPEN (0x01)
- SYS_READ (0x06)
- SYS_READC (0x07)
- SYS_REMOVE (0x0E)
- SYS_SEEK (0x0A)
- SYS_TMPNAM (0x0D)
- SYS_WRITE (0x05)
- SYS_WRITEC (0x03)
- SYS_WRITE0 (0x04)
- SYS_TIME (0x11)
- SYS_CLOCK (0x10)
- angel_SWIreason_ReportException, with reason code ADP_Stopped_ApplicationExit. (IE - End of program)
### Unsupported Calls
- SYS_SYSTEM (0x12)
- SYS_TICKFREQ (0x31)
- SYS_ELAPSED (0x30)
- SYS_RENAME (0x0F)
#stdio
Semihosting is, in theory, independent of C stdio. However, most C libraries provide semihosting support in a hosted environment by implementing the standard C stdio functions. To find out which stdio calls are supported, the specific C library documentation should be consulted.
CCS semihosting support is verified against the following test program built with the Linaro gcc toolchain.
```C
#include
#define long_len 1202
#define short_len 96
/********************************************************************************
* IOtest.c *
* *
* This is a test block for CIO. *
* Listing the functions tested by the block on stdin/stdout: *
* fflush(), puts(), fputs(), putc(), putchar(), fputc(), printf(), fwrite(), *
* gets(), fgets(), getc(), getchar(), fgetc(), scanf(), fread() *
* Listing the functions tested by the block on files: *
* fopen(), fclose(), remove(), fputs(), fgets(), fprintf(), fscanf(), fread(), *
* fwrite(), ftell(), rewind(), fgetpos(), fsetpos(), fseek(), ferror(), *
* perror(), clearerr(), feof() *
* *
*********************************************************************************/
char tmpch, ch = 'c';
// shortstring - string containing printable ASCII characters and some special characters
char * shortstring
= "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
// longstring - string of more than 1056 bytes to test overflow
char longstring[long_len];
char longtmpstring[long_len];
char tmpstring[short_len];
FILE * stream;
fpos_t pos;
//============================================================================
void puts_test (char * str) {
// Testing puts()
puts (str);
printf ("\n"); fflush (stdout);
}
void fputs_test (char * str) {
// Testing fputs(, stdout)
fputs (str, stdout);
printf ("\n"); fflush (stdout);
}
void printf_test (char * str) {
// Testing printf() on strings
printf ("%s", str);
printf ("\n"); fflush (stdout);
}
void fwrite_test (char * str) {
// Testing fwrite()
fwrite (str, sizeof(char), strlen(str), stdout);
printf ("\n"); fflush (stdout);
}
void reopen_stdin () {
// creating cio.in with information stored
stream = NULL;
if ((stream = fopen("cio.in", "w+")) != NULL) printf ("cio.in created\n");
fprintf (stream, "%s\n%s", shortstring, shortstring);
fflush (stream);
// Set pointer to beginning of file:
fseek (stream, 0L, SEEK_SET);
fscanf (stream, "%s", tmpstring);
if (strcmp(shortstring, tmpstring) == 0) printf ("cio.in initialized with a string\n");
else printf("cio.in not initialized with a string\n");
fclose (stream);
stream = freopen ("cio.in", "r+", stdin); // freopen() - reassigning stdin for further use
if (stream != NULL) printf ("stdin reassigned to cio.in\n");
else printf("stdin NOT reassigned cio.in\n");
}
void gets_test () {
// Testing gets()
rewind (stdin);
tmpstring[0] = '\0';
gets (tmpstring);
printf ("%s\n", tmpstring);
}
void return_value_of_gets_test () {
// No error should occur and gets() should not return NULL
rewind (stdin);
tmpstring[0] = '\0';
if (gets(tmpstring) != NULL) printf ("gets() successful\n");
else printf ("gets() not successful\n");
}
void fgets_test () {
// Testing fgets()
rewind (stdin);
tmpstring[0] = '\0';
fgets(tmpstring, short_len-1, stdin);
printf("%s\n", tmpstring);
}
void return_value_of_fgets_test () {
// No error should occur and fgets() should not return NULL
rewind (stdin);
tmpstring[0] = '\0';
if ( fgets(tmpstring, short_len-1, stdin) != NULL ) printf("fgets() successful\n");
else printf("fgets() not successful\n");
}
void getc_test () {
// Testing getc()
rewind (stdin);
tmpch = '\0';
tmpch = getc(stdin);
printf("%c\n", tmpch);
}
void ungetc_test () {
// Has to be run after getc_test or other call to getc
// Continuing the previous test - testing ungetc(, stdin)
ungetc(tmpch, stdin);
printf("After ungetc(), the first character in the stream is %c\n", getc(stdin));
}
void getchar_test () {
// Testing getchar()
rewind (stdin);
tmpch = '\0';
tmpch = getchar();
printf("%c\n", tmpch);
}
void fgetc_test () {
// Testing fgetc(stdin)
rewind (stdin);
tmpch = '\0';
tmpch = fgetc(stdin);
printf("%c\n", tmpch);
}
void scanf_test () {
// Testing scanf()
rewind (stdin);
tmpstring[0] = '\0';
scanf("%s", tmpstring);
printf("%s\n", tmpstring);
}
void fread_test () {
// Testing fread()
rewind (stdin);
tmpstring[0] = '\0';
fread(tmpstring, sizeof(char), short_len, stdin);
tmpstring[short_len-1] = '\0';
printf("%s\n", tmpstring);
}
void fclose_remove_file () {
// Has to be run after reopen_stdin ()
if( !fclose( stream ) ) printf ( "cio.in closed\n" );
if ( remove( "cio.in" ) == 0 ) printf ( "cio.in deleted\n" );
}
void fputs_fgets_test (char * str) {
// Testing fputs() and fgets() with files
// shortstring
rewind (stream);
fputs (str, stream); fflush (stream);
longtmpstring[0] = '\0';
rewind (stream);
fgets (longtmpstring, strlen (str) + 1, stream); // 1 is to account for the not counted '\0'
puts (longtmpstring); fflush (stdout);
}
void fprintf_fscanf_test (char * str) {
rewind (stream);
fprintf (stream, "%s", str); fflush (stream);
longtmpstring[0] = '\0';
rewind (stream);
fscanf (stream, "%s", longtmpstring);
puts (longtmpstring); fflush (stdout);
}
void fwrite_fread_test (char * str) {
rewind (stream);
fwrite (str, sizeof( char ), strlen(str), stream); fflush(stream);
longtmpstring[0] = '\0';
rewind (stream);
fread (longtmpstring, sizeof (char), strlen (str), stream); longtmpstring[strlen(str)] = '\0';
puts (longtmpstring); fflush (stdout);
}
void file_ftell_rewind_fgetpos_fsetpos_fseek_test () {
//------------------------------------------------------------------------
// Testing ftell(), rewind(), fgetpos(), fsetpos(), fseek()
// The following tests rely on the assumption that each character in the file is one byte
stream = fopen( "testfile2.tmp", "w+" );
fputs (shortstring, stream); fflush(stream);
rewind (stream);
// The position should be 0
printf ("%ld\n", ftell(stream));
fgets (tmpstring, 10, stream);
// After reading 10 bytes from the beginning of the file, the position should be 9
printf ("%ld\n", ftell(stream));
// Save the position 9 to pos
if (fgetpos(stream, &pos) != 0) printf("fgetpos() returned an error\n");
fgets (tmpstring, 10, stream );
// After reading 10 more bytes from the beginning of the file, the position should be 18
printf ("%ld\n", ftell(stream));
if (fsetpos( stream, &pos ) != 0 ) printf("fsetpos() returned an error\n");
// Now, the position should be 9 again
printf ("%ld\n", ftell(stream));
// Move pointer to the beginning of the file
if (fseek(stream, 0L, SEEK_SET)) printf ("fseek() returned an error\n");
// The position should be 0
printf ("%ld\n", ftell(stream));
fclose(stream);
}
void file_feof_test () {
// Testing feof() with testfile2.tmp from the previous test
stream = fopen("testfile2.tmp", "r");
fseek(stream, 0L, SEEK_END);
// go past the end of the file and attempt a read
tmpch = getc(stream);
if (feof(stream)) printf("end of file error\n");
else printf("no end of file error\n");
}
void file_ferror_perror_clearerr_test () {
// Testing stderr, ferror(), perror(), clearerr() with stdout
// Creating an error on stdin by attempting to write to it
clearerr(stdin);
if (ferror(stdin)) fprintf(stderr, "error not removed");
else perror("error removed");
}
//============================================================================
void main () {
// initializing longstring
int i;
for (i = 0; i < long_len-1; ++i) { longstring[i] = 'a';}
longstring[long_len-1] = '\0';
//------------------------------------------------------------------------
// Testing fflush(stdout)
fflush(stdout);
// Flushing stdout on a presumably empty buffer
if (fflush (stdout) == 0) printf ("stdout flushed successfully");
else printf ("stdout did not flush successfully");
fflush (stdout);
printf ("\n");
//------------------------------------------------------------------------
// Working with stdout
//------------------------------------------------------------------------
puts_test (shortstring);
puts_test (longstring);
fputs_test (shortstring);
fputs_test (longstring);
putc (ch, stdout); printf("\n"); fflush(stdout);
putchar (ch); printf("\n"); fflush(stdout);
fputc (ch, stdout); printf("\n"); fflush(stdout);
printf_test (shortstring);
printf_test (longstring);
printf("%c", ch); printf("\n"); fflush(stdout);
fwrite_test (shortstring);
fwrite_test (longstring);
//------------------------------------------------------------------------
// Testing standard input (reassigned to a file)
//------------------------------------------------------------------------
reopen_stdin ();
gets_test ();
return_value_of_gets_test ();
fgets_test ();
return_value_of_fgets_test ();
getc_test ();
ungetc_test ();
getchar_test ();
fgetc_test ();
scanf_test ();
fread_test ();
fclose_remove_file ();
//------------------------------------------------------------------------
// Working with files, input and output
//------------------------------------------------------------------------
if ((stream = fopen ("testfile1.tmp", "w+")) != NULL) printf ("testfile1.tmp opened\n");
fputs_fgets_test (shortstring);
fputs_fgets_test (longstring);
fclose (stream);
stream = fopen ("testfile1.tmp", "w+");
fprintf_fscanf_test (shortstring);
fprintf_fscanf_test (longstring);
fclose (stream);
stream = fopen ("testfile1.tmp", "w+");
fwrite_fread_test (shortstring);
fwrite_fread_test (longstring);
fclose (stream);
file_ftell_rewind_fgetpos_fsetpos_fseek_test (); // opens testfile2.tmp
file_feof_test ();
file_ferror_perror_clearerr_test ();
fclose (stream);
remove ("testfile1.tmp");
remove ("testfile2.tmp");
}
}
```