Separated command database.
This commit is contained in:
parent
e834241e90
commit
6dd1ab25c3
3
Makefile
3
Makefile
|
@ -56,7 +56,8 @@ install: mspdebug mspdebug.man
|
||||||
mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
|
mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
|
||||||
util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \
|
util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \
|
||||||
cproc.o vector.o output_util.o expr.o fet_error.o binfile.o \
|
cproc.o vector.o output_util.o expr.o fet_error.o binfile.o \
|
||||||
fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o
|
fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \
|
||||||
|
cmddb.o
|
||||||
$(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
$(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||||
|
* Copyright (C) 2009, 2010 Daniel Beer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cmddb.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "devcmd.h"
|
||||||
|
#include "gdb.h"
|
||||||
|
#include "rtools.h"
|
||||||
|
#include "cproc.h"
|
||||||
|
#include "sym.h"
|
||||||
|
|
||||||
|
const struct cmddb_record commands[] = {
|
||||||
|
{
|
||||||
|
.name = "help",
|
||||||
|
.func = cmd_help,
|
||||||
|
.help =
|
||||||
|
"help [command]\n"
|
||||||
|
" Without arguments, displays a list of commands. With a command\n"
|
||||||
|
" name as an argument, displays help for that command.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "opt",
|
||||||
|
.func = cmd_opt,
|
||||||
|
.help =
|
||||||
|
"opt [name] [value]\n"
|
||||||
|
" Query or set option variables. With no arguments, displays all\n"
|
||||||
|
" available options.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "read",
|
||||||
|
.func = cmd_read,
|
||||||
|
.help =
|
||||||
|
"read <filename>\n"
|
||||||
|
" Read commands from a file and evaluate them.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "setbreak",
|
||||||
|
.func = cmd_setbreak,
|
||||||
|
.help =
|
||||||
|
"setbreak <addr> [index]\n"
|
||||||
|
" Set a breakpoint. If no index is specified, the first available\n"
|
||||||
|
" slot will be used.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "delbreak",
|
||||||
|
.func = cmd_delbreak,
|
||||||
|
.help =
|
||||||
|
"delbreak [index]\n"
|
||||||
|
" Delete a breakpoint. If no index is specified, then all active\n"
|
||||||
|
" breakpoints are cleared.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "break",
|
||||||
|
.func = cmd_break,
|
||||||
|
.help =
|
||||||
|
"break\n"
|
||||||
|
" List active breakpoints.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "regs",
|
||||||
|
.func = cmd_regs,
|
||||||
|
.help =
|
||||||
|
"regs\n"
|
||||||
|
" Read and display the current register contents.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "prog",
|
||||||
|
.func = cmd_prog,
|
||||||
|
.help =
|
||||||
|
"prog <filename>\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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "md",
|
||||||
|
.func = cmd_md,
|
||||||
|
.help =
|
||||||
|
"md <address> [length]\n"
|
||||||
|
" Read the specified number of bytes from memory at the given\n"
|
||||||
|
" address, and display a hexdump.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mw",
|
||||||
|
.func = cmd_mw,
|
||||||
|
.help =
|
||||||
|
"mw <address> bytes ...\n"
|
||||||
|
" Write a sequence of bytes to a memory address. Byte values are\n"
|
||||||
|
" two-digit hexadecimal numbers.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "reset",
|
||||||
|
.func = cmd_reset,
|
||||||
|
.help =
|
||||||
|
"reset\n"
|
||||||
|
" Reset (and halt) the CPU.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "erase",
|
||||||
|
.func = cmd_erase,
|
||||||
|
.help =
|
||||||
|
"erase\n"
|
||||||
|
" Erase the device under test.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "step",
|
||||||
|
.func = cmd_step,
|
||||||
|
.help =
|
||||||
|
"step [count]\n"
|
||||||
|
" Single-step the CPU, and display the register state.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "run",
|
||||||
|
.func = cmd_run,
|
||||||
|
.help =
|
||||||
|
"run\n"
|
||||||
|
" Run the CPU to until a breakpoint is reached or the command is\n"
|
||||||
|
" interrupted.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "set",
|
||||||
|
.func = cmd_set,
|
||||||
|
.help =
|
||||||
|
"set <register> <value>\n"
|
||||||
|
" Change the value of a CPU register.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dis",
|
||||||
|
.func = cmd_dis,
|
||||||
|
.help =
|
||||||
|
"dis <address> [length]\n"
|
||||||
|
" Disassemble a section of memory.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "hexout",
|
||||||
|
.func = cmd_hexout,
|
||||||
|
.help =
|
||||||
|
"hexout <address> <length> <filename.hex>\n"
|
||||||
|
" Save a region of memory into a HEX file.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gdb",
|
||||||
|
.func = cmd_gdb,
|
||||||
|
.help =
|
||||||
|
"gdb [port]\n"
|
||||||
|
" Run a GDB remote stub on the given TCP/IP port.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "=",
|
||||||
|
.func = cmd_eval,
|
||||||
|
.help =
|
||||||
|
"= <expression>\n"
|
||||||
|
" Evaluate an expression using the symbol table.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "sym",
|
||||||
|
.func = cmd_sym,
|
||||||
|
.help =
|
||||||
|
"sym clear\n"
|
||||||
|
" Clear the symbol table.\n"
|
||||||
|
"sym set <name> <value>\n"
|
||||||
|
" Set or overwrite the value of a symbol.\n"
|
||||||
|
"sym del <name>\n"
|
||||||
|
" Delete a symbol from the symbol table.\n"
|
||||||
|
"sym import <filename>\n"
|
||||||
|
" Load symbols from the given file.\n"
|
||||||
|
"sym import+ <filename>\n"
|
||||||
|
" Load additional symbols from the given file.\n"
|
||||||
|
"sym export <filename>\n"
|
||||||
|
" Save the current symbols to a BSD-style symbol file.\n"
|
||||||
|
"sym find <regex>\n"
|
||||||
|
" Search for symbols by regular expression.\n"
|
||||||
|
"sym rename <regex> <string>\n"
|
||||||
|
" Replace every occurance of a pattern in symbol names.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "isearch",
|
||||||
|
.func = cmd_isearch,
|
||||||
|
.help =
|
||||||
|
"isearch <address> <length> [options ...]\n"
|
||||||
|
" Search for an instruction matching certain search terms. These\n"
|
||||||
|
" terms may be any of the following:\n"
|
||||||
|
" opcode <opcode>\n"
|
||||||
|
" byte|word|aword\n"
|
||||||
|
" jump|single|double|noarg\n"
|
||||||
|
" src <value>\n"
|
||||||
|
" dst <value>\n"
|
||||||
|
" srcreg <register>\n"
|
||||||
|
" dstreg <register>\n"
|
||||||
|
" srcmode R|I|S|&|@|+|#\n"
|
||||||
|
" dstmode R|I|S|&|@|+|#\n"
|
||||||
|
" For single-operand instructions, the operand is considered the\n"
|
||||||
|
" destination operand.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "cgraph",
|
||||||
|
.func = cmd_cgraph,
|
||||||
|
.help =
|
||||||
|
"cgraph <address> <length> [function]\n"
|
||||||
|
" Analyse the range given and produce a call graph. Displays a summary\n"
|
||||||
|
" of all functions if no function address is given.\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int cmddb_get(const char *name, struct cmddb_record *ret)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN(commands); i++) {
|
||||||
|
const struct cmddb_record *r = &commands[i];
|
||||||
|
|
||||||
|
if (!strcasecmp(r->name, name)) {
|
||||||
|
memcpy(ret, r, sizeof(*ret));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmddb_enum(cmddb_enum_func_t func, void *user_data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN(commands); i++)
|
||||||
|
if (func(user_data, &commands[i]) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||||
|
* Copyright (C) 2009, 2010 Daniel Beer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CMDDB_H_
|
||||||
|
#define CMDDB_H_
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
|
typedef int (*cproc_command_func_t)(cproc_t cp, char **arg);
|
||||||
|
|
||||||
|
struct cmddb_record {
|
||||||
|
const char *name;
|
||||||
|
cproc_command_func_t func;
|
||||||
|
const char *help;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fetch a command record */
|
||||||
|
int cmddb_get(const char *name, struct cmddb_record *r);
|
||||||
|
|
||||||
|
/* Enumerate all command records.
|
||||||
|
*
|
||||||
|
* Returns 0, or -1 if an error occurs during enumeration.
|
||||||
|
*/
|
||||||
|
typedef int (*cmddb_enum_func_t)(void *user_data,
|
||||||
|
const struct cmddb_record *r);
|
||||||
|
|
||||||
|
int cmddb_enum(cmddb_enum_func_t func, void *user_data);
|
||||||
|
|
||||||
|
#endif
|
125
cproc.c
125
cproc.c
|
@ -35,56 +35,26 @@
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
#include "cmddb.h"
|
||||||
|
|
||||||
struct cproc {
|
struct cproc {
|
||||||
struct vector command_list;
|
|
||||||
int lists_modified;
|
|
||||||
|
|
||||||
int modify_flags;
|
int modify_flags;
|
||||||
int in_reader_loop;
|
int in_reader_loop;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cproc_command *find_command(cproc_t cp, const char *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < cp->command_list.size; i++) {
|
|
||||||
struct cproc_command *cmd =
|
|
||||||
VECTOR_PTR(cp->command_list, i, struct cproc_command);
|
|
||||||
|
|
||||||
if (!strcasecmp(cmd->name, name))
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int namelist_cmp(const void *a, const void *b)
|
static int namelist_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return strcasecmp(*(const char **)a, *(const char **)b);
|
return strcasecmp(*(const char **)a, *(const char **)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Both sort_lists and namelist_print assume that the first item in each
|
|
||||||
* vector element is a const char *
|
|
||||||
*/
|
|
||||||
static void sort_lists(cproc_t cp)
|
|
||||||
{
|
|
||||||
if (!cp->lists_modified)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (cp->command_list.ptr)
|
|
||||||
qsort(cp->command_list.ptr, cp->command_list.size,
|
|
||||||
cp->command_list.elemsize, namelist_cmp);
|
|
||||||
|
|
||||||
cp->lists_modified = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void namelist_print(struct vector *v)
|
static void namelist_print(struct vector *v)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int max_len = 0;
|
int max_len = 0;
|
||||||
int rows, cols;
|
int rows, cols;
|
||||||
|
|
||||||
|
qsort(v->ptr, v->size, v->elemsize, namelist_cmp);
|
||||||
|
|
||||||
for (i = 0; i < v->size; i++) {
|
for (i = 0; i < v->size; i++) {
|
||||||
const char *text = VECTOR_AT(*v, i, const char *);
|
const char *text = VECTOR_AT(*v, i, const char *);
|
||||||
int len = strlen(text);
|
int len = strlen(text);
|
||||||
|
@ -137,22 +107,25 @@ static const char *type_text(opdb_type_t type)
|
||||||
static int push_option_name(void *user_data, const struct opdb_key *key,
|
static int push_option_name(void *user_data, const struct opdb_key *key,
|
||||||
const union opdb_value *value)
|
const union opdb_value *value)
|
||||||
{
|
{
|
||||||
struct vector *v = (struct vector *)user_data;
|
return vector_push((struct vector *)user_data, &key->name, 1);
|
||||||
|
|
||||||
return vector_push(v, &key->name, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_help(cproc_t cp, char **arg)
|
static int push_command_name(void *user_data, const struct cmddb_record *rec)
|
||||||
|
{
|
||||||
|
return vector_push((struct vector *)user_data, &rec->name, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_help(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
const char *topic = get_arg(arg);
|
const char *topic = get_arg(arg);
|
||||||
|
|
||||||
if (topic) {
|
if (topic) {
|
||||||
const struct cproc_command *cmd = find_command(cp, topic);
|
struct cmddb_record cmd;
|
||||||
struct opdb_key key;
|
struct opdb_key key;
|
||||||
|
|
||||||
if (cmd) {
|
if (!cmddb_get(topic, &cmd)) {
|
||||||
printc("\x1b[1mCOMMAND: %s\x1b[0m\n\n%s\n",
|
printc("\x1b[1mCOMMAND: %s\x1b[0m\n\n%s\n",
|
||||||
cmd->name, cmd->help);
|
cmd.name, cmd.help);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,18 +141,23 @@ static int cmd_help(cproc_t cp, char **arg)
|
||||||
struct vector v;
|
struct vector v;
|
||||||
|
|
||||||
vector_init(&v, sizeof(const char *));
|
vector_init(&v, sizeof(const char *));
|
||||||
sort_lists(cp);
|
|
||||||
|
|
||||||
printf("Available commands:\n");
|
if (!cmddb_enum(push_command_name, &v)) {
|
||||||
namelist_print(&cp->command_list);
|
printf("Available commands:\n");
|
||||||
printf("\n");
|
namelist_print(&v);
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
perror("help: can't allocate memory for command list");
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_realloc(&v, 0);
|
||||||
|
|
||||||
if (!opdb_enum(push_option_name, &v)) {
|
if (!opdb_enum(push_option_name, &v)) {
|
||||||
printf("Available options:\n");
|
printf("Available options:\n");
|
||||||
namelist_print(&v);
|
namelist_print(&v);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else {
|
} else {
|
||||||
perror("failed to allocate memory");
|
perror("help: can't allocate memory for option list");
|
||||||
}
|
}
|
||||||
|
|
||||||
vector_destroy(&v);
|
vector_destroy(&v);
|
||||||
|
@ -236,7 +214,7 @@ static int display_option(void *user_data, const struct opdb_key *key,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_opt(cproc_t cp, char **arg)
|
int cmd_opt(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
const char *opt_text = get_arg(arg);
|
const char *opt_text = get_arg(arg);
|
||||||
struct opdb_key key;
|
struct opdb_key key;
|
||||||
|
@ -267,7 +245,7 @@ static int cmd_opt(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_read(cproc_t cp, char **arg)
|
int cmd_read(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *filename = get_arg(arg);
|
char *filename = get_arg(arg);
|
||||||
|
|
||||||
|
@ -279,32 +257,6 @@ static int cmd_read(cproc_t cp, char **arg)
|
||||||
return cproc_process_file(cp, filename);
|
return cproc_process_file(cp, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cproc_command built_in_commands[] = {
|
|
||||||
{
|
|
||||||
.name = "help",
|
|
||||||
.func = cmd_help,
|
|
||||||
.help =
|
|
||||||
"help [command]\n"
|
|
||||||
" Without arguments, displays a list of commands. With a command\n"
|
|
||||||
" name as an argument, displays help for that command.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "opt",
|
|
||||||
.func = cmd_opt,
|
|
||||||
.help =
|
|
||||||
"opt [name] [value]\n"
|
|
||||||
" Query or set option variables. With no arguments, displays all\n"
|
|
||||||
" available options.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "read",
|
|
||||||
.func = cmd_read,
|
|
||||||
.help =
|
|
||||||
"read <filename>\n"
|
|
||||||
" Read commands from a file and evaluate them.\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cproc_t cproc_new(void)
|
cproc_t cproc_new(void)
|
||||||
{
|
{
|
||||||
cproc_t cp = malloc(sizeof(*cp));
|
cproc_t cp = malloc(sizeof(*cp));
|
||||||
|
@ -313,35 +265,14 @@ cproc_t cproc_new(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(cp, 0, sizeof(*cp));
|
memset(cp, 0, sizeof(*cp));
|
||||||
|
|
||||||
vector_init(&cp->command_list, sizeof(struct cproc_command));
|
|
||||||
|
|
||||||
if (vector_push(&cp->command_list, &built_in_commands,
|
|
||||||
ARRAY_LEN(built_in_commands)) < 0) {
|
|
||||||
vector_destroy(&cp->command_list);
|
|
||||||
free(cp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cproc_destroy(cproc_t cp)
|
void cproc_destroy(cproc_t cp)
|
||||||
{
|
{
|
||||||
vector_destroy(&cp->command_list);
|
|
||||||
free(cp);
|
free(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cproc_register_commands(cproc_t cp, const struct cproc_command *cmd,
|
|
||||||
int count)
|
|
||||||
{
|
|
||||||
if (vector_push(&cp->command_list, cmd, count) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
cp->lists_modified = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cproc_modify(cproc_t cp, int flags)
|
void cproc_modify(cproc_t cp, int flags)
|
||||||
{
|
{
|
||||||
cp->modify_flags |= flags;
|
cp->modify_flags |= flags;
|
||||||
|
@ -423,14 +354,14 @@ static int process_command(cproc_t cp, char *arg, int interactive)
|
||||||
|
|
||||||
cmd_text = get_arg(&arg);
|
cmd_text = get_arg(&arg);
|
||||||
if (cmd_text) {
|
if (cmd_text) {
|
||||||
const struct cproc_command *cmd = find_command(cp, cmd_text);
|
struct cmddb_record cmd;
|
||||||
|
|
||||||
if (cmd) {
|
if (!cmddb_get(cmd_text, &cmd)) {
|
||||||
int old = cp->in_reader_loop;
|
int old = cp->in_reader_loop;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
cp->in_reader_loop = interactive;
|
cp->in_reader_loop = interactive;
|
||||||
ret = cmd->func(cp, &arg);
|
ret = cmd.func(cp, &arg);
|
||||||
cp->in_reader_loop = old;
|
cp->in_reader_loop = old;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
26
cproc.h
26
cproc.h
|
@ -27,21 +27,6 @@
|
||||||
struct cproc;
|
struct cproc;
|
||||||
typedef struct cproc *cproc_t;
|
typedef struct cproc *cproc_t;
|
||||||
|
|
||||||
/* Command definitions.
|
|
||||||
*
|
|
||||||
* Each command is specified as a tuple of name, command function and help
|
|
||||||
* text. When the command is invoked, the command function is called with
|
|
||||||
* a mutable pointer to the command line text, and a pointer to the command
|
|
||||||
* processor.
|
|
||||||
*/
|
|
||||||
typedef int (*cproc_command_func_t)(cproc_t cp, char **arg);
|
|
||||||
|
|
||||||
struct cproc_command {
|
|
||||||
const char *name;
|
|
||||||
cproc_command_func_t func;
|
|
||||||
const char *help;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Commmand processor modification flags.
|
/* Commmand processor modification flags.
|
||||||
*
|
*
|
||||||
* Within the context of a command processor, various data items may be
|
* Within the context of a command processor, various data items may be
|
||||||
|
@ -65,12 +50,6 @@ struct cproc_command {
|
||||||
cproc_t cproc_new(void);
|
cproc_t cproc_new(void);
|
||||||
void cproc_destroy(cproc_t cp);
|
void cproc_destroy(cproc_t cp);
|
||||||
|
|
||||||
/* Register commands and options with the command processor. These functions
|
|
||||||
* return 0 on success or -1 if an error occurs (failure to allocate memory).
|
|
||||||
*/
|
|
||||||
int cproc_register_commands(cproc_t cp, const struct cproc_command *cmd,
|
|
||||||
int count);
|
|
||||||
|
|
||||||
/* This should be called before a destructive operation to give the user
|
/* This should be called before a destructive operation to give the user
|
||||||
* a chance to abort. If it returns 1, then the operation should be aborted.
|
* a chance to abort. If it returns 1, then the operation should be aborted.
|
||||||
*
|
*
|
||||||
|
@ -90,4 +69,9 @@ void cproc_reader_loop(cproc_t cp);
|
||||||
int cproc_process_command(cproc_t cp, char *cmd);
|
int cproc_process_command(cproc_t cp, char *cmd);
|
||||||
int cproc_process_file(cproc_t cp, const char *filename);
|
int cproc_process_file(cproc_t cp, const char *filename);
|
||||||
|
|
||||||
|
/* Built-in commands */
|
||||||
|
int cmd_help(cproc_t cp, char **arg);
|
||||||
|
int cmd_read(cproc_t cp, char **arg);
|
||||||
|
int cmd_opt(cproc_t cp, char **arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
140
devcmd.c
140
devcmd.c
|
@ -31,7 +31,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
|
|
||||||
static int cmd_regs(cproc_t cp, char **arg)
|
int cmd_regs(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
address_t regs[DEVICE_NUM_REGS];
|
address_t regs[DEVICE_NUM_REGS];
|
||||||
uint8_t code[16];
|
uint8_t code[16];
|
||||||
|
@ -51,7 +51,7 @@ static int cmd_regs(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_md(cproc_t cp, char **arg)
|
int cmd_md(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *off_text = get_arg(arg);
|
char *off_text = get_arg(arg);
|
||||||
char *len_text = get_arg(arg);
|
char *len_text = get_arg(arg);
|
||||||
|
@ -94,7 +94,7 @@ static int cmd_md(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_mw(cproc_t cp, char **arg)
|
int cmd_mw(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *off_text = get_arg(arg);
|
char *off_text = get_arg(arg);
|
||||||
char *byte_text;
|
char *byte_text;
|
||||||
|
@ -130,12 +130,12 @@ static int cmd_mw(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_reset(cproc_t cp, char **arg)
|
int cmd_reset(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
return device_default->ctl(device_default, DEVICE_CTL_RESET);
|
return device_default->ctl(device_default, DEVICE_CTL_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_erase(cproc_t cp, char **arg)
|
int cmd_erase(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
if (device_default->ctl(device_default, DEVICE_CTL_HALT) < 0)
|
if (device_default->ctl(device_default, DEVICE_CTL_HALT) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -144,7 +144,7 @@ static int cmd_erase(cproc_t cp, char **arg)
|
||||||
return device_default->ctl(device_default, DEVICE_CTL_ERASE);
|
return device_default->ctl(device_default, DEVICE_CTL_ERASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_step(cproc_t cp, char **arg)
|
int cmd_step(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *count_text = get_arg(arg);
|
char *count_text = get_arg(arg);
|
||||||
int count = 1;
|
int count = 1;
|
||||||
|
@ -161,7 +161,7 @@ static int cmd_step(cproc_t cp, char **arg)
|
||||||
return cmd_regs(cp, NULL);
|
return cmd_regs(cp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_run(cproc_t cp, char **arg)
|
int cmd_run(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
device_status_t status;
|
device_status_t status;
|
||||||
address_t regs[DEVICE_NUM_REGS];
|
address_t regs[DEVICE_NUM_REGS];
|
||||||
|
@ -210,7 +210,7 @@ static int cmd_run(cproc_t cp, char **arg)
|
||||||
return cmd_regs(cp, NULL);
|
return cmd_regs(cp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_set(cproc_t cp, char **arg)
|
int cmd_set(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *reg_text = get_arg(arg);
|
char *reg_text = get_arg(arg);
|
||||||
char *val_text = get_arg(arg);
|
char *val_text = get_arg(arg);
|
||||||
|
@ -244,7 +244,7 @@ static int cmd_set(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_dis(cproc_t cp, char **arg)
|
int cmd_dis(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *off_text = get_arg(arg);
|
char *off_text = get_arg(arg);
|
||||||
char *len_text = get_arg(arg);
|
char *len_text = get_arg(arg);
|
||||||
|
@ -393,7 +393,7 @@ static int hexout_feed(struct hexout_data *hexout,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_hexout(cproc_t cp, char **arg)
|
int cmd_hexout(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *off_text = get_arg(arg);
|
char *off_text = get_arg(arg);
|
||||||
char *len_text = get_arg(arg);
|
char *len_text = get_arg(arg);
|
||||||
|
@ -523,7 +523,7 @@ static int prog_feed(void *user_data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_prog(cproc_t cp, char **arg)
|
int cmd_prog(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
FILE *in;
|
FILE *in;
|
||||||
struct prog_data prog;
|
struct prog_data prog;
|
||||||
|
@ -568,7 +568,7 @@ static int cmd_prog(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_setbreak(cproc_t cp, char **arg)
|
int cmd_setbreak(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *addr_text = get_arg(arg);
|
char *addr_text = get_arg(arg);
|
||||||
char *index_text = get_arg(arg);
|
char *index_text = get_arg(arg);
|
||||||
|
@ -606,7 +606,7 @@ static int cmd_setbreak(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_delbreak(cproc_t cp, char **arg)
|
int cmd_delbreak(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *index_text = get_arg(arg);
|
char *index_text = get_arg(arg);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -633,7 +633,7 @@ static int cmd_delbreak(cproc_t cp, char **arg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_break(cproc_t cp, char **arg)
|
int cmd_break(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -660,115 +660,3 @@ static int cmd_break(cproc_t cp, char **arg)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cproc_command commands[] = {
|
|
||||||
{
|
|
||||||
.name = "setbreak",
|
|
||||||
.func = cmd_setbreak,
|
|
||||||
.help =
|
|
||||||
"setbreak <addr> [index]\n"
|
|
||||||
" Set a breakpoint. If no index is specified, the first available\n"
|
|
||||||
" slot will be used.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "delbreak",
|
|
||||||
.func = cmd_delbreak,
|
|
||||||
.help =
|
|
||||||
"delbreak [index]\n"
|
|
||||||
" Delete a breakpoint. If no index is specified, then all active\n"
|
|
||||||
" breakpoints are cleared.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "break",
|
|
||||||
.func = cmd_break,
|
|
||||||
.help =
|
|
||||||
"break\n"
|
|
||||||
" List active breakpoints.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "regs",
|
|
||||||
.func = cmd_regs,
|
|
||||||
.help =
|
|
||||||
"regs\n"
|
|
||||||
" Read and display the current register contents.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "prog",
|
|
||||||
.func = cmd_prog,
|
|
||||||
.help =
|
|
||||||
"prog <filename>\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"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "md",
|
|
||||||
.func = cmd_md,
|
|
||||||
.help =
|
|
||||||
"md <address> [length]\n"
|
|
||||||
" Read the specified number of bytes from memory at the given\n"
|
|
||||||
" address, and display a hexdump.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "mw",
|
|
||||||
.func = cmd_mw,
|
|
||||||
.help =
|
|
||||||
"mw <address> bytes ...\n"
|
|
||||||
" Write a sequence of bytes to a memory address. Byte values are\n"
|
|
||||||
" two-digit hexadecimal numbers.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "reset",
|
|
||||||
.func = cmd_reset,
|
|
||||||
.help =
|
|
||||||
"reset\n"
|
|
||||||
" Reset (and halt) the CPU.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "erase",
|
|
||||||
.func = cmd_erase,
|
|
||||||
.help =
|
|
||||||
"erase\n"
|
|
||||||
" Erase the device under test.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "step",
|
|
||||||
.func = cmd_step,
|
|
||||||
.help =
|
|
||||||
"step [count]\n"
|
|
||||||
" Single-step the CPU, and display the register state.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "run",
|
|
||||||
.func = cmd_run,
|
|
||||||
.help =
|
|
||||||
"run\n"
|
|
||||||
" Run the CPU to until a breakpoint is reached or the command is\n"
|
|
||||||
" interrupted.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "set",
|
|
||||||
.func = cmd_set,
|
|
||||||
.help =
|
|
||||||
"set <register> <value>\n"
|
|
||||||
" Change the value of a CPU register.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "dis",
|
|
||||||
.func = cmd_dis,
|
|
||||||
.help =
|
|
||||||
"dis <address> [length]\n"
|
|
||||||
" Disassemble a section of memory.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "hexout",
|
|
||||||
.func = cmd_hexout,
|
|
||||||
.help =
|
|
||||||
"hexout <address> <length> <filename.hex>\n"
|
|
||||||
" Save a region of memory into a HEX file.\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int devcmd_register(cproc_t cp)
|
|
||||||
{
|
|
||||||
return cproc_register_commands(cp, commands, ARRAY_LEN(commands));
|
|
||||||
}
|
|
||||||
|
|
16
devcmd.h
16
devcmd.h
|
@ -21,7 +21,19 @@
|
||||||
|
|
||||||
#include "cproc.h"
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register device commands */
|
int cmd_regs(cproc_t cp, char **arg);
|
||||||
int devcmd_register(cproc_t cp);
|
int cmd_md(cproc_t cp, char **arg);
|
||||||
|
int cmd_mw(cproc_t cp, char **arg);
|
||||||
|
int cmd_reset(cproc_t cp, char **arg);
|
||||||
|
int cmd_erase(cproc_t cp, char **arg);
|
||||||
|
int cmd_step(cproc_t cp, char **arg);
|
||||||
|
int cmd_run(cproc_t cp, char **arg);
|
||||||
|
int cmd_set(cproc_t cp, char **arg);
|
||||||
|
int cmd_dis(cproc_t cp, char **arg);
|
||||||
|
int cmd_hexout(cproc_t cp, char **arg);
|
||||||
|
int cmd_prog(cproc_t cp, char **arg);
|
||||||
|
int cmd_setbreak(cproc_t cp, char **arg);
|
||||||
|
int cmd_delbreak(cproc_t cp, char **arg);
|
||||||
|
int cmd_break(cproc_t cp, char **arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
15
gdb.c
15
gdb.c
|
@ -662,7 +662,7 @@ static int gdb_server(int port)
|
||||||
return data.error ? -1 : 0;
|
return data.error ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_gdb(cproc_t cp, char **arg)
|
int cmd_gdb(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *port_text = get_arg(arg);
|
char *port_text = get_arg(arg);
|
||||||
int port = 2000;
|
int port = 2000;
|
||||||
|
@ -682,16 +682,3 @@ static int cmd_gdb(cproc_t cp, char **arg)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cproc_command command_gdb = {
|
|
||||||
.name = "gdb",
|
|
||||||
.func = cmd_gdb,
|
|
||||||
.help =
|
|
||||||
"gdb [port]\n"
|
|
||||||
" Run a GDB remote stub on the given TCP/IP port.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
int gdb_register(cproc_t cp)
|
|
||||||
{
|
|
||||||
return cproc_register_commands(cp, &command_gdb, 1);
|
|
||||||
}
|
|
||||||
|
|
3
gdb.h
3
gdb.h
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include "cproc.h"
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register the "gdb" command */
|
int cmd_gdb(cproc_t cp, char **arg);
|
||||||
int gdb_register(cproc_t cp);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
8
main.c
8
main.c
|
@ -437,14 +437,6 @@ cproc_t setup_cproc(struct cmdline_args *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym_register(cp) < 0 ||
|
|
||||||
devcmd_register(cp) < 0 ||
|
|
||||||
gdb_register(cp) < 0 ||
|
|
||||||
rtools_register(cp) < 0) {
|
|
||||||
cproc_destroy(cp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
rtools.c
44
rtools.c
|
@ -373,7 +373,7 @@ static int do_isearch(cproc_t cp, address_t addr, address_t len,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_isearch(cproc_t cp, char **arg)
|
int cmd_isearch(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
const static struct {
|
const static struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -900,7 +900,7 @@ static void cgraph_func_info(struct call_graph *graph, cproc_t cp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_cgraph(cproc_t cp, char **arg)
|
int cmd_cgraph(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *offset_text, *len_text, *addr_text;;
|
char *offset_text, *len_text, *addr_text;;
|
||||||
address_t offset, len, addr;
|
address_t offset, len, addr;
|
||||||
|
@ -965,43 +965,3 @@ static int cmd_cgraph(cproc_t cp, char **arg)
|
||||||
cgraph_destroy(&graph);
|
cgraph_destroy(&graph);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
|
||||||
* Setup and registration
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const struct cproc_command rtools_commands[] = {
|
|
||||||
{
|
|
||||||
.name = "isearch",
|
|
||||||
.func = cmd_isearch,
|
|
||||||
.help =
|
|
||||||
"isearch <address> <length> [options ...]\n"
|
|
||||||
" Search for an instruction matching certain search terms. These\n"
|
|
||||||
" terms may be any of the following:\n"
|
|
||||||
" opcode <opcode>\n"
|
|
||||||
" byte|word|aword\n"
|
|
||||||
" jump|single|double|noarg\n"
|
|
||||||
" src <value>\n"
|
|
||||||
" dst <value>\n"
|
|
||||||
" srcreg <register>\n"
|
|
||||||
" dstreg <register>\n"
|
|
||||||
" srcmode R|I|S|&|@|+|#\n"
|
|
||||||
" dstmode R|I|S|&|@|+|#\n"
|
|
||||||
" For single-operand instructions, the operand is considered the\n"
|
|
||||||
" destination operand.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "cgraph",
|
|
||||||
.func = cmd_cgraph,
|
|
||||||
.help =
|
|
||||||
"cgraph <address> <length> [function]\n"
|
|
||||||
" Analyse the range given and produce a call graph. Displays a summary\n"
|
|
||||||
" of all functions if no function address is given.\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int rtools_register(cproc_t cp)
|
|
||||||
{
|
|
||||||
return cproc_register_commands(cp, rtools_commands,
|
|
||||||
ARRAY_LEN(rtools_commands));
|
|
||||||
}
|
|
||||||
|
|
4
rtools.h
4
rtools.h
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include "cproc.h"
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register reverse-engineering tool commands. */
|
int cmd_isearch(cproc_t cp, char **arg);
|
||||||
int rtools_register(cproc_t cp);
|
int cmd_cgraph(cproc_t cp, char **arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
40
sym.c
40
sym.c
|
@ -30,7 +30,7 @@
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
|
||||||
static int cmd_eval(cproc_t cp, char **arg)
|
int cmd_eval(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
address_t addr;
|
address_t addr;
|
||||||
address_t offset;
|
address_t offset;
|
||||||
|
@ -288,7 +288,7 @@ static int cmd_sym_del(cproc_t cp, char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym(cproc_t cp, char **arg)
|
int cmd_sym(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *subcmd = get_arg(arg);
|
char *subcmd = get_arg(arg);
|
||||||
|
|
||||||
|
@ -346,39 +346,3 @@ static int cmd_sym(cproc_t cp, char **arg)
|
||||||
fprintf(stderr, "sym: unknown subcommand: %s\n", subcmd);
|
fprintf(stderr, "sym: unknown subcommand: %s\n", subcmd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct cproc_command commands[] = {
|
|
||||||
{
|
|
||||||
.name = "=",
|
|
||||||
.func = cmd_eval,
|
|
||||||
.help =
|
|
||||||
"= <expression>\n"
|
|
||||||
" Evaluate an expression using the symbol table.\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "sym",
|
|
||||||
.func = cmd_sym,
|
|
||||||
.help =
|
|
||||||
"sym clear\n"
|
|
||||||
" Clear the symbol table.\n"
|
|
||||||
"sym set <name> <value>\n"
|
|
||||||
" Set or overwrite the value of a symbol.\n"
|
|
||||||
"sym del <name>\n"
|
|
||||||
" Delete a symbol from the symbol table.\n"
|
|
||||||
"sym import <filename>\n"
|
|
||||||
" Load symbols from the given file.\n"
|
|
||||||
"sym import+ <filename>\n"
|
|
||||||
" Load additional symbols from the given file.\n"
|
|
||||||
"sym export <filename>\n"
|
|
||||||
" Save the current symbols to a BSD-style symbol file.\n"
|
|
||||||
"sym find <regex>\n"
|
|
||||||
" Search for symbols by regular expression.\n"
|
|
||||||
"sym rename <regex> <string>\n"
|
|
||||||
" Replace every occurance of a pattern in symbol names.\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int sym_register(cproc_t cp)
|
|
||||||
{
|
|
||||||
return cproc_register_commands(cp, commands, ARRAY_LEN(commands));
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue