diff --git a/main.c b/main.c index d113229..22b1b71 100644 --- a/main.c +++ b/main.c @@ -676,12 +676,6 @@ static int cmd_prog(char **arg) return result; } -static int cmd_nosyms(char **arg) -{ - stab_clear(); - return 0; -} - static int cmd_eval(char **arg) { int addr; @@ -704,29 +698,147 @@ static int cmd_eval(char **arg) return 0; } -static int cmd_syms(char **arg) +static int cmd_sym_load_add(int clear, char **arg) { FILE *in = fopen(*arg, "r"); int result = 0; if (!in) { - fprintf(stderr, "syms: %s: %s\n", *arg, strerror(errno)); + fprintf(stderr, "sym: %s: %s\n", *arg, strerror(errno)); return -1; } - stab_clear(); + if (clear) + stab_clear(); if (elf32_check(in)) result = elf32_syms(in); else if (symmap_check(in)) result = symmap_syms(in); else - fprintf(stderr, "syms: %s: unknown file type\n", *arg); + fprintf(stderr, "sym: %s: unknown file type\n", *arg); fclose(in); return result; } +static FILE *savemap_out; + +static int savemap_write(const char *name, u_int16_t value) +{ + if (fprintf(savemap_out, "%08x t %s\n", value, name) < 0) { + fprintf(stderr, "sym: error writing symbols: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +static int cmd_sym_savemap(char **arg) +{ + char *fname = get_arg(arg); + + if (!fname) { + fprintf(stderr, "sym: filename required to save map\n"); + return -1; + } + + savemap_out = fopen(fname, "w"); + if (!savemap_out) { + fprintf(stderr, "sym: couldn't write to %s: %s\n", fname, + strerror(errno)); + return -1; + } + + if (stab_enum(savemap_write) < 0) + return -1; + + if (fclose(savemap_out) < 0) { + fprintf(stderr, "sym: error closing %s: %s\n", fname, + strerror(errno)); + return -1; + } + + return 0; +} + +static int printsym(const char *name, u_int16_t value) +{ + printf("0x%04x: %s\n", value, name); + return 0; +} + +static int cmd_sym(char **arg) +{ + char *subcmd = get_arg(arg); + + if (!subcmd) { + fprintf(stderr, "sym: need to specify a subcommand " + "(try \"help sym\")\n"); + return -1; + } + + if (!strcasecmp(subcmd, "clear")) { + stab_clear(); + return 0; + } + + if (!strcasecmp(subcmd, "set")) { + char *name = get_arg(arg); + char *val_text = get_arg(arg); + int value; + + if (!(name && val_text)) { + fprintf(stderr, "sym: need a name and value to set " + "symbol table entries\n"); + return -1; + } + + if (stab_parse(val_text, &value) < 0) { + fprintf(stderr, "sym: can't parse value: %s\n", + val_text); + return -1; + } + + return stab_set(name, value); + } + + if (!strcasecmp(subcmd, "del")) { + char *name = get_arg(arg); + + if (!name) { + fprintf(stderr, "sym: need a name to delete " + "symbol table entries\n"); + return -1; + } + + return stab_del(name); + } + + if (!strcasecmp(subcmd, "load")) + return cmd_sym_load_add(1, arg); + if (!strcasecmp(subcmd, "add")) + return cmd_sym_load_add(0, arg); + + if (!strcasecmp(subcmd, "savemap")) + return cmd_sym_savemap(arg); + + if (!strcasecmp(subcmd, "find")) { + char *expr = get_arg(arg); + + if (!expr) { + stab_enum(printsym); + return 0; + } + + return stab_re_search(expr, printsym) < 0 ? -1 : 0; + } + + fprintf(stderr, "sym: unknown subcommand: %s\n", subcmd); + return -1; +} + static int cmd_gdb(char **arg) { char *port_text = get_arg(arg); @@ -842,61 +954,70 @@ static int cmd_read(char **arg) static const struct command all_commands[] = { {"=", cmd_eval, -"= \n" -" Evaluate an expression using the symbol table.\n"}, + "= \n" + " Evaluate an expression using the symbol table.\n"}, {"dis", cmd_dis, -"dis
[length]\n" -" Disassemble a section of memory.\n"}, + "dis
[length]\n" + " Disassemble a section of memory.\n"}, {"erase", cmd_erase, -"erase\n" -" Erase the device under test.\n"}, + "erase\n" + " Erase the device under test.\n"}, {"gdb", cmd_gdb, -"gdb [port]\n" -" Run a GDB remote stub on the given TCP/IP port.\n"}, + "gdb [port]\n" + " Run a GDB remote stub on the given TCP/IP port.\n"}, {"help", cmd_help, -"help [command]\n" -" Without arguments, displays a list of commands. With a command name as\n" -" an argument, displays help for that command.\n"}, + "help [command]\n" + " Without arguments, displays a list of commands. With a command\n" + " name as an argument, displays help for that command.\n"}, {"hexout", cmd_hexout, -"hexout
\n" -" Save a region of memory into a HEX file.\n"}, + "hexout
\n" + " Save a region of memory into a HEX file.\n"}, {"md", cmd_md, -"md
[length]\n" -" Read the specified number of bytes from memory at the given address,\n" -" and display a hexdump.\n"}, + "md
[length]\n" + " Read the specified number of bytes from memory at the given\n" + " address, and display a hexdump.\n"}, {"mw", cmd_mw, -"mw
bytes ...\n" -" Write a sequence of bytes to a memory address. Byte values are\n" -" two-digit hexadecimal numbers.\n"}, - {"nosyms", cmd_nosyms, -"nosyms\n" -" Clear the symbol table.\n"}, + "mw
bytes ...\n" + " Write a sequence of bytes to a memory address. Byte values are\n" + " two-digit hexadecimal numbers.\n"}, {"prog", cmd_prog, -"prog \n" -" Erase the device and flash the data contained in a binary file. This\n" -" command also loads symbols from the file, if available.\n"}, + "prog \n" + " Erase the device and flash the data contained in a binary file.\n" + " This command also loads symbols from the file, if available.\n"}, {"read", cmd_read, -"read \n" -" Read commands from a file and evaluate them.\n"}, + "read \n" + " Read commands from a file and evaluate them.\n"}, {"regs", cmd_regs, -"regs\n" -" Read and display the current register contents.\n"}, + "regs\n" + " Read and display the current register contents.\n"}, {"reset", cmd_reset, -"reset\n" -" Reset (and halt) the CPU.\n"}, + "reset\n" + " Reset (and halt) the CPU.\n"}, {"run", cmd_run, -"run [breakpoint]\n" -" Run the CPU until either a specified breakpoint occurs or the command\n" -" is interrupted.\n"}, + "run [breakpoint]\n" + " Run the CPU until either a specified breakpoint occurs or the\n" + " command is interrupted.\n"}, {"set", cmd_set, -"set \n" -" Change the value of a CPU register.\n"}, + "set \n" + " Change the value of a CPU register.\n"}, {"step", cmd_step, -"step [count]\n" -" Single-step the CPU, and display the register state.\n"}, - {"syms", cmd_syms, -"syms \n" -" Load symbols from the given file.\n"}, + "step [count]\n" + " Single-step the CPU, and display the register state.\n"}, + {"sym", cmd_sym, + "sym clear\n" + " Clear the symbol table.\n" + "sym set \n" + " Set or overwrite the value of a symbol.\n" + "sym del \n" + " Delete a symbol from the symbol table.\n" + "sym load \n" + " Load symbols from the given file.\n" + "sym add \n" + " Load additional symbols from the given file.\n" + "sym savemap \n" + " Save the current symbols to a BSD-style symbol file.\n" + "sym find \n" + " Search for symbols by regular expression.\n"}, {NULL, NULL, NULL} }; diff --git a/mspdebug.man b/mspdebug.man index ca68d30..b5f9b47 100644 --- a/mspdebug.man +++ b/mspdebug.man @@ -135,9 +135,6 @@ numbers separated by spaces. Unless used in the simulation mode, this command can only be used for programming flash memory. -.IP "nosyms" -Clear all symbols from the symbol table. Symbols may be reloaded with -the \fBsyms\fR command. .IP "prog \fIfilename\fR" Erase and reprogram the device under test using the binary file supplied. The file format will be auto-detected and may be either @@ -181,13 +178,32 @@ instructions at the address selected by the program counter. An optional count can be specified to step multiple times. If no argument is given, the CPU steps once. -.IP "syms \fIfilename\fR" +.IP "sym clear" +Clear the symbol table, deleting all symbols. +.IP "sym set \fIname\fR \fIvalue\fR" +Set or alter the value of a symbol. The value given may be an address +expression. +.IP "sym del \fIname\fR" +Delete the given symbol from the symbol table. +.IP "sym load \fIfilename\fR" Load symbols from the specified file and add them to the symbol table. The file format will be auto-detected and may be either ELF32 or a BSD-style symbol listing (like the output from \fBnm\fR(1)). Symbols can be combined from many sources, as the syms command adds to the existing symbol table without discarding existing symbols. +.IP "sym add \fIfilename\fR" +This command is similar to \fBsym load\fR, except that the symbol table +is not cleared first. By using this command, symbols from multiple +sources can be combined. +.IP "sym savemap \fIfilename\fR" +Save all symbols currently defined to the given file. The symbols are +saved as a BSD-style symbol table. Note that symbol types are not stored +by MSPDebug, and all symbols are saved as type \fBt\fR. +.IP "sym find [\fIregex\fR]" +Search for symbols. If a regular expression is given, then all symbols +matching the expression are printed. If no expression is specified, then +the entire symbol table is listed. .SH ADDRESS EXPRESSIONS Any command which accepts a memory address, length or register value as an argument may be given an address expression. An address diff --git a/stab.c b/stab.c index 3124a7c..6601ffa 100644 --- a/stab.c +++ b/stab.c @@ -99,7 +99,6 @@ static const struct btree_def addr_table_def = { static btree_t sym_table; static btree_t addr_table; -static int is_modified; /************************************************************************ * Public interface @@ -133,17 +132,6 @@ void stab_clear(void) { btree_clear(sym_table); btree_clear(addr_table); - is_modified = 0; -} - -int stab_is_modified(void) -{ - return is_modified; -} - -void stab_clear_modified(void) -{ - is_modified = 0; } int stab_set(const char *name, u_int16_t addr) diff --git a/stab.h b/stab.h index 49e7066..e885a11 100644 --- a/stab.h +++ b/stab.h @@ -30,12 +30,6 @@ void stab_exit(void); /* Reset the symbol table (delete all symbols) */ void stab_clear(void); -/* Check to see if the symbol table has been modified, and clear - * modification flag. - */ -int stab_is_modified(void); -void stab_clear_modified(void); - /* Set a symbol in the table. Returns 0 on success, or -1 on error. */ int stab_set(const char *name, u_int16_t value);