Skip to content

Commit

Permalink
feature: memwatch: read memory while running
Browse files Browse the repository at this point in the history
  • Loading branch information
koendv committed Oct 24, 2023
1 parent 41bce05 commit 1cfaa53
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PROBE_HOST ?= native
PLATFORM_DIR = platforms/$(PROBE_HOST)
VPATH += $(PLATFORM_DIR) target
ENABLE_DEBUG ?=
ENABLE_MEMWATCH ?= 1

SYS = $(shell $(CC) -dumpmachine)

Expand Down Expand Up @@ -116,6 +117,11 @@ CFLAGS += -DPC_HOSTED=0
include platforms/common/Makefile.inc
endif

ifeq ($(ENABLE_MEMWATCH), 1)
CFLAGS += -DENABLE_MEMWATCH
SRC += memwatch.c
endif

ifeq ($(ENABLE_RTT), 1)
CFLAGS += -DENABLE_RTT
SRC += rtt.c rtt_if.c
Expand Down
30 changes: 30 additions & 0 deletions src/include/memwatch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef MEMWATCH_H
#define MEMWATCH_H

#include <stdint.h>
#include <stdbool.h>
#include <target.h>

#define MEMWATCH_NUM 8
/* string length has to be long enough to store an address 0x20000000 */
#define MEMWATCH_STRLEN 12

typedef enum memwatch_format {
MEMWATCH_FMT_SIGNED,
MEMWATCH_FMT_UNSIGNED,
MEMWATCH_FMT_HEX
} memwatch_format_e;

typedef struct {
uint32_t addr;
uint32_t value;
char name[MEMWATCH_STRLEN];
memwatch_format_e format;
} memwatch_s;

extern memwatch_s memwatch_table[MEMWATCH_NUM];
extern uint32_t memwatch_cnt;
extern bool memwatch_timestamp;
extern void poll_memwatch(target_s *cur_target);

#endif
5 changes: 5 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "gdb_packet.h"
#include "morse.h"
#include "command.h"
#include "memwatch.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
Expand Down Expand Up @@ -58,6 +59,10 @@ static void bmp_poll_loop(void)
#ifdef ENABLE_RTT
if (rtt_enabled)
poll_rtt(cur_target);
#endif
#ifdef ENABLE_MEMWATCH
if (memwatch_cnt != 0)
poll_memwatch(cur_target);
#endif
}

Expand Down
65 changes: 65 additions & 0 deletions src/memwatch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "general.h"
#include "gdb_packet.h"
#include "memwatch.h"
#include "rtt_if.h"
#if PC_HOSTED == 1
#include <unistd.h>
#else
#include "usb_serial.h"
#endif

memwatch_s memwatch_table[MEMWATCH_NUM];
uint32_t memwatch_cnt = 0;
bool memwatch_timestamp = false;

#ifndef ENABLE_RTT
uint32_t rtt_write(const char *buf, uint32_t len)
{
#if PC_HOSTED == 1
return write(1, buf, len);
#else
uint32_t start_ms = platform_time_ms();
while (usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf, len) <= 0) {
if (platform_time_ms() - start_ms >= 25)
return 0; /* drop silently */
}
return len;
#endif
}
#endif

void poll_memwatch(target_s *cur_target)
{
uint32_t val;
char buf[64];
char timestamp[64];
uint32_t len;
if (!cur_target || (memwatch_cnt == 0))
return;

for (uint32_t i = 0; i < memwatch_cnt; i++) {
if (!target_mem_read(cur_target, &val, memwatch_table[i].addr, sizeof(val)) &&
(val != memwatch_table[i].value)) {
if (memwatch_timestamp)
snprintf(timestamp, sizeof(timestamp), "%" PRIu32 " ", platform_time_ms());
else
timestamp[0] = '\0';
switch (memwatch_table[i].format) {
case MEMWATCH_FMT_SIGNED:
len = snprintf(buf, sizeof(buf), "%s%s %" PRId32 "\r\n", timestamp, memwatch_table[i].name, val);
break;
case MEMWATCH_FMT_UNSIGNED:
len = snprintf(buf, sizeof(buf), "%s%s %" PRIu32 "\r\n", timestamp, memwatch_table[i].name, val);
break;
case MEMWATCH_FMT_HEX:
default:
len = snprintf(buf, sizeof(buf), "%s%s 0x%" PRIx32 "\r\n", timestamp, memwatch_table[i].name, val);
break;
}
buf[sizeof(buf) - 1] = '\0';
rtt_write(buf, len);
memwatch_table[i].value = val;
}
}
return;
}
73 changes: 73 additions & 0 deletions src/target/cortexm.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "command.h"
#include "gdb_packet.h"
#include "semihosting.h"
#include "memwatch.h"
#include "platform.h"

#include <string.h>
Expand All @@ -53,6 +54,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>

#if PC_HOSTED == 1

Expand All @@ -72,12 +74,18 @@
#endif

static bool cortexm_vector_catch(target_s *t, int argc, const char **argv);
#ifdef ENABLE_MEMWATCH
static bool cortexm_memwatch(target_s *t, int argc, const char **argv);
#endif
#if PC_HOSTED == 0
static bool cortexm_redirect_stdout(target_s *t, int argc, const char **argv);
#endif

const command_s cortexm_cmd_list[] = {
{"vector_catch", cortexm_vector_catch, "Catch exception vectors"},
#ifdef ENABLE_MEMWATCH
{"memwatch", cortexm_memwatch, "Print variable when value changes: [[NAME] [/d|/u|/x] ADDRESS]..."},
#endif
#if PC_HOSTED == 0
{"redirect_stdout", cortexm_redirect_stdout, "Redirect semihosting stdout to USB UART"},
#endif
Expand Down Expand Up @@ -1376,6 +1384,71 @@ static bool cortexm_vector_catch(target_s *t, int argc, const char **argv)
return true;
}

#ifdef ENABLE_MEMWATCH
static bool cortexm_memwatch(target_s *t, int argc, const char **argv)
{
memwatch_format_e fmt = MEMWATCH_FMT_HEX;
char name[MEMWATCH_STRLEN] = {0};
memset(memwatch_table, 0, sizeof(memwatch_table));
memwatch_cnt = 0;
memwatch_timestamp = false;
/* target has to support debugger memory access while running */
if (target_mem_access_needs_halt(t)) {
gdb_out("memwatch not supported for target\n");
return true;
}
for (int32_t i = 1; i < argc; i++) {
if (argv[i][0] == '/') {
/* format follows */
switch (argv[i][1]) {
case 'd':
fmt = MEMWATCH_FMT_SIGNED;
break;
case 'u':
fmt = MEMWATCH_FMT_UNSIGNED;
break;
case 'x':
fmt = MEMWATCH_FMT_HEX;
break;
case 't':
memwatch_timestamp = true;
break;
default:
break;
}
} else if (isalpha(argv[i][0])) {
/* name follows */
strncpy(name, argv[i], sizeof(name));
name[sizeof(name) - 1] = '\0';
} else if (isdigit(argv[i][0])) {
/* address follows */
uint32_t addr = strtoul(argv[i], NULL, 0);

/* add new name, format and address to memwatch table */
if (name[0] == '\0') {
/* no name given, use address as name */
snprintf(name, MEMWATCH_STRLEN, "0x%08" PRIx32, addr);
name[MEMWATCH_STRLEN - 1] = '\0';
}
memwatch_table[memwatch_cnt].addr = addr;
memwatch_table[memwatch_cnt].value = 0xdeadbeef;
memwatch_table[memwatch_cnt].format = fmt;
memcpy(memwatch_table[memwatch_cnt].name, name, MEMWATCH_STRLEN);
memwatch_cnt++;
memset(name, 0, sizeof(name));
gdb_outf("0x%x ", addr);
if (memwatch_cnt == MEMWATCH_NUM)
break;
} else {
gdb_outf("?");
break;
}
}
gdb_outf("\n");
return true;
}
#endif

#if PC_HOSTED == 0
static bool cortexm_redirect_stdout(target_s *t, int argc, const char **argv)
{
Expand Down

0 comments on commit 1cfaa53

Please sign in to comment.