Skip to content

Commit

Permalink
Book: TSDL: bool type, enumerations, and comments; example with inclu…
Browse files Browse the repository at this point in the history
…des.

Merge fixes in issue #38 (thank you ALTracer).
CTF decoding: fix bugs due to data streams being split into multiple packets.
TSDL parser: support "bool", try include from path relative to source TSDL.
SWO trace capture: more solid handling of SWO packets being split across two USB packets.
BMDebug: show TSDL error in serial monitor too (if serial port is open); command to save the contents of the SWO Tracing log; fix re-download of firmware on a reset.
  • Loading branch information
compuphase committed Jan 1, 2024
1 parent 531cf04 commit acb08ca
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 94 deletions.
Binary file modified BlackMagicProbe.pdf
Binary file not shown.
64 changes: 56 additions & 8 deletions source/bmdebug.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@ static int console_autocomplete(char *text, size_t textsize, const DWARF_SYMBOLL
{ "quit", NULL, NULL },
{ "reset", NULL, "hard load" },
{ "run", NULL, NULL },
{ "semihosting", NULL, "clear" },
{ "semihosting", NULL, "clear save" },
{ "serial", NULL, "clear disable enable info plain save %path" },
{ "set", NULL, "%var" },
{ "start", NULL, NULL },
Expand Down Expand Up @@ -2944,6 +2944,9 @@ int ctf_error_notify(int code, int linenr, const char *message)
strlcpy(msg, "TSDL file error: ", sizearray(msg));
strlcat(msg, message, sizearray(msg));
tracelog_statusmsg(TRACESTATMSG_CTF, msg, 0);
if (sermon_isopen)
sermon_statusmsg(msg, true);
console_add(msg, STRFLG_ERROR);
}
return 0;
}
Expand Down Expand Up @@ -4312,6 +4315,7 @@ static bool handle_help_cmd(char *command, STRINGLIST *textroot, int *active,
stringlist_append(textroot, "Semihosting options.", 0);
stringlist_append(textroot, "", 0);
stringlist_append(textroot, "semimosting clear -- clear the semihosting monitor view (delete contents).", 0);
stringlist_append(textroot, "semihosting save [filename] -- save the contents in the semihosting monitor to a file.", 0);
} else if (TERM_EQU(cmdptr, "serial", 6)) {
stringlist_append(textroot, "Configure the serial monitor.", 0);
stringlist_append(textroot, "", 0);
Expand Down Expand Up @@ -5003,7 +5007,6 @@ static void trace_info_mode(const SWOSETTINGS *swo, int showchannels, STRINGLIST
*/
static int handle_trace_cmd(const char *command, SWOSETTINGS *swo)
{
char *ptr, *cmdcopy;
unsigned newmode = SWOMODE_NONE;
int tsdl_set = 0;

Expand All @@ -5013,13 +5016,29 @@ static int handle_trace_cmd(const char *command, SWOSETTINGS *swo)
return 0;

/* make a copy of the command string, to be able to clear parts of it */
cmdcopy = alloca(strlen(command) + 1);
char *cmdcopy = alloca(strlen(command) + 1);
strcpy(cmdcopy, command);
ptr = (char*)skipwhite(cmdcopy + 5);
char *ptr = (char*)skipwhite(cmdcopy + 5);

if (*ptr == '\0' || TERM_EQU(ptr, "info", 4))
return 3; /* if only "trace" is typed, interpret it as "trace info" */

char *opt_save;
if ((opt_save = strstr(cmdcopy, "save")) != NULL && TERM_END(opt_save, 4)) {
/* get the filename */
const char *ptr_name = skipwhite(opt_save + 4);
const char *tail = ptr_name;
while (*tail > ' ')
tail++;
if (tail != ptr_name) {
char *name = alloca((tail - ptr_name + 1) * sizeof(char));
strncpy(name, ptr_name, tail - ptr_name);
name[tail - ptr_name] = '\0';
tracestring_save(name);
}
memset(opt_save, ' ', tail - opt_save); /* erase the "save" parameter from the string (plus the filename) */
}

char *opt_clear;
if ((opt_clear = strstr(cmdcopy, "clear")) != NULL && TERM_END(opt_clear, 5)) {
tracestring_clear();
Expand Down Expand Up @@ -5235,6 +5254,30 @@ static bool handle_semihosting_cmd(const char *command)
const char *ptr = (char*)skipwhite(command + 11);
if (TERM_EQU(ptr, "clear", 5)) {
stringlist_clear(&semihosting_root);
} else if (TERM_EQU(ptr, "save", 4)) {
ptr = skipwhite(ptr + 4);
if (*ptr != '\0') {
FILE *fp = fopen(ptr, "wt");
if (fp != NULL) {
int count = 0;
STRINGLIST *item = semihosting_root.next;
while (item != NULL) {
assert(item->text != NULL);
fprintf(fp, "%s\n", item->text);
item = item->next;
count++;
}
fclose(fp);
char message[100];
sprintf(message,"%d lines saved\n", count);
console_add(message, STRFLG_STATUS);
} else {
console_add("Failed to save to file\n", STRFLG_ERROR);
}
} else {
console_add("Missing filename\n", STRFLG_ERROR);
}
return 4;
}

return true;
Expand Down Expand Up @@ -6968,8 +7011,9 @@ static void panel_serialmonitor(struct nk_context *ctx, APPSTATE *state,
int linecount = 0;
float lineheight = 0;
const char *text;
bool is_error;
sermon_rewind();
while ((text = sermon_next()) != NULL) {
while ((text = sermon_next(&is_error)) != NULL) {
nk_layout_row_begin(ctx, NK_STATIC, opt_fontsize, 1);
if (lineheight < 0.01) {
struct nk_rect rcline = nk_layout_widget_bounds(ctx);
Expand All @@ -6979,14 +7023,16 @@ static void panel_serialmonitor(struct nk_context *ctx, APPSTATE *state,
assert(font != NULL && font->width != NULL);
float textwidth = font->width(font->userdata, font->height, text, textlength) + 10;
nk_layout_row_push(ctx, textwidth);
nk_text(ctx, text, textlength, NK_TEXT_LEFT);
if (is_error)
nk_text_colored(ctx,text,textlength,NK_TEXT_LEFT, COLOUR_FG_RED);
else
nk_text(ctx,text,textlength,NK_TEXT_LEFT);
nk_layout_row_end(ctx);
linecount += 1;
}
if (!sermon_isopen()) {
struct nk_color clr = COLOUR_FG_RED;
nk_layout_row_dynamic(ctx, opt_fontsize, 1);
nk_label_colored(ctx, "No port opened", NK_TEXT_LEFT, clr);
nk_label_colored(ctx, "No port opened", NK_TEXT_LEFT, COLOUR_FG_RED);
linecount += 1;
}
nk_group_end(ctx);
Expand Down Expand Up @@ -7739,6 +7785,7 @@ static void handle_stateaction(APPSTATE *state, const enum nk_collapse_states ta
item->flags |= STRFLG_HANDLED;
}
if (item != NULL && strncmp(item->text, "warning:", 8) == 0) {
item->flags |= STRFLG_HANDLED;
MOVESTATE(state, STATE_DOWNLOAD);
if (!state->autodownload) {
/* make the mismatch stand out */
Expand Down Expand Up @@ -8574,6 +8621,7 @@ int main(int argc, char *argv[])
source_execfile = -1;
source_execline = 0;
disasm_init(&appstate.armstate, DISASM_ADDRESS | DISASM_INSTR | DISASM_COMMENT);
ctf_decode_reset();

ctx = guidriver_init("BlackMagic Debugger", canvas_width, canvas_height,
GUIDRV_RESIZEABLE | GUIDRV_TIMER, opt_fontstd, opt_fontmono, opt_fontsize);
Expand Down
2 changes: 1 addition & 1 deletion source/bmflash_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ const char bmflash_help[] = {
"It is a self-contained utility; it does not require GDB.\n"
"\n"
"---\n"
"Version 1.2.6986 \\\n"
"Version 1.2.7072M \\\n"
"Copyright 2019-2023 CompuPhase \\\n"
"Licensed under the Apache License version 2.0\n"
"\n"
Expand Down
2 changes: 1 addition & 1 deletion source/bmp-scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#define BMP_IF_UART 2 /* interface 2 -> 3.3V TTL UART */
#define BMP_IF_DFU 4
#define BMP_IF_TRACE 5
#define BMP_EP_TRACE 0x85 /* endpoint 5 is bulk data endpoint for trace interface */
#define BMP_EP_TRACE 0x85 /* endpoint 5 is bulk data endpoint for trace interface on the original BMP; may be overruled */

#define BMP_IF_SERIAL 9 /* pseudo-interface for getting the serial number */

Expand Down
36 changes: 29 additions & 7 deletions source/bmp-support.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ bool bmp_connect(int probe, const char *ipaddress)
gdbrsp_xmit("qRcmd,version", -1);
do {
size = gdbrsp_recv(buffer, sizearray(buffer)-1, 250);
} while (size > 0 && size < 2);
} while (!testreply(buffer, size, "OK"));
if (!testreply(buffer, size, "OK")) {
notice(BMPERR_NORESPONSE, "No response on %s", devname);
notice(BMPERR_NORESPONSE, "No valid response on %s", devname);
hCom = rs232_close(hCom);
return false;
}
Expand Down Expand Up @@ -1259,6 +1259,9 @@ bool bmp_dumpflash(const char *path, unsigned flashsize)
* this parameter. This parameter may be NULL.
*
* \return true on success, false on failure.
*
* \note Versions 1.6 .. 1.8.2: <serial>:<interface>:<endpoint>
* Version 1.9: Trace enabled for BMP serial <serial>, USB EP <endpoint>
*/
static bool bmp_parsetracereply(const char *reply, unsigned char *endpoint)
{
Expand All @@ -1273,7 +1276,7 @@ static bool bmp_parsetracereply(const char *reply, unsigned char *endpoint)
*endpoint = (unsigned char)ep;
}

/* reply changed in release 1.9: "Trace enabled for BMP serial <serial>, USB EP <endpoint>>" */
/* reply changed in release 1.9: "Trace enabled for BMP serial <serial>, USB EP <endpoint>" */
if (!ok && strncmp(reply, "Trace enabled", 13) == 0) {
ptr = strstr(reply, "USB EP");
if (ptr != NULL) {
Expand Down Expand Up @@ -1315,10 +1318,29 @@ bool bmp_enabletrace(int async_bitrate, unsigned char *endpoint)
if (rcvd > 0)
break;
}
/* a correct answer starts with 'o' and contains a serial number, the
interface for trace capture (0x05) and the endpoint (0x85, on the original
Black Magic Probe) */
buffer[rcvd] = '\0';
buffer[rcvd] = '\0'; /* force to zero-terminate */

/* the probe answers with a message (which starts with 'o' in the GDB RSP
protocol), with the USB endpoint for trace capture (0x85, on the original
Black Magic Probe); plus possibly the probe's serial number and the
interface for trace capture (the format of the message depends on the
version of the firmware) */

/* probes implementing asynchronous mode will post their baudrate first */
if (strncmp(buffer, "oBaudrate:", 10) == 0) {
/* get another packet which should contain the actual EP number */
rcvd = gdbrsp_recv(buffer, sizearray(buffer), 250);
buffer[rcvd] = '\0';
}
/* probes implementing Manchester mode will post their channel decode mask
first: 'Channel mask: 00000000000000000000000000000000' */
if (strncmp(buffer, "oChannel mask:", 14) == 0) {
/* drain the bits of mask coming in separate putchar-like packets */
do {
rcvd = gdbrsp_recv(buffer, sizearray(buffer), 250);
} while (rcvd > 0 && rcvd < 3);
buffer[rcvd] = '\0';
}
bool ok = (buffer[0] == 'o') && bmp_parsetracereply(buffer + 1, endpoint);
if (!ok)
notice(BMPERR_MONITORCMD, "Trace setup failed");
Expand Down
2 changes: 1 addition & 1 deletion source/bmprofile_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ const char bmprofile_help[] = {
"Black Magic Probe. It is a self-contained utility; it does not require GDB.\n"
"\n"
"---\n"
"Version 1.2.6986 \\\n"
"Version 1.2.7072M \\\n"
"Copyright 2022-2023 CompuPhase \\\n"
"Licensed under the Apache License version 2.0\n"
"\n"
Expand Down
2 changes: 1 addition & 1 deletion source/bmserial_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ const char bmserial_help[] = {
"The book is available as a free PDF file, and as a printed book.\n"
"\n"
"---\n"
"Version 1.2.6986 \\\n"
"Version 1.2.7072M \\\n"
"Copyright 2022-2023 CompuPhase \\\n"
"Licensed under the Apache License version 2.0\n"
"\n"
Expand Down
15 changes: 9 additions & 6 deletions source/bmtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ static void handle_stateaction(APPSTATE *state)
{
if (state->reinitialize == 1) {
int result;
char msg[100];
char msg[200];
tracelog_statusclear();
tracestring_clear();
trace_overflowerrors(true);
Expand Down Expand Up @@ -1037,7 +1037,7 @@ static void handle_stateaction(APPSTATE *state)
case TRACESTAT_OK:
if (state->init_target || state->init_bmp) {
assert(strlen(state->mcu_family) > 0);
sprintf(msg, "Connected [%s]", state->mcu_family);
snprintf(msg, sizearray(msg), "Connected [%s]", state->mcu_family);
tracelog_statusmsg(TRACESTATMSG_BMP, msg, BMPSTAT_SUCCESS);
} else {
tracelog_statusmsg(TRACESTATMSG_BMP, "Listening (passive mode)...", BMPSTAT_SUCCESS);
Expand All @@ -1047,10 +1047,13 @@ static void handle_stateaction(APPSTATE *state)
case TRACESTAT_NO_INTERFACE:
case TRACESTAT_NO_DEVPATH:
case TRACESTAT_NO_PIPE:
strlcpy(msg, "Trace interface not available", sizearray(msg));
if (state->probe == state->netprobe && state->swomode != MODE_ASYNC)
strlcat(msg, "; try NRZ/Async mode", sizearray(msg));
tracelog_statusmsg(TRACESTATMSG_BMP, msg, BMPERR_GENERAL);
{ int loc;
unsigned long error = trace_errno(&loc);
snprintf(msg, sizearray(msg), "Trace interface not available (%d), error %d:%lu", state->trace_status, loc, error);
if (state->probe == state->netprobe && state->swomode != MODE_ASYNC)
strlcat(msg, "; try NRZ/Async mode", sizearray(msg));
tracelog_statusmsg(TRACESTATMSG_BMP, msg, BMPERR_GENERAL);
}
break;
case TRACESTAT_NO_ACCESS:
{ int loc;
Expand Down
2 changes: 1 addition & 1 deletion source/bmtrace_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ const char bmtrace_help[] = {
"Black Magic Probe. It is a self-contained utility; it does not require GDB.\n"
"\n"
"---\n"
"Version 1.2.6986 \\\n"
"Version 1.2.7072M \\\n"
"Copyright 2019-2023 CompuPhase \\\n"
"Licensed under the Apache License version 2.0\n"
"\n"
Expand Down
23 changes: 19 additions & 4 deletions source/decodectf.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ static void cache_grow(size_t extra)
cache = (unsigned char*)malloc(cache_size);
} else {
unsigned char *newcache = (unsigned char*)realloc(cache, cache_size);
if (newcache == NULL)
if (newcache == NULL) {
free((void*)cache);
cache_size = 0;
}
cache = newcache;
}
assert(cache != NULL); /* should be handled as a run-time error */
Expand Down Expand Up @@ -134,8 +136,10 @@ static void msgbuffer_grow(size_t extra)
msgbuffer = (char*)malloc(msgbuffer_size);
} else {
char *newbuffer = (char*)realloc(msgbuffer, msgbuffer_size);
if (newbuffer == NULL)
if (newbuffer == NULL) {
free((void*)msgbuffer);
msgbuffer_size = 0;
}
msgbuffer = newbuffer;
}
assert(msgbuffer != NULL);
Expand Down Expand Up @@ -379,6 +383,10 @@ static char *fmt_int64(int64_t num, char *str, int base)

static void format_field(const char *fieldname, const CTF_TYPE *type, const unsigned char *data)
{
assert(fieldname);
assert(type);
assert(data);

msgbuffer_append(fieldname, -1);
msgbuffer_append(" = ", 3);

Expand Down Expand Up @@ -466,6 +474,12 @@ static void format_field(const char *fieldname, const CTF_TYPE *type, const unsi
msgbuffer_append(" }", 2);
break;

case CLASS_BOOL:
assert(type->size == 8);
assert(!(type->flags & TYPEFLAG_SIGNED));
msgbuffer_append(*data ? "true" : "false", -1);
break;

default:
assert(0);
} /* switch (typeclass) */
Expand All @@ -478,7 +492,6 @@ int ctf_decode(const unsigned char *stream, size_t size, long channel)
if (event_count(-1) == 0) /* no events defined, nothing to do */
return 0;

cache_reset();
result = 0;
idx = 0;

Expand Down Expand Up @@ -520,6 +533,7 @@ int ctf_decode(const unsigned char *stream, size_t size, long channel)
}
}
if (state == STATE_SCAN_MAGIC) {
/* scanning for header (so cache check failed) */
while (idx < size) {
while (idx < size && stream[idx] != magic[0])
idx++; /* find first byte of the magic */
Expand All @@ -528,7 +542,7 @@ int ctf_decode(const unsigned char *stream, size_t size, long channel)
len = pkt_header->header.magic_size / 8;
if (idx + len > size)
len = size - idx;
if (memcmp(stream, magic + cache_filled, len) == 0) {
if (memcmp(stream + idx, magic + cache_filled, len) == 0) {
/* match, check whether this is still a patial match */
if (len == pkt_header->header.magic_size / 8u) {
state++; /* full match -> advance state & restart */
Expand Down Expand Up @@ -712,6 +726,7 @@ int ctf_decode(const unsigned char *stream, size_t size, long channel)
switch (field->type.typeclass) {
case CLASS_INTEGER:
case CLASS_FLOAT:
case CLASS_BOOL:
case CLASS_ENUM:
case CLASS_STRUCT:
assert(field->type.size / 8 > 0);
Expand Down
4 changes: 2 additions & 2 deletions source/nuklear.c
Original file line number Diff line number Diff line change
Expand Up @@ -18880,8 +18880,8 @@ nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,
/* calculate button content space */
content->x = r.x + style->padding.x + style->border + style->rounding;
content->y = r.y + style->padding.y + style->border + style->rounding;
content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2);
content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2);
content->w = r.w - (2 * style->padding.x + style->border + style->rounding);
content->h = r.h - (2 * style->padding.y + style->border + style->rounding);

/* execute button behavior */
bounds.x = r.x - style->touch_padding.x;
Expand Down
Loading

0 comments on commit acb08ca

Please sign in to comment.