mirror of
https://github.com/digarok/gsplus.git
synced 2024-06-08 10:45:07 +00:00
Debugger - GSBug.Templates support.
address\temp TemplateName to print structured memory. Also, registers now need a % prefix so as not to interfere with other commands.
This commit is contained in:
parent
2f05a766b0
commit
5cb4f63993
|
@ -78,6 +78,12 @@ add_custom_command(
|
|||
MAIN_DEPENDENCY debug_shell.re2c
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT debug_template.c
|
||||
COMMAND re2c -W -o ${CMAKE_CURRENT_BINARY_DIR}/debug_template.c "${CMAKE_CURRENT_SOURCE_DIR}/debug_template.re2c"
|
||||
MAIN_DEPENDENCY debug_template.re2c
|
||||
)
|
||||
|
||||
add_executable(to_pro to_pro.c)
|
||||
add_executable(partls partls.c)
|
||||
|
||||
|
@ -124,6 +130,7 @@ add_executable(GSplus WIN32 MACOSX_BUNDLE
|
|||
|
||||
disasm.c
|
||||
debug_shell.c
|
||||
debug_template.c
|
||||
|
||||
$<$<BOOL:${WITH_DEBUGGER}>:debug.c>
|
||||
$<$<BOOL:${WITH_HOST_FST}>:${host_fst_code}>
|
||||
|
@ -132,6 +139,7 @@ add_executable(GSplus WIN32 MACOSX_BUNDLE
|
|||
|
||||
$<$<BOOL:${WIN32}>:win32.rc>
|
||||
$<$<BOOL:${APPLE}>:assets/gsp_icon.icns>
|
||||
$<$<BOOL:${APPLE}>:assets/GSBug.Templates>
|
||||
$<$<BOOL:${APPLE}>:fix_mac_menu.m>
|
||||
)
|
||||
|
||||
|
@ -140,8 +148,13 @@ SET_SOURCE_FILES_PROPERTIES(
|
|||
assets/gsp_icon.icns
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
)
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(
|
||||
assets/GSBug.Templates
|
||||
PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
|
|
2549
src/assets/GSBug.Templates
Normal file
2549
src/assets/GSBug.Templates
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -42,6 +42,63 @@ static word32 g_prev_address = 0;
|
|||
static word32 g_prev_stack_address = 0;
|
||||
static word32 g_prev_stack_bank = 0;
|
||||
|
||||
|
||||
static int g_templates_loaded = 0;
|
||||
extern void debug_load_template(const char *path);
|
||||
extern word32 debug_apply_template(word32 address, const char *name);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
static char *get_resource_path(const char *leaf) {
|
||||
|
||||
uint32_t size = 0;
|
||||
char *buffer = 0;
|
||||
int ok;
|
||||
char *cp;
|
||||
int l;
|
||||
|
||||
l = strlen(leaf);
|
||||
ok = _NSGetExecutablePath(NULL, &size);
|
||||
size += l + 1 + sizeof("Resources/");
|
||||
buffer = malloc(size);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
/*
|
||||
* expect .../GSPlus.app/Contents/MacOS/GSPlus
|
||||
* drop
|
||||
*/
|
||||
ok = _NSGetExecutablePath(buffer, &size);
|
||||
if (ok < 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
cp = strrchr(buffer, '/');
|
||||
if (!cp) { free(buffer); return NULL; }
|
||||
*cp = 0;
|
||||
cp = strrchr(buffer, '/');
|
||||
if (!cp) { free(buffer); return NULL; }
|
||||
|
||||
strcpy(cp + 1, "Resources/");
|
||||
strcat(cp, leaf);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
/* todo -- something clever like find the home directory */
|
||||
#else
|
||||
static char *get_resource_path(const char *leaf) {
|
||||
int l;
|
||||
char *cp;
|
||||
static char path[] = "/usr/local/share/gsplus/";
|
||||
l = strlen(leaf);
|
||||
cp = malloc(l + sizeof(path) + 1);
|
||||
if (!cp) return NULL;
|
||||
strcpy(cp, path);
|
||||
strcat(cp, leaf);
|
||||
return cp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* todo
|
||||
* - tool break support
|
||||
|
@ -380,7 +437,8 @@ static word32 to_hex(const char *iter, const char *end) {
|
|||
/*!re2c
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:yyfill:enable = 0;
|
||||
end = "\x00";
|
||||
eol = "\x00";
|
||||
ws = [ \t];
|
||||
x = [A-Fa-f0-9];
|
||||
*/
|
||||
|
||||
|
@ -394,23 +452,23 @@ static int do_assign(const char *cp, int reg) {
|
|||
/*!re2c
|
||||
|
||||
* { return -1; }
|
||||
x{6} end {
|
||||
x{6} eol {
|
||||
addr = to_hex(cp, cp + 6);
|
||||
has_bank = 1;
|
||||
goto next;
|
||||
}
|
||||
x{2} "/" x{4} end {
|
||||
x{2} "/" x{4} eol {
|
||||
addr = to_hex(cp, cp + 2) << 16;
|
||||
addr |= to_hex(cp + 3, cp + 7);
|
||||
has_bank = 1;
|
||||
goto next;
|
||||
}
|
||||
x{4} end {
|
||||
x{4} eol {
|
||||
addr = to_hex(cp, cp + 4);
|
||||
has_bank = 0;
|
||||
goto next;
|
||||
}
|
||||
"%"[01]{2} end {
|
||||
"%"[01]{2} eol {
|
||||
if (reg != REG_MX) return -1;
|
||||
if (cp[1] == '1') addr |= 0x20;
|
||||
if (cp[2] == '1') addr |= 0x10;
|
||||
|
@ -483,8 +541,8 @@ static word32 do_mem_assign(word32 addr, const char *cp) {
|
|||
for(;;) {
|
||||
const char *start = YYCURSOR;
|
||||
/*!re2c
|
||||
end { return addr; }
|
||||
" " { continue; }
|
||||
eol { return addr; }
|
||||
ws { continue; }
|
||||
* {
|
||||
fputs("Invalid data\n", stderr);
|
||||
return addr;
|
||||
|
@ -672,68 +730,78 @@ static int parse_command(const char *cp) {
|
|||
|
||||
/*!re2c
|
||||
|
||||
_ = (" " | "\x00");
|
||||
_ = (ws | eol);
|
||||
|
||||
* { --YYCURSOR; if (cp == YYCURSOR) goto command; return -1; }
|
||||
|
||||
"a=" { return do_assign(YYCURSOR, REG_A); }
|
||||
"x=" { return do_assign(YYCURSOR, REG_X); }
|
||||
"y=" { return do_assign(YYCURSOR, REG_Y); }
|
||||
"d=" { return do_assign(YYCURSOR, REG_D); }
|
||||
"e=" { return do_assign(YYCURSOR, REG_E); }
|
||||
"s=" { return do_assign(YYCURSOR, REG_S); }
|
||||
"k=" { return do_assign(YYCURSOR, REG_K); }
|
||||
"b=" { return do_assign(YYCURSOR, REG_B); }
|
||||
"p=" { return do_assign(YYCURSOR, REG_P); }
|
||||
"pc=" { return do_assign(YYCURSOR, REG_PC); }
|
||||
"mx=" { return do_assign(YYCURSOR, REG_MX); }
|
||||
"bp" eol { show_bp('B'); return 0; }
|
||||
"mp" eol { show_bp('M'); return 0; }
|
||||
|
||||
"bp" end { show_bp('B'); return 0; }
|
||||
"mp" end { show_bp('M'); return 0; }
|
||||
"*" eol { show_regs(); return 0; }
|
||||
|
||||
"*" end { show_regs(); return 0; }
|
||||
("q" | "quit" | "exit" | "bye") eol { return 'q'; }
|
||||
"reset" eol { do_reset(); return 0; }
|
||||
("help" | "?") eol { do_help(); return 0; }
|
||||
|
||||
("q" | "quit" | "exit") end { return 'q'; }
|
||||
"reset" end { do_reset(); return 0; }
|
||||
("help" | "?") end { do_help(); return 0; }
|
||||
// register stuff
|
||||
|
||||
"pc" {
|
||||
"%pc++" eol {
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
|
||||
"%a=" { return do_assign(YYCURSOR, REG_A); }
|
||||
"%x=" { return do_assign(YYCURSOR, REG_X); }
|
||||
"%y=" { return do_assign(YYCURSOR, REG_Y); }
|
||||
"%d=" { return do_assign(YYCURSOR, REG_D); }
|
||||
"%e=" { return do_assign(YYCURSOR, REG_E); }
|
||||
"5s=" { return do_assign(YYCURSOR, REG_S); }
|
||||
"%k=" { return do_assign(YYCURSOR, REG_K); }
|
||||
"%b=" { return do_assign(YYCURSOR, REG_B); }
|
||||
"%p=" { return do_assign(YYCURSOR, REG_P); }
|
||||
"%pc=" { return do_assign(YYCURSOR, REG_PC); }
|
||||
"%mx=" { return do_assign(YYCURSOR, REG_MX); }
|
||||
|
||||
|
||||
"%pc" {
|
||||
addr = engine.kpc;
|
||||
has_addr = 1;
|
||||
has_bank = 1;
|
||||
goto indir;
|
||||
}
|
||||
"a" {
|
||||
"%a" {
|
||||
addr = engine.acc;
|
||||
has_addr = 1;
|
||||
has_bank = 0;
|
||||
goto indir;
|
||||
}
|
||||
"x" {
|
||||
"%x" {
|
||||
addr = engine.xreg;
|
||||
has_addr = 1;
|
||||
has_bank = 0;
|
||||
goto indir;
|
||||
}
|
||||
"y" {
|
||||
"%y" {
|
||||
addr = engine.yreg;
|
||||
has_addr = 1;
|
||||
has_bank = 0;
|
||||
goto indir;
|
||||
}
|
||||
"s" {
|
||||
"%s" {
|
||||
addr = engine.stack;
|
||||
has_addr = 1;
|
||||
has_bank = 1;
|
||||
goto indir;
|
||||
}
|
||||
"d" {
|
||||
"%d" {
|
||||
addr = engine.dbank;
|
||||
has_addr = 1;
|
||||
has_bank = 1;
|
||||
goto indir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
x{6} {
|
||||
addr = to_hex(cp, cp + 6);
|
||||
has_bank = 1;
|
||||
|
@ -780,48 +848,33 @@ indir:
|
|||
}
|
||||
|
||||
command:
|
||||
if (!has_bank) {
|
||||
addr |= (g_prev_address & 0xff0000);
|
||||
}
|
||||
if (!has_addr) {
|
||||
addr = g_prev_address;
|
||||
}
|
||||
|
||||
cp = YYCURSOR;
|
||||
/*!re2c
|
||||
* { return -1; }
|
||||
|
||||
":" {
|
||||
if (!has_addr) {
|
||||
addr = g_prev_address;
|
||||
has_bank = 1;
|
||||
}
|
||||
if (!has_bank) addr |= (g_prev_address & 0xff0000);
|
||||
g_prev_address = do_mem_assign(addr, YYCURSOR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(";l" | "l") end {
|
||||
(";l" | "l") eol {
|
||||
int psr = engine.psr;
|
||||
if (!has_addr) {
|
||||
addr = g_prev_address;
|
||||
if (!addr) {
|
||||
addr = engine.kpc;
|
||||
has_bank = 1;
|
||||
}
|
||||
}
|
||||
if (!has_bank) {
|
||||
addr |= (engine.kpc & 0xff0000);
|
||||
}
|
||||
g_prev_address = do_list(addr, &psr, 20);
|
||||
return 0;
|
||||
}
|
||||
";h" end {
|
||||
if (!has_addr) {
|
||||
addr = g_prev_address;
|
||||
has_bank = 1;
|
||||
}
|
||||
if (!has_bank) {
|
||||
addr |= (engine.dbank << 16);
|
||||
}
|
||||
";h" eol {
|
||||
g_prev_address = do_hexdump(addr, 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
";s" end {
|
||||
";s" eol {
|
||||
/* print the stack */
|
||||
word32 bank;
|
||||
if (!has_addr) {
|
||||
|
@ -836,44 +889,47 @@ command:
|
|||
return 0;
|
||||
}
|
||||
|
||||
"g" end {
|
||||
"g" eol {
|
||||
/* GO! */
|
||||
if (has_addr) {
|
||||
if (!has_bank) addr |= (engine.kpc & 0xff0000);
|
||||
engine.kpc = addr;
|
||||
}
|
||||
g_stepping = 0;
|
||||
return 1;
|
||||
}
|
||||
"s" end {
|
||||
"s" eol {
|
||||
/* step */
|
||||
if (has_addr) {
|
||||
if (!has_bank) addr |= (engine.kpc & 0xff0000);
|
||||
engine.kpc = addr;
|
||||
}
|
||||
g_stepping = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
";bp" [+-]? end {
|
||||
";bp" [+-]? eol {
|
||||
char plus = cp[3];
|
||||
if (!has_addr && plus == 0) { show_bp('B'); return 0; }
|
||||
if (!has_addr) return -1;
|
||||
if (!has_bank) addr |= (engine.kpc & 0xff0000);
|
||||
if (plus == '-') delete_bp('B', addr);
|
||||
else set_bp('B', addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
";mp" [+-]? end {
|
||||
";mp" [+-]? eol {
|
||||
char plus = cp[3];
|
||||
if (!has_addr && plus == 0) { show_bp('M'); return 0; }
|
||||
if (!has_addr) return -1;
|
||||
if (!has_bank) addr |= (engine.kpc & 0xff0000);
|
||||
if (plus == '-') delete_bp('M', addr);
|
||||
else set_bp('M', addr);
|
||||
return 0;
|
||||
}
|
||||
"\\temp" / (ws|eol) {
|
||||
/* apply a gsbug template to memory */
|
||||
/* address\temp name */
|
||||
while (isspace(*YYCURSOR)) ++YYCURSOR;
|
||||
g_prev_address = debug_apply_template(addr, YYCURSOR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
@ -892,6 +948,15 @@ int debug_shell(int code) {
|
|||
|
||||
int psr = engine.psr;
|
||||
|
||||
if (!g_templates_loaded) {
|
||||
char *path;
|
||||
g_templates_loaded = 1;
|
||||
|
||||
path = get_resource_path("GSBug.Templates");
|
||||
debug_load_template(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
|
||||
/* todo -- only clear IF exit pc == entry pc ? */
|
||||
if (code == RET_BP) {
|
||||
|
@ -932,6 +997,7 @@ int debug_shell(int code) {
|
|||
}
|
||||
|
||||
static void do_sig_intr(int sig) {
|
||||
/* todo -- raise() if halt already pending */
|
||||
set_halt(4);
|
||||
}
|
||||
|
||||
|
|
312
src/debug_template.re2c
Normal file
312
src/debug_template.re2c
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
*
|
||||
* Load and parse GSBug templates and Nifty List Data.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "defc.h"
|
||||
|
||||
/*!re2c
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:define:YYCURSOR = cp;
|
||||
re2c:yyfill:enable = 0;
|
||||
eol = "\x00";
|
||||
ws = [ \t\r\n];
|
||||
*/
|
||||
|
||||
|
||||
/* format
|
||||
_START name
|
||||
name [type [size]] *
|
||||
_END
|
||||
*/
|
||||
|
||||
|
||||
struct field {
|
||||
char *name;
|
||||
int type;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct record {
|
||||
char *name;
|
||||
int total_size; /* total size */
|
||||
int field_count; /* # of fields */
|
||||
int field_alloc;
|
||||
struct field *fields;
|
||||
};
|
||||
|
||||
static struct record *records = NULL;
|
||||
static int record_count = 0;
|
||||
static int record_alloc = 0;
|
||||
|
||||
static int record_compare(const void *a, const void *b) {
|
||||
const struct record *aa = (const struct record *)a;
|
||||
const struct record *bb = (const struct record *)b;
|
||||
int rv;
|
||||
rv = strcasecmp(aa->name, bb->name);
|
||||
//if (rv == 0) return aa->total_size - bb->total_size;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* 192 records in the standard file... */
|
||||
static void add_record(struct record *r) {
|
||||
if (record_count == record_alloc) {
|
||||
size_t size = (record_alloc + 256) * sizeof(struct record);
|
||||
void *tmp = realloc(records, size);
|
||||
if (!tmp) return; /* oops */
|
||||
records = tmp;
|
||||
record_alloc += 256;
|
||||
}
|
||||
records[record_count++] = *r;
|
||||
}
|
||||
|
||||
static void free_record(struct record *r) {
|
||||
int i;
|
||||
for (i = 0; i < r->field_count; ++i) {
|
||||
free(r->fields[i].name);
|
||||
}
|
||||
free(r->name);
|
||||
free(r->fields);
|
||||
}
|
||||
|
||||
/* average ~14 fields per record */
|
||||
static void add_field(struct record *r, struct field *f) {
|
||||
if (r->field_count == r->field_alloc) {
|
||||
size_t size = (r->field_alloc + 32) * sizeof(struct field);
|
||||
void *tmp = realloc(r->fields, size);
|
||||
if (!tmp) return; /* oops */
|
||||
r->fields = tmp;
|
||||
r->field_alloc += 32;
|
||||
}
|
||||
r->fields[r->field_count++] = *f;
|
||||
r->total_size += f->type * f->count;
|
||||
}
|
||||
|
||||
|
||||
/* 0 - no field, 1 - ok, -1 - warning */
|
||||
static int parse_field(const char *cp, struct field *f) {
|
||||
const char *start;
|
||||
const char *end;
|
||||
const char *YYMARKER = NULL;
|
||||
|
||||
int type = 0;
|
||||
int count = 0;
|
||||
|
||||
start = cp;
|
||||
for(;;) {
|
||||
/*!re2c
|
||||
eol | ws { --cp; break; }
|
||||
* { continue; }
|
||||
*/
|
||||
}
|
||||
end = cp;
|
||||
if (start == end) return 0;
|
||||
|
||||
f->name = strndup(start, end - start);
|
||||
f->type = 0;
|
||||
f->count = 0;
|
||||
|
||||
while (isspace(*cp)) ++cp;
|
||||
|
||||
/* optional type */
|
||||
/*!re2c
|
||||
"BYTE" / (ws | eol) { type = 1; goto next; }
|
||||
"WORD" / (ws | eol) { type = 2; goto next; }
|
||||
"LONG" / (ws | eol) { type = 4; goto next; }
|
||||
"" { type = 0; goto next; }
|
||||
*/
|
||||
|
||||
next:
|
||||
while (isspace(*cp)) ++cp;
|
||||
if (type) {
|
||||
count = 0;
|
||||
while(isdigit(*cp)) {
|
||||
count = count * 10 + *cp - '0';
|
||||
++cp;
|
||||
}
|
||||
if (!count) count = 1;
|
||||
}
|
||||
while (isspace(*cp)) ++cp;
|
||||
if (*cp != 0) {
|
||||
return -1;
|
||||
}
|
||||
f->type = type;
|
||||
f->count = count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void debug_load_template(const char *path) {
|
||||
FILE *f;
|
||||
char buffer[1024];
|
||||
int ok;
|
||||
int in_struct = 0;
|
||||
struct record record;
|
||||
struct field field;
|
||||
unsigned line = 0;
|
||||
const char *YYMARKER = NULL;
|
||||
|
||||
|
||||
f = fopen(path, "r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Unable to load %s: %s\n", path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
for (line = 1;;++line) {
|
||||
const char *start = NULL;
|
||||
const char *end = NULL;
|
||||
|
||||
const char *cp = fgets(buffer, sizeof(buffer), f);
|
||||
if (!cp) break;
|
||||
|
||||
|
||||
/*!re2c
|
||||
"" { goto _field; }
|
||||
";" { continue; }
|
||||
ws* eol { continue; }
|
||||
"_END" / (ws | eol) { goto _end; }
|
||||
"_START" / (ws | eol) { goto _start; }
|
||||
*/
|
||||
|
||||
_field:
|
||||
if (!in_struct) {
|
||||
/* warn and create fake struct */
|
||||
fprintf(stderr, "%s:%d: Missing _START.\n", path, line);
|
||||
memset(&record, 0, sizeof(record));
|
||||
in_struct = -1;
|
||||
}
|
||||
|
||||
memset(&field, 0, sizeof(field));
|
||||
ok = parse_field(cp, &field);
|
||||
if (ok == 0) continue;
|
||||
if (ok < 1) {
|
||||
/* warn but add */
|
||||
fprintf(stderr, "%s:%d: Bad field line: %s\n", path, line, buffer);
|
||||
}
|
||||
add_field(&record, &field);
|
||||
continue;
|
||||
|
||||
_start:
|
||||
if (in_struct) {
|
||||
/* warn and close it */
|
||||
if (in_struct > 0) add_record(&record);
|
||||
if (in_struct < 0) free_record(&record);
|
||||
}
|
||||
memset(&record, 0, sizeof(record));
|
||||
|
||||
while (isspace(*cp)) ++cp;
|
||||
start = cp;
|
||||
for(;;) {
|
||||
/*!re2c
|
||||
eol | ws { --cp; break; }
|
||||
* { continue; }
|
||||
*/
|
||||
}
|
||||
end = cp;
|
||||
if (start == end) {
|
||||
/* warning ... */
|
||||
fprintf(stderr, "%s:%d: _START missing name.\n", path, line);
|
||||
in_struct = -1;
|
||||
} else {
|
||||
in_struct = 1;
|
||||
record.name = strndup(start, end - start);
|
||||
}
|
||||
|
||||
while (isspace(*cp)) ++cp;
|
||||
if (*cp != 0) {
|
||||
/* warning */
|
||||
fprintf(stderr, "%s:%d: Bad _START line: %s\n", path, line, buffer);
|
||||
}
|
||||
continue;
|
||||
|
||||
_end:
|
||||
while (isspace(*cp)) ++cp;
|
||||
if (*cp != 0) {
|
||||
/* warning ... */
|
||||
fprintf(stderr, "%s:%d: Bad _END line: %s\n", path, line, buffer);
|
||||
}
|
||||
|
||||
if (in_struct) {
|
||||
if (in_struct > 0) add_record(&record);
|
||||
if (in_struct < 0) free_record(&record);
|
||||
} else {
|
||||
/* warning */
|
||||
fprintf(stderr, "%s:%d: _END without _START.\n", path, line);
|
||||
}
|
||||
in_struct = 0;
|
||||
memset(&record, 0, sizeof(record));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_struct) {
|
||||
/* warn & close */
|
||||
fprintf(stderr, "%s:%d: Missing _END.\n", path, line);
|
||||
if (in_struct > 0) add_record(&record);
|
||||
if (in_struct < 0) free_record(&record);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
qsort(records, record_count, sizeof(struct record), record_compare);
|
||||
}
|
||||
|
||||
static int record_search(const void *a, const void *b) {
|
||||
const struct record *r = b;
|
||||
return strcasecmp(a, r->name);
|
||||
}
|
||||
|
||||
word32 debug_apply_template(word32 address, const char *name) {
|
||||
/* 1 - lookup template */
|
||||
struct record *r;
|
||||
int i, j;
|
||||
|
||||
r = bsearch(name, records, record_count, sizeof(struct record), record_search);
|
||||
if (r == NULL) {
|
||||
fprintf(stderr, "Invalid template: %s\n", name);
|
||||
return address;
|
||||
}
|
||||
if (r->total_size == 0) {
|
||||
/* just print the fields */
|
||||
for (i = 0; i < r->field_count; ++i) {
|
||||
fputs(r->fields[i].name, stdout);
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
return address;
|
||||
}
|
||||
|
||||
for (i = 0; i < r->field_count; ++i) {
|
||||
struct field *f = &r->fields[i];
|
||||
word32 value;
|
||||
unsigned type = f->type;
|
||||
printf("%-16s", f->name);
|
||||
for (j = 0; j < f->count; ++j) {
|
||||
switch(type) {
|
||||
case 1:
|
||||
value = get_memory_c(address, 0);
|
||||
address += 1;
|
||||
printf("%02x ", value);
|
||||
break;
|
||||
case 2:
|
||||
value = get_memory16_c(address, 0);
|
||||
address += 2;
|
||||
printf("%04x ", value);
|
||||
break;
|
||||
case 4:
|
||||
value = get_memory16_c(address, 0);
|
||||
address += 4;
|
||||
printf("%08x ", value);
|
||||
break;
|
||||
}
|
||||
address &= 0xffffff;
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
return address;
|
||||
}
|
Loading…
Reference in New Issue
Block a user