+ Describe what gdb_stdio does, describe what UT does.
+ Where raw files end up.
+ Dump files and how to use them.
+ + check if "CFLAGS: -mlittle-endian -mthumb -mthumb-interwork" needed
Getting Started
-------------------------
$ git clone https://github.com/texane/stlink.git
$ cd stlink
~/stlink$ git checkout bbecbc1e81b15b85829149424d048d96bd844939
- ~/stlink$ patch -p0 < ~/codec2-dev/stlink.patch
+ ~/stlink$ patch -p0 < ~/codec2-dev/stm32/stlink/stlink.patch
+ ~/stlink$ cp ~/codec2-dev/stm32/stlink/elfsym.* .
+ ~/stlink$ ./autogen.sh
+ ~/stlink$ ./configure
~/stlink$ make
. Place a copy of hts1a.raw in the stlink directory and start st-util:
~/stlink$ cp ~/codec2-dev/raw/hts1a .
~/stlink$ sudo ./st-util -f /home/david/codec2-dev/stm32/stm32f4_codec2.elf
-. Start gdb:
+. In _another_ console start gdb:
$ ~/codec2-dev/stm32$ ~/sat/bin/arm-none-eabi-gdb stm32f4_codec2.elf
1. Profiling macros.
-2. enable DUMP to dump files, note proofiling times will be corrupted
-by this due to latency in talking to Host
+2. enable DUMP variable in Makefile to dump files, note profiling
+times will be corrupted by this due to latency in talking to Host
3. Compare outputs using octave/diff_codec. Worked example:
Gotcha
------
-using printf rather than gdb_stdio_printf, regular stdio functions are stubbed out so will link, just nothing will happen.
+Using printf rather than gdb_stdio_printf, regular stdio functions are stubbed out so will link, just nothing will happen.
+++ /dev/null
-diff --git Makefile.am Makefile.am
-index a315dd7..7406216 100644
---- Makefile.am
-+++ Makefile.am
-@@ -7,7 +7,7 @@ bin_PROGRAMS = st-flash st-util
- noinst_LIBRARIES = libstlink.a
-
- st_flash_SOURCES = flash/main.c
--st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c mingw/mingw.c mingw/mingw.h
-+st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c gdbserver/elfsym.c mingw/mingw.c mingw/mingw.h
-
- CFILES = \
- src/stlink-common.c \
-@@ -24,14 +24,14 @@ HFILES = \
-
- libstlink_a_SOURCES = $(CFILES) $(HFILES)
-
--libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2
-+libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -g
- libstlink_a_LIBADD = $(LIBOBJS)
-
- st_flash_LDADD = libstlink.a
--st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
-+st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw
-
--st_util_LDADD = libstlink.a
--st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
-+st_util_LDADD = libstlink.a -lelf
-+st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw
-
- EXTRA_DIST = autogen.sh
-
-diff --git gdbserver/Makefile gdbserver/Makefile
-index bd5c73d..6763388 100644
---- gdbserver/Makefile
-+++ gdbserver/Makefile
-@@ -1,12 +1,11 @@
- PRG := st-util
--OBJS = gdb-remote.o gdb-server.o
-+OBJS = gdb-remote.o gdb-server.o elfsym.o
-
- CFLAGS+=-g -Wall -Werror -std=gnu99 -I../src
- LDFLAGS=-L.. -lstlink
-
- # libusb location
--LDFLAGS+=`pkg-config --libs libusb-1.0`
--CFLAGS+=`pkg-config --cflags libusb-1.0`
-+LDFLAGS+=`pkg-config --libs libusb-1.0` -lelfCFLAGS+=`pkg-config --cflags libusb-1.0`
-
- all: $(PRG)
-
-diff --git gdbserver/gdb-server.c gdbserver/gdb-server.c
-index f92fc05..e54d136 100644
---- gdbserver/gdb-server.c
-+++ gdbserver/gdb-server.c
-@@ -1,11 +1,12 @@
- /* -*- tab-width:8 -*- */
--#define DEBUG 0
-+//#define DEBUG 0
- /*
- Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file.
- */
-
-+#include <assert.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <string.h>
-@@ -20,14 +21,29 @@
- #include <arpa/inet.h>
- #include <signal.h>
- #endif
-+#include <sys/stat.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-
- #include <stlink-common.h>
-
- #include "gdb-remote.h"
-+#include "elfsym.h"
-
- #define DEFAULT_LOGGING_LEVEL 50
- #define DEFAULT_GDB_LISTEN_PORT 4242
-
-+/* stdio command codes from target */
-+
-+#define GDB_STDIO_PRINTF 1
-+#define GDB_STDIO_FOPEN 2
-+#define GDB_STDIO_FCLOSE 3
-+#define GDB_STDIO_FWRITE 4
-+#define GDB_STDIO_FREAD 5
-+#define GDB_STDIO_FPRINTF 6
-+
-+#define MAX_STR 256
-+
- #define STRINGIFY_inner(name) #name
- #define STRINGIFY(name) STRINGIFY_inner(name)
-
-@@ -46,11 +62,12 @@ typedef struct _st_state_t {
- // "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTE531X6-if00-port0" is only 58 chars
- char devicename[100];
- int logging_level;
-- int listen_port;
-+ int listen_port;
-+ char elf_filename[255];
- } st_state_t;
-
-
--int serve(stlink_t *sl, int port);
-+int serve(stlink_t *sl, int port, char *elf_filename);
- char* make_memory_map(stlink_t *sl);
-
-
-@@ -76,13 +93,14 @@ int parse_options(int argc, char** argv, st_state_t *st) {
- " -p 4242, --listen_port=1234\n"
- "\t\t\tSet the gdb server listen port. "
- "(default port: " STRINGIFY(DEFAULT_GDB_LISTEN_PORT) ")\n"
-+ " -f <elf_filename>\tenable File I/O of target executable elf_filename"
- ;
-
-
- int option_index = 0;
- int c;
- int q;
-- while ((c = getopt_long(argc, argv, "hv::d:s:1p:", long_options, &option_index)) != -1) {
-+ while ((c = getopt_long(argc, argv, "hv::d:s:1p:1f:", long_options, &option_index)) != -1) {
- switch (c) {
- case 0:
- printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n");
-@@ -110,25 +128,29 @@ int parse_options(int argc, char** argv, st_state_t *st) {
- strcpy(st->devicename, optarg);
- }
- break;
-- case '1':
-- st->stlink_version = 1;
-- break;
-- case 's':
-- sscanf(optarg, "%i", &q);
-- if (q < 0 || q > 2) {
-- fprintf(stderr, "stlink version %d unknown!\n", q);
-- exit(EXIT_FAILURE);
-- }
-- st->stlink_version = q;
-- break;
-- case 'p':
-- sscanf(optarg, "%i", &q);
-- if (q < 0) {
-- fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
-- exit(EXIT_FAILURE);
-- }
-- st->listen_port = q;
-- break;
-+ case '1':
-+ st->stlink_version = 1;
-+ break;
-+ case 's':
-+ sscanf(optarg, "%i", &q);
-+ if (q < 0 || q > 2) {
-+ fprintf(stderr, "stlink version %d unknown!\n", q);
-+ exit(EXIT_FAILURE);
-+ }
-+ st->stlink_version = q;
-+ break;
-+ case 'p':
-+ sscanf(optarg, "%i", &q);
-+ if (q < 0) {
-+ fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
-+ exit(EXIT_FAILURE);
-+ }
-+ st->listen_port = q;
-+ break;
-+ case 'f':
-+ sscanf(optarg, "%s", st->elf_filename);
-+ printf("-f arg; %s\n", st->elf_filename);
-+ break;
- }
- }
-
-@@ -162,7 +184,7 @@ int main(int argc, char** argv) {
- sl = stlink_v1_open(state.logging_level);
- if(sl == NULL) return 1;
- break;
-- }
-+ }
-
- printf("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
-
-@@ -177,7 +199,7 @@ int main(int argc, char** argv) {
- }
- #endif
-
-- while(serve(sl, state.listen_port) == 0);
-+ while(serve(sl, state.listen_port, state.elf_filename) == 0);
-
- #ifdef __MINGW32__
- winsock_error:
-@@ -625,7 +647,179 @@ error:
- return error;
- }
-
--int serve(stlink_t *sl, int port) {
-+static unsigned int func_addr, ret_addr, pstr1_addr, pstr2_addr;
-+static unsigned int strlen1_addr, strlen2_addr, file_addr, ptr_addr;
-+static unsigned int size_addr, nmem_addr;
-+
-+static void write_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) {
-+ /* write the buffer right after the loader */
-+ size_t chunk = size & ~0x3;
-+ size_t rem = size & 0x3;
-+
-+ if (chunk) {
-+ memcpy(sl->q_buf, buf, chunk);
-+ stlink_write_mem32(sl, target_addr, chunk);
-+ }
-+ if (rem) {
-+ memcpy(sl->q_buf, buf+chunk, rem);
-+ stlink_write_mem8(sl, target_addr+chunk, rem);
-+ }
-+}
-+
-+static void read_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) {
-+ unsigned adj_start = target_addr % 4;
-+ unsigned count_rnd = (size + adj_start + 4 - 1) / 4 * 4;
-+ size_t i;
-+
-+ stlink_read_mem32(sl, target_addr - adj_start, count_rnd);
-+
-+ for(i=0; i<size; i++)
-+ buf[i] = sl->q_buf[i + adj_start];
-+}
-+
-+static void fileio(stlink_t *sl)
-+{
-+ int func, pstr1, pstr2, strlen1, strlen2, ptr, size, nmem;
-+ int ret = 0;
-+ FILE *file;
-+ char file_name[MAX_STR];
-+ char mode[MAX_STR];
-+ char *buf;
-+
-+ stlink_read_mem32(sl, func_addr, 4);
-+ func = read_uint32(sl->q_buf, 0);
-+
-+ /* func != 0 means target has requested a system call */
-+
-+ switch(func) {
-+
-+ case GDB_STDIO_PRINTF:
-+ stlink_read_mem32(sl, pstr1_addr, 4);
-+ pstr1 = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, strlen1_addr, 4);
-+ strlen1 = read_uint32(sl->q_buf, 0);
-+ buf = (char*)malloc(strlen1+1);
-+ assert(buf != NULL);
-+ read_buffer(sl, pstr1, buf, strlen1);
-+ buf[strlen1] = 0;
-+ #ifdef DEBUG
-+ //printf("gdb_stdio printf pstr1: 0x%0x strlen1: %d buf: %s\n", pstr1, strlen1, buf);
-+ #endif
-+ fputs(buf, stdout);
-+ free(buf);
-+
-+ break;
-+
-+ case GDB_STDIO_FPRINTF:
-+ stlink_read_mem32(sl, file_addr, 4);
-+ file = (FILE*)read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, pstr1_addr, 4);
-+ pstr1 = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, strlen1_addr, 4);
-+ strlen1 = read_uint32(sl->q_buf, 0);
-+ buf = (char*)malloc(strlen1+1);
-+ assert(buf != NULL);
-+ read_buffer(sl, pstr1, buf, strlen1);
-+ buf[strlen1] = 0;
-+ #ifdef DEBUG
-+ //printf("gdb_stdio fprintf pstr1: 0x%0x strlen1: %d buf: %s file: 0x%x\n", pstr1, strlen1, buf, (unsigned int)file);
-+ #endif
-+ fputs(buf, file);
-+ free(buf);
-+
-+ break;
-+
-+ case GDB_STDIO_FOPEN:
-+ stlink_read_mem32(sl, pstr1_addr, 4);
-+ pstr1 = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, strlen1_addr, 4);
-+ strlen1 = read_uint32(sl->q_buf, 0);
-+ assert(strlen1 < MAX_STR);
-+ read_buffer(sl, pstr1, file_name, strlen1);
-+ file_name[strlen1] = 0;
-+
-+ stlink_read_mem32(sl, pstr2_addr, 4);
-+ pstr2 = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, strlen2_addr, 4);
-+ strlen2 = read_uint32(sl->q_buf, 0);
-+ assert(strlen2 < MAX_STR);
-+ read_buffer(sl, pstr2, mode, strlen2);
-+ mode[strlen2] = 0;
-+
-+ file = fopen(file_name, mode);
-+
-+ ret = (int)file;
-+ #ifdef DEBUG
-+ printf("gdb_stdio fopen file_name: %s mode: %s file: 0x%x\n", file_name, mode, (unsigned int)file);
-+ #endif
-+ break;
-+
-+ case GDB_STDIO_FCLOSE:
-+ stlink_read_mem32(sl, file_addr, 4);
-+ file = (FILE*)read_uint32(sl->q_buf, 0);
-+ fclose(file);
-+
-+ #ifdef DEBUG
-+ printf("gdb_stdio fclose file: 0x%x\n", (unsigned int)file);
-+ #endif
-+ break;
-+
-+ case GDB_STDIO_FWRITE:
-+ stlink_read_mem32(sl, ptr_addr, 4);
-+ ptr = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, size_addr, 4);
-+ size = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, nmem_addr, 4);
-+ nmem = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, file_addr, 4);
-+ file = (FILE*)read_uint32(sl->q_buf, 0);
-+
-+ buf = (char*)malloc(size*nmem);
-+ assert(buf != NULL);
-+ read_buffer(sl, ptr, buf, size*nmem);
-+ ret = fwrite(buf, size, nmem, file);
-+ free(buf);
-+ #ifdef DEBUG
-+ printf("gdb_stdio fwrite ptr: 0x%x size: %d nmem: %d file: 0x%x\n",
-+ ptr, size, nmem, (unsigned int)file);
-+ #endif
-+ break;
-+
-+ case GDB_STDIO_FREAD:
-+ stlink_read_mem32(sl, ptr_addr, 4);
-+ ptr = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, size_addr, 4);
-+ size = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, nmem_addr, 4);
-+ nmem = read_uint32(sl->q_buf, 0);
-+ stlink_read_mem32(sl, file_addr, 4);
-+ file = (FILE*)read_uint32(sl->q_buf, 0);
-+
-+ buf = (char*)malloc(size*nmem);
-+ assert(buf != NULL);
-+ ret = fread(buf, size, nmem, file);
-+ write_buffer(sl, ptr, buf, size*nmem);
-+ free(buf);
-+
-+ #ifdef DEBUG
-+ printf("gdb_stdio fread ptr: 0x%x size: %d nmem: %d file: 0x%x\n",
-+ ptr, size, nmem, (unsigned int)file);
-+ #endif
-+ break;
-+ }
-+
-+ if (func) {
-+ memcpy(sl->q_buf, &ret, sizeof(int));
-+ stlink_write_mem32(sl, ret_addr, 4);
-+
-+ func = 0;
-+ memcpy(sl->q_buf, &func, sizeof(int));
-+ stlink_write_mem32(sl, func_addr, 4);
-+ }
-+}
-+
-+
-+int serve(stlink_t *sl, int port, char *elf_filename) {
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- if(sock < 0) {
- perror("socket");
-@@ -650,7 +844,33 @@ int serve(stlink_t *sl, int port) {
- perror("listen");
- return 1;
- }
--\r
-+
-+ /* init for file I/O */
-+
-+ func_addr = ret_addr = pstr1_addr = pstr2_addr = strlen1_addr = strlen2_addr = 0;
-+ file_addr = ptr_addr = size_addr = nmem_addr = 0;
-+
-+ printf("elf_filename: %s----------------------------------\n", elf_filename);
-+ if (*elf_filename != 0) {
-+ int fd = elfsym_open(elf_filename);
-+ if (fd == -1)
-+ exit(0);
-+ func_addr = elfsym_get_symbol_address(fd, "gdb_stdio_func");
-+ ret_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ret");
-+ pstr1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr1");
-+ pstr2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr2");
-+ strlen1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen1");
-+ strlen2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen2");
-+ file_addr = elfsym_get_symbol_address(fd, "gdb_stdio_file");
-+ ptr_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ptr");
-+ size_addr = elfsym_get_symbol_address(fd, "gdb_stdio_size");
-+ nmem_addr = elfsym_get_symbol_address(fd, "gdb_stdio_nmem");
-+ elfsym_close(fd);
-+ #ifdef DEBUG
-+ printf("func_addr: 0x%x\n", func_addr);
-+ #endif
-+ }
-+
- start_again:
- stlink_force_debug(sl);
- stlink_reset(sl);
-@@ -924,8 +1144,13 @@ start_again:
- if(sl->core_stat == STLINK_CORE_HALTED) {
- break;
- }
-+
-+ /* file I/O if enabled */
-+
-+ if (*elf_filename != 0)
-+ fileio(sl);
-
-- usleep(100000);
-+ usleep(10000);
- }
-
- reply = strdup("S05"); // TRAP
--- /dev/null
+/*
+ elfsym.c
+
+ Read symbol adresses from a .elf file.
+
+ Based on libelf-howto.c from: http://em386.blogspot.com
+
+ Unit test with:
+
+ gcc elfsym.c -o elfsym -D__UNITTEST__ -Wall -lelf
+ ./elfsym elf_file.elf
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libelf.h>
+#include <gelf.h>
+#include "elfsym.h"
+
+#define ERR -1
+
+int elfsym_open(char file[]) {
+ int fd; /* File Descriptor */
+ char *base_ptr; /* ptr to our object in memory */
+ struct stat elf_stats; /* fstat struct */
+
+ if((fd = open(file, O_RDWR)) == ERR) {
+ printf("couldnt open %s\n", file);
+ return ERR;
+ }
+
+ if((fstat(fd, &elf_stats))) {
+ printf("could not fstat %s\n", file);
+ close(fd);
+ return ERR;
+ }
+
+ if((base_ptr = (char *) malloc(elf_stats.st_size)) == NULL) {
+ fprintf(stderr, "could not malloc\n");
+ close(fd);
+ return ERR;
+ }
+
+ if((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) {
+ fprintf(stderr, "could not read %s\n", file);
+ free(base_ptr);
+ close(fd);
+ return ERR;
+ }
+
+ /* Check libelf version first */
+
+ if(elf_version(EV_CURRENT) == EV_NONE) {
+ fprintf(stderr, "WARNING Elf Library is out of date!\n");
+ }
+
+ free(base_ptr);
+
+ return fd;
+}
+
+
+void elfsym_close(int fd) {
+ close(fd);
+}
+
+unsigned int elfsym_get_symbol_address(int fd, char symbol_name[])
+{
+ Elf_Scn *scn; /* Section Descriptor */
+ Elf_Data *edata; /* Data Descriptor */
+ GElf_Sym sym; /* Symbol */
+ GElf_Shdr shdr; /* Section Header */
+ Elf *elf; /* Our Elf pointer for libelf */
+ unsigned int symbol_address;
+ int symbol_count;
+ int i;
+
+ /* Iterate through section headers, stop when we find symbols,
+ and check for match */
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == 0) {
+ fprintf(stderr, "could not elf_begin\n");
+ }
+ symbol_address = 0;
+ scn = NULL;
+
+ while((scn = elf_nextscn(elf, scn)) != 0) {
+ gelf_getshdr(scn, &shdr);
+
+ // When we find a section header marked SHT_SYMTAB stop and get symbols
+ edata = NULL;
+ if(shdr.sh_type == SHT_SYMTAB) {
+ // edata points to our symbol table
+ edata = elf_getdata(scn, edata);
+
+ // how many symbols are there? this number comes from the size of
+ // the section divided by the entry size
+ symbol_count = shdr.sh_size / shdr.sh_entsize;
+
+ // loop through to grab all symbols
+ for(i = 0; i < symbol_count; i++) {
+ // libelf grabs the symbol data using gelf_getsym()
+ gelf_getsym(edata, i, &sym);
+
+ if (strcmp(symbol_name,
+ elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) {
+ symbol_address = sym.st_value;
+ }
+ }
+
+ }
+ }
+
+ return symbol_address;
+}
+
+#ifdef __UNITTEST__
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ unsigned int flag_addr, ptr_addr, file_addr, len_addr;
+
+ fd = elfsym_open(argv[1]);
+ flag_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_flag");
+ ptr_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_ptr");
+ file_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_file");
+ len_addr = elfsym_get_symbol_address(fd, "syscalls_gdb_len");
+ elfsym_close(fd);
+
+ printf("flag_addr: 0x%x\n", flag_addr);
+ printf("ptr_addr: 0x%x\n", ptr_addr);
+ printf("file_addr: 0x%x\n", file_addr);
+ printf("len_addr: 0x%x\n", len_addr);
+
+ return 0;
+}
+
+#endif
--- /dev/null
+/*
+ elfsym.h
+
+ Read symbol adresses from a .elf file.
+*/
+
+#ifndef __ELFSYM__
+#define __ELFSYM__
+
+int elfsym_open(char file[]);
+void elfsym_close(int fd);
+unsigned int elfsym_get_symbol_address(int fd, char symbol_name[]);
+
+#endif
--- /dev/null
+diff --git Makefile.am Makefile.am
+index a315dd7..7406216 100644
+--- Makefile.am
++++ Makefile.am
+@@ -7,7 +7,7 @@ bin_PROGRAMS = st-flash st-util
+ noinst_LIBRARIES = libstlink.a
+
+ st_flash_SOURCES = flash/main.c
+-st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c mingw/mingw.c mingw/mingw.h
++st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c gdbserver/elfsym.c mingw/mingw.c mingw/mingw.h
+
+ CFILES = \
+ src/stlink-common.c \
+@@ -24,14 +24,14 @@ HFILES = \
+
+ libstlink_a_SOURCES = $(CFILES) $(HFILES)
+
+-libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2
++libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -g
+ libstlink_a_LIBADD = $(LIBOBJS)
+
+ st_flash_LDADD = libstlink.a
+-st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
++st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+
+-st_util_LDADD = libstlink.a
+-st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
++st_util_LDADD = libstlink.a -lelf
++st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -g -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+
+ EXTRA_DIST = autogen.sh
+
+diff --git gdbserver/Makefile gdbserver/Makefile
+index bd5c73d..6763388 100644
+--- gdbserver/Makefile
++++ gdbserver/Makefile
+@@ -1,12 +1,11 @@
+ PRG := st-util
+-OBJS = gdb-remote.o gdb-server.o
++OBJS = gdb-remote.o gdb-server.o elfsym.o
+
+ CFLAGS+=-g -Wall -Werror -std=gnu99 -I../src
+ LDFLAGS=-L.. -lstlink
+
+ # libusb location
+-LDFLAGS+=`pkg-config --libs libusb-1.0`
+-CFLAGS+=`pkg-config --cflags libusb-1.0`
++LDFLAGS+=`pkg-config --libs libusb-1.0` -lelfCFLAGS+=`pkg-config --cflags libusb-1.0`
+
+ all: $(PRG)
+
+diff --git gdbserver/gdb-server.c gdbserver/gdb-server.c
+index f92fc05..e54d136 100644
+--- gdbserver/gdb-server.c
++++ gdbserver/gdb-server.c
+@@ -1,11 +1,12 @@
+ /* -*- tab-width:8 -*- */
+-#define DEBUG 0
++//#define DEBUG 0
+ /*
+ Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+ */
+
++#include <assert.h>
+ #include <getopt.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -20,14 +21,29 @@
+ #include <arpa/inet.h>
+ #include <signal.h>
+ #endif
++#include <sys/stat.h>
++#include <unistd.h>
++#include <fcntl.h>
+
+ #include <stlink-common.h>
+
+ #include "gdb-remote.h"
++#include "elfsym.h"
+
+ #define DEFAULT_LOGGING_LEVEL 50
+ #define DEFAULT_GDB_LISTEN_PORT 4242
+
++/* stdio command codes from target */
++
++#define GDB_STDIO_PRINTF 1
++#define GDB_STDIO_FOPEN 2
++#define GDB_STDIO_FCLOSE 3
++#define GDB_STDIO_FWRITE 4
++#define GDB_STDIO_FREAD 5
++#define GDB_STDIO_FPRINTF 6
++
++#define MAX_STR 256
++
+ #define STRINGIFY_inner(name) #name
+ #define STRINGIFY(name) STRINGIFY_inner(name)
+
+@@ -46,11 +62,12 @@ typedef struct _st_state_t {
+ // "/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTE531X6-if00-port0" is only 58 chars
+ char devicename[100];
+ int logging_level;
+- int listen_port;
++ int listen_port;
++ char elf_filename[255];
+ } st_state_t;
+
+
+-int serve(stlink_t *sl, int port);
++int serve(stlink_t *sl, int port, char *elf_filename);
+ char* make_memory_map(stlink_t *sl);
+
+
+@@ -76,13 +93,14 @@ int parse_options(int argc, char** argv, st_state_t *st) {
+ " -p 4242, --listen_port=1234\n"
+ "\t\t\tSet the gdb server listen port. "
+ "(default port: " STRINGIFY(DEFAULT_GDB_LISTEN_PORT) ")\n"
++ " -f <elf_filename>\tenable File I/O of target executable elf_filename"
+ ;
+
+
+ int option_index = 0;
+ int c;
+ int q;
+- while ((c = getopt_long(argc, argv, "hv::d:s:1p:", long_options, &option_index)) != -1) {
++ while ((c = getopt_long(argc, argv, "hv::d:s:1p:1f:", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 0:
+ printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n");
+@@ -110,25 +128,29 @@ int parse_options(int argc, char** argv, st_state_t *st) {
+ strcpy(st->devicename, optarg);
+ }
+ break;
+- case '1':
+- st->stlink_version = 1;
+- break;
+- case 's':
+- sscanf(optarg, "%i", &q);
+- if (q < 0 || q > 2) {
+- fprintf(stderr, "stlink version %d unknown!\n", q);
+- exit(EXIT_FAILURE);
+- }
+- st->stlink_version = q;
+- break;
+- case 'p':
+- sscanf(optarg, "%i", &q);
+- if (q < 0) {
+- fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
+- exit(EXIT_FAILURE);
+- }
+- st->listen_port = q;
+- break;
++ case '1':
++ st->stlink_version = 1;
++ break;
++ case 's':
++ sscanf(optarg, "%i", &q);
++ if (q < 0 || q > 2) {
++ fprintf(stderr, "stlink version %d unknown!\n", q);
++ exit(EXIT_FAILURE);
++ }
++ st->stlink_version = q;
++ break;
++ case 'p':
++ sscanf(optarg, "%i", &q);
++ if (q < 0) {
++ fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
++ exit(EXIT_FAILURE);
++ }
++ st->listen_port = q;
++ break;
++ case 'f':
++ sscanf(optarg, "%s", st->elf_filename);
++ printf("-f arg; %s\n", st->elf_filename);
++ break;
+ }
+ }
+
+@@ -162,7 +184,7 @@ int main(int argc, char** argv) {
+ sl = stlink_v1_open(state.logging_level);
+ if(sl == NULL) return 1;
+ break;
+- }
++ }
+
+ printf("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
+
+@@ -177,7 +199,7 @@ int main(int argc, char** argv) {
+ }
+ #endif
+
+- while(serve(sl, state.listen_port) == 0);
++ while(serve(sl, state.listen_port, state.elf_filename) == 0);
+
+ #ifdef __MINGW32__
+ winsock_error:
+@@ -625,7 +647,179 @@ error:
+ return error;
+ }
+
+-int serve(stlink_t *sl, int port) {
++static unsigned int func_addr, ret_addr, pstr1_addr, pstr2_addr;
++static unsigned int strlen1_addr, strlen2_addr, file_addr, ptr_addr;
++static unsigned int size_addr, nmem_addr;
++
++static void write_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) {
++ /* write the buffer right after the loader */
++ size_t chunk = size & ~0x3;
++ size_t rem = size & 0x3;
++
++ if (chunk) {
++ memcpy(sl->q_buf, buf, chunk);
++ stlink_write_mem32(sl, target_addr, chunk);
++ }
++ if (rem) {
++ memcpy(sl->q_buf, buf+chunk, rem);
++ stlink_write_mem8(sl, target_addr+chunk, rem);
++ }
++}
++
++static void read_buffer(stlink_t *sl, int target_addr, char* buf, size_t size) {
++ unsigned adj_start = target_addr % 4;
++ unsigned count_rnd = (size + adj_start + 4 - 1) / 4 * 4;
++ size_t i;
++
++ stlink_read_mem32(sl, target_addr - adj_start, count_rnd);
++
++ for(i=0; i<size; i++)
++ buf[i] = sl->q_buf[i + adj_start];
++}
++
++static void fileio(stlink_t *sl)
++{
++ int func, pstr1, pstr2, strlen1, strlen2, ptr, size, nmem;
++ int ret = 0;
++ FILE *file;
++ char file_name[MAX_STR];
++ char mode[MAX_STR];
++ char *buf;
++
++ stlink_read_mem32(sl, func_addr, 4);
++ func = read_uint32(sl->q_buf, 0);
++
++ /* func != 0 means target has requested a system call */
++
++ switch(func) {
++
++ case GDB_STDIO_PRINTF:
++ stlink_read_mem32(sl, pstr1_addr, 4);
++ pstr1 = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, strlen1_addr, 4);
++ strlen1 = read_uint32(sl->q_buf, 0);
++ buf = (char*)malloc(strlen1+1);
++ assert(buf != NULL);
++ read_buffer(sl, pstr1, buf, strlen1);
++ buf[strlen1] = 0;
++ #ifdef DEBUG
++ //printf("gdb_stdio printf pstr1: 0x%0x strlen1: %d buf: %s\n", pstr1, strlen1, buf);
++ #endif
++ fputs(buf, stdout);
++ free(buf);
++
++ break;
++
++ case GDB_STDIO_FPRINTF:
++ stlink_read_mem32(sl, file_addr, 4);
++ file = (FILE*)read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, pstr1_addr, 4);
++ pstr1 = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, strlen1_addr, 4);
++ strlen1 = read_uint32(sl->q_buf, 0);
++ buf = (char*)malloc(strlen1+1);
++ assert(buf != NULL);
++ read_buffer(sl, pstr1, buf, strlen1);
++ buf[strlen1] = 0;
++ #ifdef DEBUG
++ //printf("gdb_stdio fprintf pstr1: 0x%0x strlen1: %d buf: %s file: 0x%x\n", pstr1, strlen1, buf, (unsigned int)file);
++ #endif
++ fputs(buf, file);
++ free(buf);
++
++ break;
++
++ case GDB_STDIO_FOPEN:
++ stlink_read_mem32(sl, pstr1_addr, 4);
++ pstr1 = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, strlen1_addr, 4);
++ strlen1 = read_uint32(sl->q_buf, 0);
++ assert(strlen1 < MAX_STR);
++ read_buffer(sl, pstr1, file_name, strlen1);
++ file_name[strlen1] = 0;
++
++ stlink_read_mem32(sl, pstr2_addr, 4);
++ pstr2 = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, strlen2_addr, 4);
++ strlen2 = read_uint32(sl->q_buf, 0);
++ assert(strlen2 < MAX_STR);
++ read_buffer(sl, pstr2, mode, strlen2);
++ mode[strlen2] = 0;
++
++ file = fopen(file_name, mode);
++
++ ret = (int)file;
++ #ifdef DEBUG
++ printf("gdb_stdio fopen file_name: %s mode: %s file: 0x%x\n", file_name, mode, (unsigned int)file);
++ #endif
++ break;
++
++ case GDB_STDIO_FCLOSE:
++ stlink_read_mem32(sl, file_addr, 4);
++ file = (FILE*)read_uint32(sl->q_buf, 0);
++ fclose(file);
++
++ #ifdef DEBUG
++ printf("gdb_stdio fclose file: 0x%x\n", (unsigned int)file);
++ #endif
++ break;
++
++ case GDB_STDIO_FWRITE:
++ stlink_read_mem32(sl, ptr_addr, 4);
++ ptr = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, size_addr, 4);
++ size = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, nmem_addr, 4);
++ nmem = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, file_addr, 4);
++ file = (FILE*)read_uint32(sl->q_buf, 0);
++
++ buf = (char*)malloc(size*nmem);
++ assert(buf != NULL);
++ read_buffer(sl, ptr, buf, size*nmem);
++ ret = fwrite(buf, size, nmem, file);
++ free(buf);
++ #ifdef DEBUG
++ printf("gdb_stdio fwrite ptr: 0x%x size: %d nmem: %d file: 0x%x\n",
++ ptr, size, nmem, (unsigned int)file);
++ #endif
++ break;
++
++ case GDB_STDIO_FREAD:
++ stlink_read_mem32(sl, ptr_addr, 4);
++ ptr = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, size_addr, 4);
++ size = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, nmem_addr, 4);
++ nmem = read_uint32(sl->q_buf, 0);
++ stlink_read_mem32(sl, file_addr, 4);
++ file = (FILE*)read_uint32(sl->q_buf, 0);
++
++ buf = (char*)malloc(size*nmem);
++ assert(buf != NULL);
++ ret = fread(buf, size, nmem, file);
++ write_buffer(sl, ptr, buf, size*nmem);
++ free(buf);
++
++ #ifdef DEBUG
++ printf("gdb_stdio fread ptr: 0x%x size: %d nmem: %d file: 0x%x\n",
++ ptr, size, nmem, (unsigned int)file);
++ #endif
++ break;
++ }
++
++ if (func) {
++ memcpy(sl->q_buf, &ret, sizeof(int));
++ stlink_write_mem32(sl, ret_addr, 4);
++
++ func = 0;
++ memcpy(sl->q_buf, &func, sizeof(int));
++ stlink_write_mem32(sl, func_addr, 4);
++ }
++}
++
++
++int serve(stlink_t *sl, int port, char *elf_filename) {
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ if(sock < 0) {
+ perror("socket");
+@@ -650,7 +844,33 @@ int serve(stlink_t *sl, int port) {
+ perror("listen");
+ return 1;
+ }
+-\r
++
++ /* init for file I/O */
++
++ func_addr = ret_addr = pstr1_addr = pstr2_addr = strlen1_addr = strlen2_addr = 0;
++ file_addr = ptr_addr = size_addr = nmem_addr = 0;
++
++ printf("elf_filename: %s----------------------------------\n", elf_filename);
++ if (*elf_filename != 0) {
++ int fd = elfsym_open(elf_filename);
++ if (fd == -1)
++ exit(0);
++ func_addr = elfsym_get_symbol_address(fd, "gdb_stdio_func");
++ ret_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ret");
++ pstr1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr1");
++ pstr2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_pstr2");
++ strlen1_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen1");
++ strlen2_addr = elfsym_get_symbol_address(fd, "gdb_stdio_strlen2");
++ file_addr = elfsym_get_symbol_address(fd, "gdb_stdio_file");
++ ptr_addr = elfsym_get_symbol_address(fd, "gdb_stdio_ptr");
++ size_addr = elfsym_get_symbol_address(fd, "gdb_stdio_size");
++ nmem_addr = elfsym_get_symbol_address(fd, "gdb_stdio_nmem");
++ elfsym_close(fd);
++ #ifdef DEBUG
++ printf("func_addr: 0x%x\n", func_addr);
++ #endif
++ }
++
+ start_again:
+ stlink_force_debug(sl);
+ stlink_reset(sl);
+@@ -924,8 +1144,13 @@ start_again:
+ if(sl->core_stat == STLINK_CORE_HALTED) {
+ break;
+ }
++
++ /* file I/O if enabled */
++
++ if (*elf_filename != 0)
++ fileio(sl);
+
+- usleep(100000);
++ usleep(10000);
+ }
+
+ reply = strdup("S05"); // TRAP