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 Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ +#include #include #include #include @@ -20,14 +21,29 @@ #include #include #endif +#include +#include +#include #include #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 \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; iq_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; } - + + /* 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