Skip to content

Instantly share code, notes, and snippets.

@mofosyne
Created December 17, 2019 04:05
Show Gist options
  • Save mofosyne/08a9f19a4ed029b1f80709d8cde7a5b2 to your computer and use it in GitHub Desktop.
Save mofosyne/08a9f19a4ed029b1f80709d8cde7a5b2 to your computer and use it in GitHub Desktop.
/***********************
SEMIHOSTING
************************/
#define SEMIHOSTING
#ifdef SEMIHOSTING
#include <stdarg.h>
#include <ctype.h> //isprint
/*
Note: This semihost printing utility functions is targeted towards STM32 based chips
*/
void arm_semihosting_print_string(char* str)
{
int len = 0;
/* Check if debugger is attached */
if (!((CoreDebug->DHCSR & 1) == 1 ))
return;
/* Calculate String Length */
for (len = 0; str[len]; (len)++);
/* Call Semihost */
int args[3] = {2 /*stderr*/, (int) str, (int)len};
asm volatile (
" mov r0, %[reason] \n"
" mov r1, %[arg] \n"
" bkpt %[swi] \n"
: /* Output */
: [reason] "r" (0x05), [arg] "r" (args), [swi] "i" (0xAB) /* Inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
);
}
void arm_semihosting_printf(char* format, ...)
{
char buff[400] = {0};
size_t buff_size = sizeof(buff);
/* Check if debugger is attached */
if (!((CoreDebug->DHCSR & 1) == 1 ))
{
return;
}
/* Format String */
va_list argptr;
va_start(argptr, format);
vasnprintf(buff, &buff_size, format, argptr);
va_end(argptr);
/* Print */
arm_semihosting_print_string(buff);
}
void arm_semihosting_hex_dump( const void *addr, const uint32_t nBytes)
{
const uint8_t byte_per_row = 16;
const uint8_t *addr_ptr = addr;
uint32_t offset = 0;
while (offset < nBytes)
{
char buff[400] = {0}; // Line Buff
char *buff_ptr = buff;
const char *buff_end = buff + sizeof(buff) - 1;
buff_ptr += snprintf(buff_ptr, buff_end-buff_ptr, " %4u | ", (unsigned) offset);
for (uint8_t i = 0 ; i < byte_per_row ; i++)
{ /* Hex */
if ((offset + i) >= nBytes)
break;
buff_ptr += snprintf(buff_ptr, buff_end-buff_ptr, " %02x", addr_ptr[offset+i]);
}
buff_ptr += snprintf(buff_ptr, buff_end-buff_ptr, " : ");
for (uint8_t i = 0 ; i < byte_per_row ; i++)
{ /* Printables */
if ((offset + i) >= nBytes) break;
char c = isprint(addr_ptr[offset+i]) ? addr_ptr[offset+i] : '.';
buff_ptr += snprintf(buff_ptr, buff_end-buff_ptr, "%c", c);
}
offset += byte_per_row;
arm_semihosting_print_string(buff);
arm_semihosting_print_string("\r\n");
}
arm_semihosting_print_string("\r\n");
}
#else
#define arm_semihosting_print_string(...)
#define arm_semihosting_printf(...)
#define arm_semihosting_hex_dump(...)
#endif
@mofosyne
Copy link
Author

mofosyne commented Dec 17, 2019

Example output

payload integrity fail (8020000,  255 bytes) (0 != ff)
    0 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   16 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   32 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   48 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   64 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   80 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
   96 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  112 |  00 00 00 00 00 00 00 00 00 00 00 00 7f 00 00 00  :  ................
  128 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  144 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  160 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  176 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  192 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  208 |  00 00 00 00 7f 00 00 00 00 00 00 00 00 00 00 00  :  ................
  224 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................
  240 |  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  :  ................

Useful for bootloader dev and other development where you don't have access to the serial console.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment