Command processor is now an object.
This commit is contained in:
parent
90d39a96f5
commit
ba6e3366ff
2
Makefile
2
Makefile
|
@ -41,7 +41,7 @@ install: mspdebug mspdebug.man
|
||||||
|
|
||||||
mspdebug: main.o fet.o rf2500.o dis.o uif.o ihex.o elf32.o stab.o util.o \
|
mspdebug: main.o fet.o rf2500.o dis.o uif.o ihex.o elf32.o stab.o util.o \
|
||||||
bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o sym.o devcmd.o \
|
bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o sym.o devcmd.o \
|
||||||
parse.o vector.o
|
cproc.o vector.o cproc_util.o
|
||||||
$(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
$(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
|
@ -0,0 +1,604 @@
|
||||||
|
/* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef USE_READLINE
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
#include "vector.h"
|
||||||
|
#include "stab.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct cproc {
|
||||||
|
struct vector command_list;
|
||||||
|
struct vector option_list;
|
||||||
|
int lists_modified;
|
||||||
|
|
||||||
|
int modify_flags;
|
||||||
|
int in_reader_loop;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cproc_option *find_option(cproc_t cp, const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cp->option_list.size; i++) {
|
||||||
|
struct cproc_option *opt =
|
||||||
|
VECTOR_PTR(cp->option_list, i, struct cproc_option);
|
||||||
|
|
||||||
|
if (!strcasecmp(opt->name, name))
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (cp->option_list.ptr)
|
||||||
|
qsort(cp->option_list.ptr, cp->option_list.size,
|
||||||
|
cp->option_list.elemsize, namelist_cmp);
|
||||||
|
|
||||||
|
cp->lists_modified = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void namelist_print(struct vector *v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int max_len = 0;
|
||||||
|
int rows, cols;
|
||||||
|
|
||||||
|
for (i = 0; i < v->size; i++) {
|
||||||
|
const char *text = VECTOR_AT(*v, i, const char *);
|
||||||
|
int len = strlen(text);
|
||||||
|
|
||||||
|
if (len > max_len)
|
||||||
|
max_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_len += 2;
|
||||||
|
cols = 72 / max_len;
|
||||||
|
rows = (v->size + cols - 1) / cols;
|
||||||
|
|
||||||
|
for (i = 0; i < rows; i++) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
printf(" ");
|
||||||
|
for (j = 0; j < cols; j++) {
|
||||||
|
int k = j * rows + i;
|
||||||
|
const char *text;
|
||||||
|
|
||||||
|
if (k >= v->size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
text = VECTOR_AT(*v, k, const char *);
|
||||||
|
printf("%s", text);
|
||||||
|
for (k = strlen(text); k < max_len; k++)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *type_text(cproc_option_type_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case CPROC_OPTION_BOOL:
|
||||||
|
return "boolean";
|
||||||
|
|
||||||
|
case CPROC_OPTION_NUMERIC:
|
||||||
|
return "numeric";
|
||||||
|
|
||||||
|
case CPROC_OPTION_STRING:
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_help(cproc_t cp, char **arg)
|
||||||
|
{
|
||||||
|
const char *topic = get_arg(arg);
|
||||||
|
|
||||||
|
if (topic) {
|
||||||
|
const struct cproc_command *cmd = find_command(cp, topic);
|
||||||
|
const struct cproc_option *opt = find_option(cp, topic);
|
||||||
|
|
||||||
|
if (cmd) {
|
||||||
|
cproc_printf(cp, "\x1b[1mCOMMAND: %s\x1b[0m\n",
|
||||||
|
cmd->name);
|
||||||
|
fputs(cmd->help, stdout);
|
||||||
|
if (opt)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt) {
|
||||||
|
cproc_printf(cp, "\x1b[1mOPTION: %s (%s)\x1b[0m\n",
|
||||||
|
opt->name, type_text(opt->type));
|
||||||
|
fputs(opt->help, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cmd || opt)) {
|
||||||
|
fprintf(stderr, "help: unknown command: %s\n", topic);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sort_lists(cp);
|
||||||
|
|
||||||
|
printf("Available commands:\n");
|
||||||
|
namelist_print(&cp->command_list);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("Available options:\n");
|
||||||
|
namelist_print(&cp->option_list);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("Type \"help <topic>\" for more information.\n");
|
||||||
|
printf("Press Ctrl+D to quit.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_option(struct cproc_option *o, const char *word)
|
||||||
|
{
|
||||||
|
switch (o->type) {
|
||||||
|
case CPROC_OPTION_BOOL:
|
||||||
|
o->data.numeric = (isdigit(word[0]) && word[0] > '0') ||
|
||||||
|
word[0] == 't' || word[0] == 'y' ||
|
||||||
|
(word[0] == 'o' && word[1] == 'n');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPROC_OPTION_NUMERIC:
|
||||||
|
return stab_exp(word, &o->data.numeric);
|
||||||
|
|
||||||
|
case CPROC_OPTION_STRING:
|
||||||
|
strncpy(o->data.text, word, sizeof(o->data.text));
|
||||||
|
o->data.text[sizeof(o->data.text) - 1] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void display_option(const struct cproc_option *o)
|
||||||
|
{
|
||||||
|
printf("%32s = ", o->name);
|
||||||
|
|
||||||
|
switch (o->type) {
|
||||||
|
case CPROC_OPTION_BOOL:
|
||||||
|
printf("%s", o->data.numeric ? "true" : "false");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPROC_OPTION_NUMERIC:
|
||||||
|
printf("0x%x (%d)", o->data.numeric,
|
||||||
|
o->data.numeric);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPROC_OPTION_STRING:
|
||||||
|
printf("%s", o->data.text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_opt(cproc_t cp, char **arg)
|
||||||
|
{
|
||||||
|
const char *opt_text = get_arg(arg);
|
||||||
|
struct cproc_option *opt = NULL;
|
||||||
|
|
||||||
|
sort_lists(cp);
|
||||||
|
|
||||||
|
if (opt_text) {
|
||||||
|
opt = find_option(cp, opt_text);
|
||||||
|
if (!opt) {
|
||||||
|
fprintf(stderr, "opt: no such option: %s\n",
|
||||||
|
opt_text);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (**arg) {
|
||||||
|
if (parse_option(opt, *arg) < 0) {
|
||||||
|
fprintf(stderr, "opt: can't parse option: %s\n",
|
||||||
|
*arg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (opt_text) {
|
||||||
|
display_option(opt);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cp->option_list.size; i++)
|
||||||
|
display_option(VECTOR_PTR(cp->option_list, i,
|
||||||
|
struct cproc_option));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_read(cproc_t cp, char **arg)
|
||||||
|
{
|
||||||
|
char *filename = get_arg(arg);
|
||||||
|
|
||||||
|
if (!filename) {
|
||||||
|
fprintf(stderr, "read: filename must be specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct cproc_option built_in_options[] = {
|
||||||
|
{
|
||||||
|
.name = "color",
|
||||||
|
.type = CPROC_OPTION_BOOL,
|
||||||
|
.help = "Colorize debugging output.\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cproc_t cproc_new(void)
|
||||||
|
{
|
||||||
|
cproc_t cp = malloc(sizeof(*cp));
|
||||||
|
|
||||||
|
if (!cp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(cp, 0, sizeof(*cp));
|
||||||
|
|
||||||
|
vector_init(&cp->command_list, sizeof(struct cproc_command));
|
||||||
|
vector_init(&cp->option_list, sizeof(struct cproc_option));
|
||||||
|
|
||||||
|
if (vector_push(&cp->command_list, &built_in_commands,
|
||||||
|
ARRAY_LEN(built_in_commands)) < 0 ||
|
||||||
|
vector_push(&cp->option_list, &built_in_options,
|
||||||
|
ARRAY_LEN(built_in_options)) < 0) {
|
||||||
|
vector_destroy(&cp->command_list);
|
||||||
|
vector_destroy(&cp->option_list);
|
||||||
|
free(cp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_destroy(cproc_t cp)
|
||||||
|
{
|
||||||
|
vector_destroy(&cp->command_list);
|
||||||
|
vector_destroy(&cp->option_list);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_register_options(cproc_t cp, const struct cproc_option *opt,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
if (vector_push(&cp->option_list, opt, count) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cp->lists_modified = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_printf(cproc_t cp, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
va_list ap;
|
||||||
|
int want_color = 0;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
cproc_get_int(cp, "color", &want_color);
|
||||||
|
if (!want_color) {
|
||||||
|
char *src = buf;
|
||||||
|
char *dst = buf;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (*src == 27) {
|
||||||
|
while (*src && !isalpha(*src))
|
||||||
|
src++;
|
||||||
|
if (*src)
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*src)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_modify(cproc_t cp, int flags)
|
||||||
|
{
|
||||||
|
cp->modify_flags |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_unmodify(cproc_t cp, int flags)
|
||||||
|
{
|
||||||
|
cp->modify_flags &= ~flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_prompt_abort(cproc_t cp, int flags)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if (!(cp->in_reader_loop && (cp->modify_flags & flags)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
printf("Symbols have not been saved since modification. "
|
||||||
|
"Continue (y/n)? ");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if (!fgets(buf, sizeof(buf), stdin)) {
|
||||||
|
printf("\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toupper(buf[0]) == 'Y')
|
||||||
|
return 0;
|
||||||
|
if (toupper(buf[0]) == 'N')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
printf("Please answer \"y\" or \"n\".\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_get_int(cproc_t cp, const char *name, int *value)
|
||||||
|
{
|
||||||
|
struct cproc_option *opt = find_option(cp, name);
|
||||||
|
|
||||||
|
if (!opt)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (opt->type == CPROC_OPTION_NUMERIC ||
|
||||||
|
opt->type == CPROC_OPTION_BOOL) {
|
||||||
|
*value = opt->data.numeric;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_get_string(cproc_t cp, const char *name, char *value, int max_len)
|
||||||
|
{
|
||||||
|
struct cproc_option *opt = find_option(cp, name);
|
||||||
|
|
||||||
|
if (!opt)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (opt->type == CPROC_OPTION_STRING) {
|
||||||
|
strncpy(value, opt->data.text, max_len);
|
||||||
|
value[max_len - 1] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USE_READLINE
|
||||||
|
#define LINE_BUF_SIZE 128
|
||||||
|
|
||||||
|
static char *readline(const char *prompt)
|
||||||
|
{
|
||||||
|
char *buf = malloc(LINE_BUF_SIZE);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
perror("readline: can't allocate memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
printf("(mspdebug) ");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if (fgets(buf, LINE_BUF_SIZE, stdin))
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
if (feof(stdin))
|
||||||
|
break;
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define add_history(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int process_command(cproc_t cp, char *arg, int interactive)
|
||||||
|
{
|
||||||
|
const char *cmd_text;
|
||||||
|
int len = strlen(arg);
|
||||||
|
|
||||||
|
while (len && isspace(arg[len - 1]))
|
||||||
|
len--;
|
||||||
|
arg[len] = 0;
|
||||||
|
|
||||||
|
cmd_text = get_arg(&arg);
|
||||||
|
if (cmd_text) {
|
||||||
|
const struct cproc_command *cmd = find_command(cp, cmd_text);
|
||||||
|
|
||||||
|
if (cmd) {
|
||||||
|
int old = cp->in_reader_loop;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cp->in_reader_loop = interactive;
|
||||||
|
ret = cmd->func(cp, &arg);
|
||||||
|
cp->in_reader_loop = old;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "unknown command: %s (try \"help\")\n",
|
||||||
|
cmd_text);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_reader_loop(cproc_t cp)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
cmd_help(cp, NULL);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (;;) {
|
||||||
|
char *buf = readline("(mspdebug) ");
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
break;
|
||||||
|
|
||||||
|
add_history(buf);
|
||||||
|
process_command(cp, buf, 1);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
} while (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_process_command(cproc_t cp, char *cmd)
|
||||||
|
{
|
||||||
|
return process_command(cp, cmd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cproc_process_file(cproc_t cp, const char *filename)
|
||||||
|
{
|
||||||
|
FILE *in;
|
||||||
|
char buf[1024];
|
||||||
|
int line_no = 0;
|
||||||
|
|
||||||
|
in = fopen(filename, "r");
|
||||||
|
if (!in) {
|
||||||
|
fprintf(stderr, "read: can't open %s: %s\n",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), in)) {
|
||||||
|
char *cmd = buf;
|
||||||
|
|
||||||
|
line_no++;
|
||||||
|
|
||||||
|
while (*cmd && isspace(*cmd))
|
||||||
|
cmd++;
|
||||||
|
|
||||||
|
if (*cmd == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (process_command(cp, cmd, 0) < 0) {
|
||||||
|
fprintf(stderr, "read: error processing %s (line %d)\n",
|
||||||
|
filename, line_no);
|
||||||
|
fclose(in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/* 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 CPROC_H_
|
||||||
|
#define CPROC_H_
|
||||||
|
|
||||||
|
/* Command processor.
|
||||||
|
*
|
||||||
|
* This contains a list of all defined commands and options, plus modification
|
||||||
|
* flags.
|
||||||
|
*/
|
||||||
|
struct cproc;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Option definitions.
|
||||||
|
*
|
||||||
|
* Options come in three different types, and can be manipulated with the
|
||||||
|
* in-built "set" function.
|
||||||
|
*
|
||||||
|
* Default values may be specified by filling out the value portion in the
|
||||||
|
* option's definition.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
CPROC_OPTION_STRING,
|
||||||
|
CPROC_OPTION_NUMERIC,
|
||||||
|
CPROC_OPTION_BOOL
|
||||||
|
} cproc_option_type_t;
|
||||||
|
|
||||||
|
struct cproc_option {
|
||||||
|
const char *name;
|
||||||
|
cproc_option_type_t type;
|
||||||
|
const char *help;
|
||||||
|
|
||||||
|
union {
|
||||||
|
char text[128];
|
||||||
|
int numeric;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Commmand processor modification flags.
|
||||||
|
*
|
||||||
|
* Within the context of a command processor, various data items may be
|
||||||
|
* marked as having been modified. These flags can be checked, and a prompt
|
||||||
|
* invoked to ask the user to confirm before proceeding with a destructive
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* The same prompting occurs when the user elects to quit the command
|
||||||
|
* processor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPROC_MODIFY_SYMS 0x01
|
||||||
|
|
||||||
|
/* Create/destroy a command processor. The init function returns 0 if
|
||||||
|
* successful, or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
cproc_t cproc_new(void);
|
||||||
|
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);
|
||||||
|
int cproc_register_options(cproc_t cp, const struct cproc_option *opt,
|
||||||
|
int count);
|
||||||
|
|
||||||
|
/* Print a line of text on the command processor's standard output.
|
||||||
|
*
|
||||||
|
* ANSI colour codes can be embedded in the output text, and will be stripped
|
||||||
|
* out if colour is disabled.
|
||||||
|
*/
|
||||||
|
void cproc_printf(cproc_t cp, const char *fmt, ...);
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* The flags argument should be a bitwise combination representing the bits
|
||||||
|
* modify_flags that will be affected by the operation.
|
||||||
|
*/
|
||||||
|
void cproc_modify(cproc_t cp, int flags);
|
||||||
|
void cproc_unmodify(cproc_t cp, int flags);
|
||||||
|
int cproc_prompt_abort(cproc_t cp, int flags);
|
||||||
|
|
||||||
|
/* Retrieve option values. These functions return 0 on success or -1 if
|
||||||
|
* an error occurs.
|
||||||
|
*/
|
||||||
|
int cproc_get_int(cproc_t cp, const char *opt, int *value);
|
||||||
|
int cproc_get_string(cproc_t cp, const char *opt, char *value, int max_len);
|
||||||
|
|
||||||
|
/* Run the reader loop */
|
||||||
|
void cproc_reader_loop(cproc_t cp);
|
||||||
|
|
||||||
|
/* Commands can be fed directly to the processor either one at a time,
|
||||||
|
* or by specifying a file to read from.
|
||||||
|
*/
|
||||||
|
int cproc_process_command(cproc_t cp, char *cmd);
|
||||||
|
int cproc_process_file(cproc_t cp, const char *filename);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,302 @@
|
||||||
|
/* 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 <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "dis.h"
|
||||||
|
#include "cproc_util.h"
|
||||||
|
#include "stab.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int format_addr(char *buf, int max_len,
|
||||||
|
msp430_amode_t amode, u_int16_t addr)
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
u_int16_t offset;
|
||||||
|
int numeric = 0;
|
||||||
|
const char *prefix = "";
|
||||||
|
|
||||||
|
switch (amode) {
|
||||||
|
case MSP430_AMODE_REGISTER:
|
||||||
|
case MSP430_AMODE_INDIRECT:
|
||||||
|
case MSP430_AMODE_INDIRECT_INC:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case MSP430_AMODE_IMMEDIATE:
|
||||||
|
prefix = "#";
|
||||||
|
case MSP430_AMODE_INDEXED:
|
||||||
|
numeric = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSP430_AMODE_ABSOLUTE:
|
||||||
|
prefix = "&";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSP430_AMODE_SYMBOLIC:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!numeric ||
|
||||||
|
(addr >= 0x200 && addr < 0xfff0)) &&
|
||||||
|
!stab_nearest(addr, name, sizeof(name), &offset) &&
|
||||||
|
!offset)
|
||||||
|
return snprintf(buf, max_len,
|
||||||
|
"%s\x1b[1m%s\x1b[0m", prefix, name);
|
||||||
|
else if (numeric)
|
||||||
|
return snprintf(buf, max_len,
|
||||||
|
"%s\x1b[1m0x%x\x1b[0m", prefix, addr);
|
||||||
|
else
|
||||||
|
return snprintf(buf, max_len,
|
||||||
|
"%s\x1b[1m0x%04x\x1b[0m", prefix, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int format_reg(char *buf, int max_len,
|
||||||
|
msp430_amode_t amode, msp430_reg_t reg)
|
||||||
|
{
|
||||||
|
const char *prefix = "";
|
||||||
|
const char *suffix = "";
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
|
||||||
|
switch (amode) {
|
||||||
|
case MSP430_AMODE_REGISTER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSP430_AMODE_INDEXED:
|
||||||
|
prefix = "(";
|
||||||
|
suffix = ")";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSP430_AMODE_IMMEDIATE:
|
||||||
|
case MSP430_AMODE_SYMBOLIC:
|
||||||
|
case MSP430_AMODE_ABSOLUTE:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case MSP430_AMODE_INDIRECT_INC:
|
||||||
|
suffix = "+";
|
||||||
|
case MSP430_AMODE_INDIRECT:
|
||||||
|
prefix = "@";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = dis_reg_name(reg);
|
||||||
|
if (!name)
|
||||||
|
name = "???";
|
||||||
|
|
||||||
|
return snprintf(buf, max_len,
|
||||||
|
"%s\x1b[33m%s\x1b[0m%s",
|
||||||
|
prefix, name, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given an operands addressing mode, value and associated register,
|
||||||
|
* print the canonical representation of it to stdout.
|
||||||
|
*
|
||||||
|
* Returns the number of characters printed.
|
||||||
|
*/
|
||||||
|
static int format_operand(char *buf, int max_len,
|
||||||
|
msp430_amode_t amode, u_int16_t addr,
|
||||||
|
msp430_reg_t reg)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
len += format_addr(buf, max_len, amode, addr);
|
||||||
|
len += format_reg(buf + len, max_len - len, amode, addr);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write assembly language for the instruction to this buffer */
|
||||||
|
static int dis_format(char *buf, int max_len,
|
||||||
|
const struct msp430_instruction *insn)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
int tlen;
|
||||||
|
int total = 0;
|
||||||
|
const char *opname = dis_opcode_name(insn->op);
|
||||||
|
|
||||||
|
if (!opname)
|
||||||
|
opname = "???";
|
||||||
|
|
||||||
|
len = snprintf(buf + total, max_len - total,
|
||||||
|
"\x1b[36m%s%s\x1b[0m", opname,
|
||||||
|
insn->is_byte_op ? ".B" : "");
|
||||||
|
tlen = textlen(buf + total);
|
||||||
|
total += len;
|
||||||
|
|
||||||
|
while (tlen < 8 && total < max_len) {
|
||||||
|
buf[total++] = ' ';
|
||||||
|
tlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Source operand */
|
||||||
|
if (insn->itype == MSP430_ITYPE_DOUBLE) {
|
||||||
|
len = format_operand(buf + total,
|
||||||
|
max_len - total,
|
||||||
|
insn->src_mode,
|
||||||
|
insn->src_addr,
|
||||||
|
insn->src_reg);
|
||||||
|
tlen = textlen(buf + total);
|
||||||
|
total += len;
|
||||||
|
|
||||||
|
if (total < max_len)
|
||||||
|
buf[total++] = ',';
|
||||||
|
|
||||||
|
while (tlen < 15 && total < max_len) {
|
||||||
|
tlen++;
|
||||||
|
buf[total++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total < max_len)
|
||||||
|
buf[total++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destination operand */
|
||||||
|
if (insn->itype != MSP430_ITYPE_NOARG)
|
||||||
|
total += format_operand(buf + total,
|
||||||
|
max_len - total,
|
||||||
|
insn->dst_mode,
|
||||||
|
insn->dst_addr,
|
||||||
|
insn->dst_reg);
|
||||||
|
|
||||||
|
if (total < max_len)
|
||||||
|
buf[total] = 0;
|
||||||
|
else if (total) {
|
||||||
|
total--;
|
||||||
|
buf[total] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_disassemble(cproc_t cp,
|
||||||
|
u_int16_t offset, const u_int8_t *data, int length)
|
||||||
|
{
|
||||||
|
int first_line = 1;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
struct msp430_instruction insn = {0};
|
||||||
|
int retval;
|
||||||
|
int count;
|
||||||
|
int i;
|
||||||
|
u_int16_t oboff;
|
||||||
|
char obname[64];
|
||||||
|
char buf[256];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (!stab_nearest(offset, obname, sizeof(obname), &oboff)) {
|
||||||
|
if (!oboff)
|
||||||
|
cproc_printf(cp, "\x1b[m%s:\x1b[0m", obname);
|
||||||
|
else if (first_line)
|
||||||
|
cproc_printf(cp, "\x1b[m%s+0x%x:\x1b[0m",
|
||||||
|
obname, oboff);
|
||||||
|
}
|
||||||
|
first_line = 0;
|
||||||
|
|
||||||
|
retval = dis_decode(data, offset, length, &insn);
|
||||||
|
count = retval > 0 ? retval : 2;
|
||||||
|
if (count > length)
|
||||||
|
count = length;
|
||||||
|
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
" \x1b[36m%04x\x1b[0m:", offset);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
" %02x", data[i]);
|
||||||
|
|
||||||
|
while (i < 7) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
buf[len++] = ' ';
|
||||||
|
buf[len++] = ' ';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval >= 0)
|
||||||
|
len += dis_format(buf + len, sizeof(buf) - len,
|
||||||
|
&insn);
|
||||||
|
|
||||||
|
cproc_printf(cp, "%s", buf);
|
||||||
|
offset += count;
|
||||||
|
length -= count;
|
||||||
|
data += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_hexdump(cproc_t cp, u_int16_t addr, const u_int8_t *data, int len)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
char buf[128];
|
||||||
|
int len = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* Address label */
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
" \x1b[36m%04x:\x1b[0m", offset + addr);
|
||||||
|
|
||||||
|
/* Hex portion */
|
||||||
|
for (i = 0; i < 16 && offset + i < len; i++)
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
" %02x", data[offset + i]);
|
||||||
|
for (j = i; j < 16; j++) {
|
||||||
|
buf[len++] = ' ';
|
||||||
|
buf[len++] = ' ';
|
||||||
|
buf[len++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Printable characters */
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
" \x1b[32m|");
|
||||||
|
for (j = 0; j < i; j++) {
|
||||||
|
int c = data[offset + j];
|
||||||
|
|
||||||
|
buf[len++] = (c >= 32 && c <= 126) ? c : '.';
|
||||||
|
}
|
||||||
|
for (; j < 16; j++)
|
||||||
|
buf[len++] = ' ';
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
"|\x1b[0m");
|
||||||
|
|
||||||
|
cproc_printf(cp, "%s", buf);
|
||||||
|
offset += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cproc_regs(cproc_t cp, const u_int16_t *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
int j;
|
||||||
|
char buf[128];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
buf[len++] = ' ';
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
int k = j * 4 + i;
|
||||||
|
|
||||||
|
len += snprintf(buf + len, sizeof(buf) - len,
|
||||||
|
"(\x1b[1m%3s:\x1b[0m %04x) ",
|
||||||
|
dis_reg_name(k), regs[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cproc_printf(cp, "%s", buf);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* 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 CPROC_UTIL_H_
|
||||||
|
#define CPROC_UTIL_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
|
/* Print colorized disassembly on command processor standard output */
|
||||||
|
void cproc_disassemble(cproc_t cp, u_int16_t addr,
|
||||||
|
const u_int8_t *buf, int len);
|
||||||
|
|
||||||
|
/* Print colorized hexdump on standard output */
|
||||||
|
void cproc_hexdump(cproc_t cp, u_int16_t addr,
|
||||||
|
const u_int8_t *buf, int len);
|
||||||
|
|
||||||
|
/* Colorized register dump */
|
||||||
|
void cproc_regs(cproc_t cp, const u_int16_t *regs);
|
||||||
|
|
||||||
|
#endif
|
255
devcmd.c
255
devcmd.c
|
@ -25,62 +25,29 @@
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "binfile.h"
|
#include "binfile.h"
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "parse.h"
|
#include "cproc.h"
|
||||||
|
#include "cproc_util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
|
|
||||||
#define REG_COLUMNS 4
|
static int cmd_regs(cproc_t cp, char **arg)
|
||||||
#define REG_ROWS ((DEVICE_NUM_REGS + REG_COLUMNS - 1) / REG_COLUMNS)
|
|
||||||
|
|
||||||
static void show_regs(u_int16_t *regs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < REG_ROWS; i++) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
printf(" ");
|
|
||||||
for (j = 0; j < REG_COLUMNS; j++) {
|
|
||||||
int k = j * REG_ROWS + i;
|
|
||||||
|
|
||||||
if (k < DEVICE_NUM_REGS) {
|
|
||||||
printf("(");
|
|
||||||
colorize("1m");
|
|
||||||
printf("R%02d: ", k);
|
|
||||||
colorize("0m");
|
|
||||||
printf("%04x) ", regs[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_regs(char **arg)
|
|
||||||
{
|
{
|
||||||
u_int16_t regs[DEVICE_NUM_REGS];
|
u_int16_t regs[DEVICE_NUM_REGS];
|
||||||
u_int8_t code[16];
|
u_int8_t code[16];
|
||||||
|
|
||||||
if (device_get()->getregs(regs) < 0)
|
if (device_get()->getregs(regs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
show_regs(regs);
|
cproc_regs(cp, regs);
|
||||||
|
|
||||||
/* Try to disassemble the instruction at PC */
|
/* Try to disassemble the instruction at PC */
|
||||||
if (device_get()->readmem(regs[0], code, sizeof(code)) < 0)
|
if (device_get()->readmem(regs[0], code, sizeof(code)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
disassemble(regs[0], (u_int8_t *)code, sizeof(code));
|
cproc_disassemble(cp, regs[0], (u_int8_t *)code, sizeof(code));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_regs = {
|
static int cmd_md(cproc_t cp, char **arg)
|
||||||
.name = "regs",
|
|
||||||
.func = cmd_regs,
|
|
||||||
.help =
|
|
||||||
"regs\n"
|
|
||||||
" Read and display the current register contents.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_md(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);
|
||||||
|
@ -118,7 +85,7 @@ static int cmd_md(char **arg)
|
||||||
|
|
||||||
if (device_get()->readmem(offset, buf, blen) < 0)
|
if (device_get()->readmem(offset, buf, blen) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
hexdump(offset, buf, blen);
|
cproc_hexdump(cp, offset, buf, blen);
|
||||||
|
|
||||||
offset += blen;
|
offset += blen;
|
||||||
length -= blen;
|
length -= blen;
|
||||||
|
@ -127,16 +94,7 @@ static int cmd_md(char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_md = {
|
static int cmd_mw(cproc_t cp, char **arg)
|
||||||
.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"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_mw(char **arg)
|
|
||||||
{
|
{
|
||||||
char *off_text = get_arg(arg);
|
char *off_text = get_arg(arg);
|
||||||
char *byte_text;
|
char *byte_text;
|
||||||
|
@ -177,29 +135,12 @@ static int cmd_mw(char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_mw = {
|
static int cmd_reset(cproc_t cp, char **arg)
|
||||||
.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"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_reset(char **arg)
|
|
||||||
{
|
{
|
||||||
return device_get()->control(DEVICE_CTL_RESET);
|
return device_get()->control(DEVICE_CTL_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_reset = {
|
static int cmd_erase(cproc_t cp, char **arg)
|
||||||
.name = "reset",
|
|
||||||
.func = cmd_reset,
|
|
||||||
.help =
|
|
||||||
"reset\n"
|
|
||||||
" Reset (and halt) the CPU.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_erase(char **arg)
|
|
||||||
{
|
{
|
||||||
if (device_get()->control(DEVICE_CTL_HALT) < 0)
|
if (device_get()->control(DEVICE_CTL_HALT) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -208,15 +149,7 @@ static int cmd_erase(char **arg)
|
||||||
return device_get()->control(DEVICE_CTL_ERASE);
|
return device_get()->control(DEVICE_CTL_ERASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_erase = {
|
static int cmd_step(cproc_t cp, char **arg)
|
||||||
.name = "erase",
|
|
||||||
.func = cmd_erase,
|
|
||||||
.help =
|
|
||||||
"erase\n"
|
|
||||||
" Erase the device under test.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_step(char **arg)
|
|
||||||
{
|
{
|
||||||
char *count_text = get_arg(arg);
|
char *count_text = get_arg(arg);
|
||||||
int count = 1;
|
int count = 1;
|
||||||
|
@ -230,18 +163,10 @@ static int cmd_step(char **arg)
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd_regs(NULL);
|
return cmd_regs(cp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_step = {
|
static int cmd_run(cproc_t cp, char **arg)
|
||||||
.name = "step",
|
|
||||||
.func = cmd_step,
|
|
||||||
.help =
|
|
||||||
"step [count]\n"
|
|
||||||
" Single-step the CPU, and display the register state.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_run(char **arg)
|
|
||||||
{
|
{
|
||||||
char *bp_text = get_arg(arg);
|
char *bp_text = get_arg(arg);
|
||||||
int bp_addr;
|
int bp_addr;
|
||||||
|
@ -274,19 +199,10 @@ static int cmd_run(char **arg)
|
||||||
if (device_get()->control(DEVICE_CTL_HALT) < 0)
|
if (device_get()->control(DEVICE_CTL_HALT) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return cmd_regs(NULL);
|
return cmd_regs(cp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_run = {
|
static int cmd_set(cproc_t cp, char **arg)
|
||||||
.name = "run",
|
|
||||||
.func = cmd_run,
|
|
||||||
.help =
|
|
||||||
"run [breakpoint]\n"
|
|
||||||
" Run the CPU until either a specified breakpoint occurs or the\n"
|
|
||||||
" command is interrupted.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_set(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);
|
||||||
|
@ -319,19 +235,11 @@ static int cmd_set(char **arg)
|
||||||
if (device_get()->setregs(regs) < 0)
|
if (device_get()->setregs(regs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
show_regs(regs);
|
cproc_regs(cp, regs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_set = {
|
static int cmd_dis(cproc_t cp, char **arg)
|
||||||
.name = "set",
|
|
||||||
.func = cmd_set,
|
|
||||||
.help =
|
|
||||||
"set <register> <value>\n"
|
|
||||||
" Change the value of a CPU register.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_dis(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);
|
||||||
|
@ -368,18 +276,10 @@ static int cmd_dis(char **arg)
|
||||||
if (device_get()->readmem(offset, buf, length) < 0)
|
if (device_get()->readmem(offset, buf, length) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
disassemble(offset, (u_int8_t *)buf, length);
|
cproc_disassemble(cp, offset, (u_int8_t *)buf, length);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_dis = {
|
|
||||||
.name = "dis",
|
|
||||||
.func = cmd_dis,
|
|
||||||
.help =
|
|
||||||
"dis <address> [length]\n"
|
|
||||||
" Disassemble a section of memory.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static FILE *hexout_file;
|
static FILE *hexout_file;
|
||||||
static u_int16_t hexout_addr;
|
static u_int16_t hexout_addr;
|
||||||
static u_int8_t hexout_buf[16];
|
static u_int8_t hexout_buf[16];
|
||||||
|
@ -455,7 +355,7 @@ static int hexout_feed(u_int16_t addr, const u_int8_t *buf, int len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_hexout(char **arg)
|
static 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);
|
||||||
|
@ -510,14 +410,6 @@ fail:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_hexout = {
|
|
||||||
.name = "hexout",
|
|
||||||
.func = cmd_hexout,
|
|
||||||
.help =
|
|
||||||
"hexout <address> <length> <filename.hex>\n"
|
|
||||||
" Save a region of memory into a HEX file.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static u_int8_t prog_buf[128];
|
static u_int8_t prog_buf[128];
|
||||||
static u_int16_t prog_addr;
|
static u_int16_t prog_addr;
|
||||||
static int prog_len;
|
static int prog_len;
|
||||||
|
@ -589,12 +481,12 @@ static int prog_feed(u_int16_t addr, const u_int8_t *data, int len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_prog(char **arg)
|
static int cmd_prog(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
FILE *in;
|
FILE *in;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (modify_prompt(MODIFY_SYMS))
|
if (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
in = fopen(*arg, "r");
|
in = fopen(*arg, "r");
|
||||||
|
@ -630,30 +522,95 @@ static int cmd_prog(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_clear(MODIFY_SYMS);
|
cproc_unmodify(cp, CPROC_MODIFY_SYMS);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_prog = {
|
static const struct cproc_command commands[] = {
|
||||||
.name = "prog",
|
{
|
||||||
.func = cmd_prog,
|
.name = "regs",
|
||||||
.help =
|
.func = cmd_regs,
|
||||||
"prog <filename>\n"
|
.help =
|
||||||
" Erase the device and flash the data contained in a binary file.\n"
|
"regs\n"
|
||||||
" This command also loads symbols from the file, if available.\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 [breakpoint]\n"
|
||||||
|
" Run the CPU until either a specified breakpoint occurs or the\n"
|
||||||
|
" command is 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"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void devcmd_init(void)
|
int devcmd_register(cproc_t cp)
|
||||||
{
|
{
|
||||||
register_command(&command_md);
|
return cproc_register_commands(cp, commands, ARRAY_LEN(commands));
|
||||||
register_command(&command_mw);
|
|
||||||
register_command(&command_reset);
|
|
||||||
register_command(&command_erase);
|
|
||||||
register_command(&command_regs);
|
|
||||||
register_command(&command_run);
|
|
||||||
register_command(&command_step);
|
|
||||||
register_command(&command_set);
|
|
||||||
register_command(&command_dis);
|
|
||||||
register_command(&command_hexout);
|
|
||||||
register_command(&command_prog);
|
|
||||||
}
|
}
|
||||||
|
|
4
devcmd.h
4
devcmd.h
|
@ -19,7 +19,9 @@
|
||||||
#ifndef DEVCMD_H_
|
#ifndef DEVCMD_H_
|
||||||
#define DEVCMD_H_
|
#define DEVCMD_H_
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register device commands */
|
/* Register device commands */
|
||||||
void devcmd_init(void);
|
int devcmd_register(cproc_t cp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
272
dis.c
272
dis.c
|
@ -17,12 +17,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "parse.h"
|
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
#include "stab.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
* Returns the number of bytes consumed in decoding, or -1 if the a
|
* Returns the number of bytes consumed in decoding, or -1 if the a
|
||||||
* valid single-operand instruction could not be found.
|
* valid single-operand instruction could not be found.
|
||||||
*/
|
*/
|
||||||
static int decode_single(u_int8_t *code, u_int16_t offset, u_int16_t size,
|
static int decode_single(const u_int8_t *code, u_int16_t offset,
|
||||||
struct msp430_instruction *insn)
|
u_int16_t size, struct msp430_instruction *insn)
|
||||||
{
|
{
|
||||||
u_int16_t op = (code[1] << 8) | code[0];
|
u_int16_t op = (code[1] << 8) | code[0];
|
||||||
int need_arg = 0;
|
int need_arg = 0;
|
||||||
|
@ -86,8 +86,8 @@ static int decode_single(u_int8_t *code, u_int16_t offset, u_int16_t size,
|
||||||
* Returns the number of bytes consumed or -1 if a valid instruction
|
* Returns the number of bytes consumed or -1 if a valid instruction
|
||||||
* could not be found.
|
* could not be found.
|
||||||
*/
|
*/
|
||||||
static int decode_double(u_int8_t *code, u_int16_t offset, u_int16_t size,
|
static int decode_double(const u_int8_t *code, u_int16_t offset,
|
||||||
struct msp430_instruction *insn)
|
u_int16_t size, struct msp430_instruction *insn)
|
||||||
{
|
{
|
||||||
u_int16_t op = (code[1] << 8) | code[0];
|
u_int16_t op = (code[1] << 8) | code[0];
|
||||||
int need_src = 0;
|
int need_src = 0;
|
||||||
|
@ -175,7 +175,7 @@ static int decode_double(u_int8_t *code, u_int16_t offset, u_int16_t size,
|
||||||
* All jump instructions are one word in length, so this function
|
* All jump instructions are one word in length, so this function
|
||||||
* always returns 2 (to indicate the consumption of 2 bytes).
|
* always returns 2 (to indicate the consumption of 2 bytes).
|
||||||
*/
|
*/
|
||||||
static int decode_jump(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
static int decode_jump(const u_int8_t *code, u_int16_t offset, u_int16_t len,
|
||||||
struct msp430_instruction *insn)
|
struct msp430_instruction *insn)
|
||||||
{
|
{
|
||||||
u_int16_t op = (code[1] << 8) | code[0];
|
u_int16_t op = (code[1] << 8) | code[0];
|
||||||
|
@ -396,7 +396,7 @@ static void find_emulated_ops(struct msp430_instruction *insn)
|
||||||
* successful, the decoded instruction is written into the structure
|
* successful, the decoded instruction is written into the structure
|
||||||
* pointed to by insn.
|
* pointed to by insn.
|
||||||
*/
|
*/
|
||||||
int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
int dis_decode(const u_int8_t *code, u_int16_t offset, u_int16_t len,
|
||||||
struct msp430_instruction *insn)
|
struct msp430_instruction *insn)
|
||||||
{
|
{
|
||||||
u_int16_t op;
|
u_int16_t op;
|
||||||
|
@ -514,12 +514,8 @@ static const struct {
|
||||||
{MSP430_OP_TST, "TST"}
|
{MSP430_OP_TST, "TST"}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return the mnemonic for an operation, if possible.
|
/* Return the mnemonic for an operation, if possible. */
|
||||||
*
|
const char *dis_opcode_name(msp430_op_t op)
|
||||||
* If the argument is not a valid operation, this function returns the
|
|
||||||
* string "???".
|
|
||||||
*/
|
|
||||||
static const char *msp_op_name(msp430_op_t op)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -527,7 +523,18 @@ static const char *msp_op_name(msp430_op_t op)
|
||||||
if (op == opcode_names[i].op)
|
if (op == opcode_names[i].op)
|
||||||
return opcode_names[i].mnemonic;
|
return opcode_names[i].mnemonic;
|
||||||
|
|
||||||
return "???";
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msp430_op_t dis_opcode_from_name(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN(opcode_names); i++)
|
||||||
|
if (!strcasecmp(name, opcode_names[i].mnemonic))
|
||||||
|
return opcode_names[i].op;
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const msp430_reg_names[] = {
|
static const char *const msp430_reg_names[] = {
|
||||||
|
@ -537,227 +544,34 @@ static const char *const msp430_reg_names[] = {
|
||||||
"R12", "R13", "R14", "R15"
|
"R12", "R13", "R14", "R15"
|
||||||
};
|
};
|
||||||
|
|
||||||
static int format_addr(msp430_amode_t amode, u_int16_t addr)
|
msp430_reg_t dis_reg_from_name(const char *name)
|
||||||
{
|
{
|
||||||
char name[64];
|
const char *num = name;
|
||||||
u_int16_t offset;
|
|
||||||
int numeric = 0;
|
|
||||||
int len;
|
|
||||||
int count = 0;
|
|
||||||
const char *prefix = "";
|
|
||||||
|
|
||||||
switch (amode) {
|
while (num && isdigit(*num))
|
||||||
case MSP430_AMODE_REGISTER:
|
num++;
|
||||||
case MSP430_AMODE_INDIRECT:
|
|
||||||
case MSP430_AMODE_INDIRECT_INC:
|
if (*num) {
|
||||||
|
msp430_reg_t r = atoi(num);
|
||||||
|
|
||||||
|
if (r >= 0 && r <= 15)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "pc"))
|
||||||
return 0;
|
return 0;
|
||||||
|
if (!strcasecmp(name, "sp"))
|
||||||
case MSP430_AMODE_IMMEDIATE:
|
return 1;
|
||||||
prefix = "#";
|
if (!strcasecmp(name, "sr"))
|
||||||
case MSP430_AMODE_INDEXED:
|
return 2;
|
||||||
numeric = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MSP430_AMODE_ABSOLUTE:
|
|
||||||
prefix = "&";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MSP430_AMODE_SYMBOLIC:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = printf("%s", prefix);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
if ((!numeric ||
|
|
||||||
(addr >= 0x200 && addr < 0xfff0)) &&
|
|
||||||
!stab_nearest(addr, name, sizeof(name), &offset) &&
|
|
||||||
!offset) {
|
|
||||||
colorize("1m");
|
|
||||||
len = printf("%s", name);
|
|
||||||
colorize("0m");
|
|
||||||
} else {
|
|
||||||
colorize("32m");
|
|
||||||
len = printf(numeric ? "0x%x" : "0x%04x", addr);
|
|
||||||
colorize("0m");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int format_reg(msp430_amode_t amode, msp430_reg_t reg)
|
|
||||||
{
|
|
||||||
const char *prefix = "";
|
|
||||||
const char *suffix = "";
|
|
||||||
int len;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
switch (amode) {
|
|
||||||
case MSP430_AMODE_REGISTER:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MSP430_AMODE_INDEXED:
|
|
||||||
prefix = "(";
|
|
||||||
suffix = ")";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MSP430_AMODE_IMMEDIATE:
|
|
||||||
case MSP430_AMODE_SYMBOLIC:
|
|
||||||
case MSP430_AMODE_ABSOLUTE:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case MSP430_AMODE_INDIRECT_INC:
|
|
||||||
suffix = "+";
|
|
||||||
case MSP430_AMODE_INDIRECT:
|
|
||||||
prefix = "@";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (reg >= 0 && reg < ARRAY_LEN(msp430_reg_names));
|
|
||||||
|
|
||||||
len = printf("%s", prefix);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
colorize("33m");
|
|
||||||
len = printf("%s", msp430_reg_names[reg]);
|
|
||||||
colorize("0m");
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
len = printf("%s", suffix);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given an operands addressing mode, value and associated register,
|
|
||||||
* print the canonical representation of it to stdout.
|
|
||||||
*
|
|
||||||
* Returns the number of characters printed.
|
|
||||||
*/
|
|
||||||
static int format_operand(msp430_amode_t amode, u_int16_t addr,
|
|
||||||
msp430_reg_t reg)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
len = format_addr(amode, addr);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
len = format_reg(amode, reg);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write assembly language for the instruction to this buffer */
|
|
||||||
static void dis_format(const struct msp430_instruction *insn)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
colorize("36m");
|
|
||||||
len = printf("%s%s", msp_op_name(insn->op),
|
|
||||||
insn->is_byte_op ? ".B" : "");
|
|
||||||
colorize("0m");
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
while (count < 8) {
|
|
||||||
count++;
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Source operand */
|
|
||||||
if (insn->itype == MSP430_ITYPE_DOUBLE) {
|
|
||||||
len = format_operand(insn->src_mode,
|
|
||||||
insn->src_addr,
|
|
||||||
insn->src_reg);
|
|
||||||
if (len >= 0)
|
|
||||||
count += len;
|
|
||||||
|
|
||||||
printf(",");
|
|
||||||
count++;
|
|
||||||
while (count < 23) {
|
|
||||||
count++;
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf(" ");
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destination operand */
|
|
||||||
if (insn->itype != MSP430_ITYPE_NOARG)
|
|
||||||
format_operand(insn->dst_mode,
|
|
||||||
insn->dst_addr,
|
|
||||||
insn->dst_reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dis_opcode_by_name(const char *name, msp430_op_t *op)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LEN(opcode_names); i++)
|
|
||||||
if (!strcasecmp(name, opcode_names[i].mnemonic)) {
|
|
||||||
if (op)
|
|
||||||
*op = opcode_names[i].op;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disassemble(u_int16_t offset, u_int8_t *data, int length)
|
const char *dis_reg_name(msp430_reg_t reg)
|
||||||
{
|
{
|
||||||
int first_line = 1;
|
if (reg >= 0 && reg <= 15)
|
||||||
|
return msp430_reg_names[reg];
|
||||||
|
|
||||||
while (length) {
|
return NULL;
|
||||||
struct msp430_instruction insn;
|
|
||||||
int retval;
|
|
||||||
int count;
|
|
||||||
int i;
|
|
||||||
u_int16_t oboff;
|
|
||||||
char obname[64];
|
|
||||||
|
|
||||||
if (!stab_nearest(offset, obname, sizeof(obname), &oboff)) {
|
|
||||||
colorize("1m");
|
|
||||||
if (!oboff)
|
|
||||||
printf("%s:\n", obname);
|
|
||||||
else if (first_line)
|
|
||||||
printf("%s+0x%x:\n", obname, oboff);
|
|
||||||
colorize("0m");
|
|
||||||
}
|
|
||||||
first_line = 0;
|
|
||||||
|
|
||||||
retval = dis_decode(data, offset, length, &insn);
|
|
||||||
count = retval > 0 ? retval : 2;
|
|
||||||
if (count > length)
|
|
||||||
count = length;
|
|
||||||
|
|
||||||
colorize("36m");
|
|
||||||
printf(" %04x:", offset);
|
|
||||||
colorize("0m");
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
printf(" %02x", data[i]);
|
|
||||||
|
|
||||||
while (i < 7) {
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retval >= 0)
|
|
||||||
dis_format(&insn);
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
offset += count;
|
|
||||||
length -= count;
|
|
||||||
data += count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
13
dis.h
13
dis.h
|
@ -202,13 +202,14 @@ struct msp430_instruction {
|
||||||
* successful, the decoded instruction is written into the structure
|
* successful, the decoded instruction is written into the structure
|
||||||
* pointed to by insn.
|
* pointed to by insn.
|
||||||
*/
|
*/
|
||||||
int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
int dis_decode(const u_int8_t *code,
|
||||||
|
u_int16_t offset, u_int16_t len,
|
||||||
struct msp430_instruction *insn);
|
struct msp430_instruction *insn);
|
||||||
|
|
||||||
/* Look up an opcode by name. Returns 0 if successful, -1 otherwise. */
|
/* Look up names for registers and opcodes */
|
||||||
int dis_opcode_by_name(const char *name, msp430_op_t *op);
|
msp430_op_t dis_opcode_from_name(const char *name);
|
||||||
|
const char *dis_opcode_name(msp430_op_t op);
|
||||||
/* Print a disassembly on stdout */
|
msp430_reg_t dis_reg_from_name(const char *name);
|
||||||
void disassemble(u_int16_t offset, u_int8_t *buf, int length);
|
const char *dis_reg_name(msp430_reg_t reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
9
gdb.c
9
gdb.c
|
@ -30,7 +30,6 @@
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* GDB IO routines
|
* GDB IO routines
|
||||||
|
@ -579,7 +578,7 @@ static int gdb_server(int port)
|
||||||
return gdb_errno ? -1 : 0;
|
return gdb_errno ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_gdb(char **arg)
|
static 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;
|
||||||
|
@ -595,7 +594,7 @@ static int cmd_gdb(char **arg)
|
||||||
return gdb_server(port);
|
return gdb_server(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_gdb = {
|
static const struct cproc_command command_gdb = {
|
||||||
.name = "gdb",
|
.name = "gdb",
|
||||||
.func = cmd_gdb,
|
.func = cmd_gdb,
|
||||||
.help =
|
.help =
|
||||||
|
@ -603,7 +602,7 @@ static struct command command_gdb = {
|
||||||
" Run a GDB remote stub on the given TCP/IP port.\n"
|
" Run a GDB remote stub on the given TCP/IP port.\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
void gdb_init(void)
|
int gdb_register(cproc_t cp)
|
||||||
{
|
{
|
||||||
register_command(&command_gdb);
|
return cproc_register_commands(cp, &command_gdb, 1);
|
||||||
}
|
}
|
||||||
|
|
4
gdb.h
4
gdb.h
|
@ -19,7 +19,9 @@
|
||||||
#ifndef GDB_H_
|
#ifndef GDB_H_
|
||||||
#define GDB_H_
|
#define GDB_H_
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register the "gdb" command */
|
/* Register the "gdb" command */
|
||||||
void gdb_init(void);
|
int gdb_register(cproc_t cp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
27
main.c
27
main.c
|
@ -24,7 +24,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
#include "parse.h"
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "binfile.h"
|
#include "binfile.h"
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
|
@ -66,7 +65,7 @@ static void usage(const char *progname)
|
||||||
progname, progname, progname, progname);
|
progname, progname, progname, progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_rc_file(void)
|
static void process_rc_file(cproc_t cp)
|
||||||
{
|
{
|
||||||
const char *home = getenv("HOME");
|
const char *home = getenv("HOME");
|
||||||
char text[256];
|
char text[256];
|
||||||
|
@ -76,7 +75,7 @@ static void process_rc_file(void)
|
||||||
|
|
||||||
snprintf(text, sizeof(text), "%s/.mspdebug", home);
|
snprintf(text, sizeof(text), "%s/.mspdebug", home);
|
||||||
if (!access(text, F_OK))
|
if (!access(text, F_OK))
|
||||||
process_file(text);
|
cproc_process_file(cp, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MODE_RF2500 0x01
|
#define MODE_RF2500 0x01
|
||||||
|
@ -90,6 +89,7 @@ int main(int argc, char **argv)
|
||||||
const char *uif_device = NULL;
|
const char *uif_device = NULL;
|
||||||
const char *bsl_device = NULL;
|
const char *bsl_device = NULL;
|
||||||
const struct device *msp430_dev = NULL;
|
const struct device *msp430_dev = NULL;
|
||||||
|
cproc_t cp;
|
||||||
int opt;
|
int opt;
|
||||||
int no_rc = 0;
|
int no_rc = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -192,28 +192,33 @@ int main(int argc, char **argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cp = cproc_new();
|
||||||
|
if (!cp ||
|
||||||
|
sym_register(cp) < 0 ||
|
||||||
|
devcmd_register(cp) < 0 ||
|
||||||
|
gdb_register(cp) < 0 ||
|
||||||
|
rtools_register(cp) < 0) {
|
||||||
|
perror("couldn't set up command parser");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialise parsing */
|
/* Initialise parsing */
|
||||||
device_set(msp430_dev);
|
device_set(msp430_dev);
|
||||||
ctrlc_init();
|
ctrlc_init();
|
||||||
parse_init();
|
|
||||||
sym_init();
|
|
||||||
devcmd_init();
|
|
||||||
gdb_init();
|
|
||||||
rtools_init();
|
|
||||||
|
|
||||||
if (!no_rc)
|
if (!no_rc)
|
||||||
process_rc_file();
|
process_rc_file(cp);
|
||||||
|
|
||||||
/* Process commands */
|
/* Process commands */
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
if (process_command(argv[optind++], 0) < 0) {
|
if (cproc_process_command(cp, argv[optind++]) < 0) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reader_loop();
|
cproc_reader_loop(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
msp430_dev->close();
|
msp430_dev->close();
|
||||||
|
|
545
parse.c
545
parse.c
|
@ -1,545 +0,0 @@
|
||||||
/* 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 <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifdef USE_READLINE
|
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
#include "parse.h"
|
|
||||||
#include "stab.h"
|
|
||||||
|
|
||||||
static struct option *option_list;
|
|
||||||
static struct command *command_list;
|
|
||||||
|
|
||||||
void register_option(struct option *o)
|
|
||||||
{
|
|
||||||
o->next = option_list;
|
|
||||||
option_list = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct option *find_option(const char *name)
|
|
||||||
{
|
|
||||||
struct option *o;
|
|
||||||
|
|
||||||
for (o = option_list; o; o = o->next)
|
|
||||||
if (!strcasecmp(o->name, name))
|
|
||||||
return o;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command *find_command(const char *name)
|
|
||||||
{
|
|
||||||
struct command *c;
|
|
||||||
|
|
||||||
for (c = command_list; c; c = c->next)
|
|
||||||
if (!strcasecmp(c->name, name))
|
|
||||||
return c;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_command(struct command *c)
|
|
||||||
{
|
|
||||||
c->next = command_list;
|
|
||||||
command_list = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int interactive_call = 1;
|
|
||||||
|
|
||||||
int is_interactive(void)
|
|
||||||
{
|
|
||||||
return interactive_call;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_command(char *arg, int interactive)
|
|
||||||
{
|
|
||||||
const char *cmd_text;
|
|
||||||
int len = strlen(arg);
|
|
||||||
|
|
||||||
while (len && isspace(arg[len - 1]))
|
|
||||||
len--;
|
|
||||||
arg[len] = 0;
|
|
||||||
|
|
||||||
cmd_text = get_arg(&arg);
|
|
||||||
if (cmd_text) {
|
|
||||||
const struct command *cmd = find_command(cmd_text);
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
int old = interactive_call;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
interactive_call = interactive;
|
|
||||||
ret = cmd->func(&arg);
|
|
||||||
interactive_call = old;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "unknown command: %s (try \"help\")\n",
|
|
||||||
cmd_text);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *type_text(option_type_t type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case OPTION_BOOLEAN:
|
|
||||||
return "boolean";
|
|
||||||
|
|
||||||
case OPTION_NUMERIC:
|
|
||||||
return "numeric";
|
|
||||||
|
|
||||||
case OPTION_TEXT:
|
|
||||||
return "text";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *name_list[128];
|
|
||||||
static int num_names;
|
|
||||||
static int name_max_len;
|
|
||||||
|
|
||||||
static void name_start(void)
|
|
||||||
{
|
|
||||||
num_names = 0;
|
|
||||||
name_max_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void name_push(const char *text)
|
|
||||||
{
|
|
||||||
if (num_names < ARRAY_LEN(name_list)) {
|
|
||||||
int len = strlen(text);
|
|
||||||
|
|
||||||
name_list[num_names++] = text;
|
|
||||||
if (len > name_max_len)
|
|
||||||
name_max_len = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_name(const void *left, const void *right)
|
|
||||||
{
|
|
||||||
return strcasecmp(*(const char *const *)left,
|
|
||||||
*(const char *const *)right);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void name_list_show(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int max_len = name_max_len + 2;
|
|
||||||
int rows, cols;
|
|
||||||
|
|
||||||
qsort(name_list, num_names, sizeof(name_list[0]),
|
|
||||||
compare_name);
|
|
||||||
|
|
||||||
cols = 72 / max_len;
|
|
||||||
rows = (num_names + cols - 1) / cols;
|
|
||||||
|
|
||||||
for (i = 0; i < rows; i++) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
printf(" ");
|
|
||||||
for (j = 0; j < cols; j++) {
|
|
||||||
int k = j * rows + i;
|
|
||||||
|
|
||||||
if (k >= num_names)
|
|
||||||
break;
|
|
||||||
|
|
||||||
printf("%s", name_list[k]);
|
|
||||||
for (k = strlen(name_list[k]); k < max_len; k++)
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_help(char **arg)
|
|
||||||
{
|
|
||||||
const char *topic = get_arg(arg);
|
|
||||||
|
|
||||||
if (topic) {
|
|
||||||
const struct command *cmd = find_command(topic);
|
|
||||||
const struct option *opt = find_option(topic);
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
colorize("1m");
|
|
||||||
printf("COMMAND: %s\n", cmd->name);
|
|
||||||
colorize("0m");
|
|
||||||
fputs(cmd->help, stdout);
|
|
||||||
if (opt)
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt) {
|
|
||||||
colorize("1m");
|
|
||||||
printf("OPTION: %s (%s)\n", opt->name,
|
|
||||||
type_text(opt->type));
|
|
||||||
colorize("0m");
|
|
||||||
fputs(opt->help, stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cmd || opt)) {
|
|
||||||
fprintf(stderr, "help: unknown command: %s\n", topic);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const struct command *cmd;
|
|
||||||
const struct option *opt;
|
|
||||||
|
|
||||||
name_start();
|
|
||||||
for (cmd = command_list; cmd; cmd = cmd->next)
|
|
||||||
name_push(cmd->name);
|
|
||||||
|
|
||||||
printf("Available commands:\n");
|
|
||||||
name_list_show();
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
name_start();
|
|
||||||
for (opt = option_list; opt; opt = opt->next)
|
|
||||||
name_push(opt->name);
|
|
||||||
|
|
||||||
printf("Available options:\n");
|
|
||||||
name_list_show();
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
printf("Type \"help <topic>\" for more information.\n");
|
|
||||||
printf("Press Ctrl+D to quit.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command command_help = {
|
|
||||||
.func = cmd_help,
|
|
||||||
.name = "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"
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef USE_READLINE
|
|
||||||
#define LINE_BUF_SIZE 128
|
|
||||||
|
|
||||||
static char *readline(const char *prompt)
|
|
||||||
{
|
|
||||||
char *buf = malloc(LINE_BUF_SIZE);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
perror("readline: can't allocate memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
printf("(mspdebug) ");
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
if (fgets(buf, LINE_BUF_SIZE, stdin))
|
|
||||||
return buf;
|
|
||||||
|
|
||||||
if (feof(stdin))
|
|
||||||
break;
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define add_history(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void reader_loop(void)
|
|
||||||
{
|
|
||||||
printf("\n");
|
|
||||||
cmd_help(NULL);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
do {
|
|
||||||
for (;;) {
|
|
||||||
char *buf = readline("(mspdebug) ");
|
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
break;
|
|
||||||
|
|
||||||
add_history(buf);
|
|
||||||
process_command(buf, 1);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
} while (modify_prompt(MODIFY_ALL));
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_option(const struct option *o)
|
|
||||||
{
|
|
||||||
printf("%32s = ", o->name);
|
|
||||||
|
|
||||||
switch (o->type) {
|
|
||||||
case OPTION_BOOLEAN:
|
|
||||||
printf("%s", o->data.numeric ? "true" : "false");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTION_NUMERIC:
|
|
||||||
printf("0x%x (%d)", o->data.numeric,
|
|
||||||
o->data.numeric);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTION_TEXT:
|
|
||||||
printf("%s", o->data.text);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_option(struct option *o, const char *word)
|
|
||||||
{
|
|
||||||
switch (o->type) {
|
|
||||||
case OPTION_BOOLEAN:
|
|
||||||
o->data.numeric = (isdigit(word[0]) && word[0] > '0') ||
|
|
||||||
word[0] == 't' || word[0] == 'y' ||
|
|
||||||
(word[0] == 'o' && word[1] == 'n');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTION_NUMERIC:
|
|
||||||
return stab_exp(word, &o->data.numeric);
|
|
||||||
|
|
||||||
case OPTION_TEXT:
|
|
||||||
strncpy(o->data.text, word, sizeof(o->data.text));
|
|
||||||
o->data.text[sizeof(o->data.text) - 1] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_opt(char **arg)
|
|
||||||
{
|
|
||||||
const char *opt_text = get_arg(arg);
|
|
||||||
struct option *opt = NULL;
|
|
||||||
|
|
||||||
if (opt_text) {
|
|
||||||
opt = find_option(opt_text);
|
|
||||||
if (!opt) {
|
|
||||||
fprintf(stderr, "opt: no such option: %s\n",
|
|
||||||
opt_text);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (**arg) {
|
|
||||||
if (parse_option(opt, *arg) < 0) {
|
|
||||||
fprintf(stderr, "opt: can't parse option: %s\n",
|
|
||||||
*arg);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (opt_text) {
|
|
||||||
display_option(opt);
|
|
||||||
} else {
|
|
||||||
struct option *o;
|
|
||||||
|
|
||||||
for (o = option_list; o; o = o->next)
|
|
||||||
display_option(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command command_opt = {
|
|
||||||
.name = "opt",
|
|
||||||
.func = cmd_opt,
|
|
||||||
.help =
|
|
||||||
"opt [name] [value]\n"
|
|
||||||
" Query or set option variables. With no arguments, displays all\n"
|
|
||||||
" available options.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
int process_file(const char *filename)
|
|
||||||
{
|
|
||||||
FILE *in;
|
|
||||||
char buf[1024];
|
|
||||||
int line_no = 0;
|
|
||||||
|
|
||||||
in = fopen(filename, "r");
|
|
||||||
if (!in) {
|
|
||||||
fprintf(stderr, "read: can't open %s: %s\n",
|
|
||||||
filename, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), in)) {
|
|
||||||
char *cmd = buf;
|
|
||||||
|
|
||||||
line_no++;
|
|
||||||
|
|
||||||
while (*cmd && isspace(*cmd))
|
|
||||||
cmd++;
|
|
||||||
|
|
||||||
if (*cmd == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (process_command(cmd, 0) < 0) {
|
|
||||||
fprintf(stderr, "read: error processing %s (line %d)\n",
|
|
||||||
filename, line_no);
|
|
||||||
fclose(in);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_read(char **arg)
|
|
||||||
{
|
|
||||||
char *filename = get_arg(arg);
|
|
||||||
|
|
||||||
if (!filename) {
|
|
||||||
fprintf(stderr, "read: filename must be specified\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return process_file(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct command command_read = {
|
|
||||||
.name = "read",
|
|
||||||
.func = cmd_read,
|
|
||||||
.help =
|
|
||||||
"read <filename>\n"
|
|
||||||
" Read commands from a file and evaluate them.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct option option_color = {
|
|
||||||
.name = "color",
|
|
||||||
.type = OPTION_BOOLEAN,
|
|
||||||
.help = "Colorize debugging output.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
int colorize(const char *text)
|
|
||||||
{
|
|
||||||
if (!option_color.data.numeric)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return printf("\x1b[%s", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_init(void)
|
|
||||||
{
|
|
||||||
register_option(&option_color);
|
|
||||||
|
|
||||||
register_command(&command_help);
|
|
||||||
register_command(&command_opt);
|
|
||||||
register_command(&command_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int modify_flags;
|
|
||||||
|
|
||||||
void modify_set(int flags)
|
|
||||||
{
|
|
||||||
modify_flags |= flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void modify_clear(int flags)
|
|
||||||
{
|
|
||||||
modify_flags &= ~flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
int modify_prompt(int flags)
|
|
||||||
{
|
|
||||||
char buf[32];
|
|
||||||
|
|
||||||
if (!(interactive_call && (modify_flags & flags)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
printf("Symbols have not been saved since modification. "
|
|
||||||
"Continue (y/n)? ");
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
if (!fgets(buf, sizeof(buf), stdin)) {
|
|
||||||
printf("\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toupper(buf[0]) == 'Y')
|
|
||||||
return 0;
|
|
||||||
if (toupper(buf[0]) == 'N')
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
printf("Please answer \"y\" or \"n\".\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hexdump(int addr, const u_int8_t *data, int len)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
while (offset < len) {
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
/* Address label */
|
|
||||||
colorize("36m");
|
|
||||||
printf(" %04x:", offset + addr);
|
|
||||||
colorize("0m");
|
|
||||||
|
|
||||||
/* Hex portion */
|
|
||||||
for (i = 0; i < 16 && offset + i < len; i++)
|
|
||||||
printf(" %02x", data[offset + i]);
|
|
||||||
for (j = i; j < 16; j++)
|
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
/* Printable characters */
|
|
||||||
colorize("32m");
|
|
||||||
printf(" |");
|
|
||||||
for (j = 0; j < i; j++) {
|
|
||||||
int c = data[offset + j];
|
|
||||||
|
|
||||||
printf("%c", (c >= 32 && c <= 126) ? c : '.');
|
|
||||||
}
|
|
||||||
for (; j < 16; j++)
|
|
||||||
printf(" ");
|
|
||||||
printf("|\n");
|
|
||||||
colorize("0m");
|
|
||||||
|
|
||||||
offset += i;
|
|
||||||
}
|
|
||||||
}
|
|
110
parse.h
110
parse.h
|
@ -1,110 +0,0 @@
|
||||||
/* 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 PARSE_H_
|
|
||||||
#define PARSE_H_
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
typedef int (*command_func_t)(char **arg);
|
|
||||||
|
|
||||||
struct command {
|
|
||||||
const char *name;
|
|
||||||
int (*func)(char **arg);
|
|
||||||
const char *help;
|
|
||||||
|
|
||||||
struct command *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Add a command to the global command table */
|
|
||||||
void register_command(struct command *c);
|
|
||||||
|
|
||||||
/* Process a command, returning -1 on error or 0 if executed
|
|
||||||
* successfully.
|
|
||||||
*
|
|
||||||
* The interactive argument specifies whether or not the command
|
|
||||||
* should be executed in an interactive context.
|
|
||||||
*/
|
|
||||||
int process_command(char *arg, int interactive);
|
|
||||||
int process_file(const char *filename);
|
|
||||||
|
|
||||||
/* Run the reader loop, exiting when the user presses Ctrl+D.
|
|
||||||
*
|
|
||||||
* Commands executed by the reader loop are executed in interactive
|
|
||||||
* context.
|
|
||||||
*/
|
|
||||||
void reader_loop(void);
|
|
||||||
|
|
||||||
/* Print an ANSI colour code, if the colour option has been set by
|
|
||||||
* the user.
|
|
||||||
*/
|
|
||||||
int colorize(const char *text);
|
|
||||||
|
|
||||||
/* Return non-zero if executing in an interactive context. */
|
|
||||||
int is_interactive(void);
|
|
||||||
|
|
||||||
/* Mark/unmark items as modified. The modify_prompt function, when
|
|
||||||
* called in interactive context, prompts the user before continuing
|
|
||||||
* if any of the items specified are modified. If the user elects
|
|
||||||
* to abort the operation, it returns non-zero.
|
|
||||||
*/
|
|
||||||
#define MODIFY_SYMS 0x01
|
|
||||||
#define MODIFY_ALL 0x01
|
|
||||||
|
|
||||||
void modify_set(int flags);
|
|
||||||
void modify_clear(int flags);
|
|
||||||
int modify_prompt(int flags);
|
|
||||||
|
|
||||||
/* Options interface. Options may be declared by any module and
|
|
||||||
* registered with the parser.
|
|
||||||
*
|
|
||||||
* They can then be manipulated by the "set" command (function
|
|
||||||
* declared below.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
OPTION_BOOLEAN,
|
|
||||||
OPTION_NUMERIC,
|
|
||||||
OPTION_TEXT
|
|
||||||
} option_type_t;
|
|
||||||
|
|
||||||
struct option {
|
|
||||||
const char *name;
|
|
||||||
option_type_t type;
|
|
||||||
const char *help;
|
|
||||||
|
|
||||||
union {
|
|
||||||
char text[128];
|
|
||||||
int numeric;
|
|
||||||
} data;
|
|
||||||
|
|
||||||
struct option *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Add an option to the parser's list. Options can't be removed from
|
|
||||||
* the list once added.
|
|
||||||
*/
|
|
||||||
void register_option(struct option *o);
|
|
||||||
|
|
||||||
/* Initialise the parser, and register built-ins. */
|
|
||||||
void parse_init(void);
|
|
||||||
|
|
||||||
/* Display a canonical hexdump */
|
|
||||||
void hexdump(int addr, const u_int8_t *data, int len);
|
|
||||||
|
|
||||||
#endif
|
|
20
rtools.c
20
rtools.c
|
@ -27,7 +27,7 @@
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
#include "rtools.h"
|
#include "rtools.h"
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "parse.h"
|
#include "cproc_util.h"
|
||||||
|
|
||||||
#define ISEARCH_OPCODE 0x0001
|
#define ISEARCH_OPCODE 0x0001
|
||||||
#define ISEARCH_BW 0x0002
|
#define ISEARCH_BW 0x0002
|
||||||
|
@ -59,7 +59,8 @@ static int isearch_opcode(const char *term, char **arg,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dis_opcode_by_name(opname, &q->insn.op) < 0) {
|
q->insn.op = dis_opcode_from_name(opname);
|
||||||
|
if (q->insn.op < 0) {
|
||||||
fprintf(stderr, "isearch: unknown opcode: %s\n", opname);
|
fprintf(stderr, "isearch: unknown opcode: %s\n", opname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -315,7 +316,8 @@ static int isearch_match(const struct msp430_instruction *insn,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_isearch(int addr, int len, const struct isearch_query *q)
|
static int do_isearch(cproc_t cp,
|
||||||
|
int addr, int len, const struct isearch_query *q)
|
||||||
{
|
{
|
||||||
u_int8_t *mbuf;
|
u_int8_t *mbuf;
|
||||||
const struct device *dev = device_get();
|
const struct device *dev = device_get();
|
||||||
|
@ -346,14 +348,14 @@ static int do_isearch(int addr, int len, const struct isearch_query *q)
|
||||||
int count = dis_decode(mbuf + i, addr + i, len - i, &insn);
|
int count = dis_decode(mbuf + i, addr + i, len - i, &insn);
|
||||||
|
|
||||||
if (count >= 0 && isearch_match(&insn, q))
|
if (count >= 0 && isearch_match(&insn, q))
|
||||||
disassemble(addr + i, mbuf + i, count);
|
cproc_disassemble(cp, addr + i, mbuf + i, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mbuf);
|
free(mbuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_isearch(char **arg)
|
static int cmd_isearch(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
const static struct {
|
const static struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -414,10 +416,10 @@ static int cmd_isearch(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return do_isearch(addr, len, &q);
|
return do_isearch(cp, addr, len, &q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command isearch_command = {
|
static const struct cproc_command isearch_command = {
|
||||||
.name = "isearch",
|
.name = "isearch",
|
||||||
.func = cmd_isearch,
|
.func = cmd_isearch,
|
||||||
.help =
|
.help =
|
||||||
|
@ -437,7 +439,7 @@ static struct command isearch_command = {
|
||||||
" destination operand.\n"
|
" destination operand.\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
void rtools_init(void)
|
int rtools_register(cproc_t cp)
|
||||||
{
|
{
|
||||||
register_command(&isearch_command);
|
return cproc_register_commands(cp, &isearch_command, 1);
|
||||||
}
|
}
|
||||||
|
|
4
rtools.h
4
rtools.h
|
@ -19,7 +19,9 @@
|
||||||
#ifndef RTOOLS_H_
|
#ifndef RTOOLS_H_
|
||||||
#define RTOOLS_H_
|
#define RTOOLS_H_
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register reverse-engineering tool commands. */
|
/* Register reverse-engineering tool commands. */
|
||||||
void rtools_init(void);
|
int rtools_register(cproc_t cp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1
sim.c
1
sim.c
|
@ -24,7 +24,6 @@
|
||||||
#include "dis.h"
|
#include "dis.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "parse.h"
|
|
||||||
|
|
||||||
#define MEM_SIZE 65536
|
#define MEM_SIZE 65536
|
||||||
|
|
||||||
|
|
117
sym.c
117
sym.c
|
@ -26,10 +26,10 @@
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "binfile.h"
|
#include "binfile.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "parse.h"
|
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
#include "sym.h"
|
||||||
|
|
||||||
static int cmd_eval(char **arg)
|
static int cmd_eval(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
int addr;
|
int addr;
|
||||||
u_int16_t offset;
|
u_int16_t offset;
|
||||||
|
@ -51,20 +51,12 @@ static int cmd_eval(char **arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_eval = {
|
static int cmd_sym_load_add(cproc_t cp, int clear, char **arg)
|
||||||
.name = "=",
|
|
||||||
.func = cmd_eval,
|
|
||||||
.help =
|
|
||||||
"= <expression>\n"
|
|
||||||
" Evaluate an expression using the symbol table.\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cmd_sym_load_add(int clear, char **arg)
|
|
||||||
{
|
{
|
||||||
FILE *in;
|
FILE *in;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (clear && modify_prompt(MODIFY_SYMS))
|
if (clear && cproc_prompt_abort(cp, CPROC_MODIFY_SYMS))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
in = fopen(*arg, "r");
|
in = fopen(*arg, "r");
|
||||||
|
@ -86,9 +78,9 @@ static int cmd_sym_load_add(int clear, char **arg)
|
||||||
fclose(in);
|
fclose(in);
|
||||||
|
|
||||||
if (clear)
|
if (clear)
|
||||||
modify_clear(MODIFY_SYMS);
|
cproc_unmodify(cp, CPROC_MODIFY_SYMS);
|
||||||
else
|
else
|
||||||
modify_set(MODIFY_SYMS);
|
cproc_modify(cp, CPROC_MODIFY_SYMS);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +97,7 @@ static int savemap_cb(const char *name, u_int16_t value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym_savemap(char **arg)
|
static int cmd_sym_savemap(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *fname = get_arg(arg);
|
char *fname = get_arg(arg);
|
||||||
|
|
||||||
|
@ -131,7 +123,7 @@ static int cmd_sym_savemap(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_clear(MODIFY_SYMS);
|
cproc_unmodify(cp, CPROC_MODIFY_SYMS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +143,7 @@ static int find_sym(const char *name, u_int16_t value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym_find(char **arg)
|
static int cmd_sym_find(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *expr = get_arg(arg);
|
char *expr = get_arg(arg);
|
||||||
|
|
||||||
|
@ -215,9 +207,6 @@ static int renames_do(const char *replace)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count)
|
|
||||||
modify_set(MODIFY_SYMS);
|
|
||||||
|
|
||||||
printf("%d symbols renamed\n", count);
|
printf("%d symbols renamed\n", count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +230,7 @@ static int find_renames(const char *name, u_int16_t value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym_rename(char **arg)
|
static int cmd_sym_rename(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
const char *expr = get_arg(arg);
|
const char *expr = get_arg(arg);
|
||||||
const char *replace = get_arg(arg);
|
const char *replace = get_arg(arg);
|
||||||
|
@ -269,10 +258,14 @@ static int cmd_sym_rename(char **arg)
|
||||||
regfree(&find_preg);
|
regfree(&find_preg);
|
||||||
ret = renames_do(replace);
|
ret = renames_do(replace);
|
||||||
vector_destroy(&renames_vec);
|
vector_destroy(&renames_vec);
|
||||||
return ret;
|
|
||||||
|
if (ret > 0)
|
||||||
|
cproc_modify(cp, CPROC_MODIFY_SYMS);
|
||||||
|
|
||||||
|
return ret >= 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym_del(char **arg)
|
static int cmd_sym_del(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *name = get_arg(arg);
|
char *name = get_arg(arg);
|
||||||
|
|
||||||
|
@ -288,11 +281,11 @@ static int cmd_sym_del(char **arg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_set(MODIFY_SYMS);
|
cproc_modify(cp, CPROC_MODIFY_SYMS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmd_sym(char **arg)
|
static int cmd_sym(cproc_t cp, char **arg)
|
||||||
{
|
{
|
||||||
char *subcmd = get_arg(arg);
|
char *subcmd = get_arg(arg);
|
||||||
|
|
||||||
|
@ -303,10 +296,10 @@ static int cmd_sym(char **arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcasecmp(subcmd, "clear")) {
|
if (!strcasecmp(subcmd, "clear")) {
|
||||||
if (modify_prompt(MODIFY_SYMS))
|
if (cproc_prompt_abort(cp, CPROC_MODIFY_SYMS))
|
||||||
return 0;
|
return 0;
|
||||||
stab_clear();
|
stab_clear();
|
||||||
modify_clear(MODIFY_SYMS);
|
cproc_unmodify(cp, CPROC_MODIFY_SYMS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,53 +323,59 @@ static int cmd_sym(char **arg)
|
||||||
if (stab_set(name, value) < 0)
|
if (stab_set(name, value) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
modify_set(MODIFY_SYMS);
|
cproc_modify(cp, CPROC_MODIFY_SYMS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcasecmp(subcmd, "del"))
|
if (!strcasecmp(subcmd, "del"))
|
||||||
return cmd_sym_del(arg);
|
return cmd_sym_del(cp, arg);
|
||||||
if (!strcasecmp(subcmd, "import"))
|
if (!strcasecmp(subcmd, "import"))
|
||||||
return cmd_sym_load_add(1, arg);
|
return cmd_sym_load_add(cp, 1, arg);
|
||||||
if (!strcasecmp(subcmd, "import+"))
|
if (!strcasecmp(subcmd, "import+"))
|
||||||
return cmd_sym_load_add(0, arg);
|
return cmd_sym_load_add(cp, 0, arg);
|
||||||
if (!strcasecmp(subcmd, "export"))
|
if (!strcasecmp(subcmd, "export"))
|
||||||
return cmd_sym_savemap(arg);
|
return cmd_sym_savemap(cp, arg);
|
||||||
if (!strcasecmp(subcmd, "rename"))
|
if (!strcasecmp(subcmd, "rename"))
|
||||||
return cmd_sym_rename(arg);
|
return cmd_sym_rename(cp, arg);
|
||||||
if (!strcasecmp(subcmd, "find"))
|
if (!strcasecmp(subcmd, "find"))
|
||||||
return cmd_sym_find(arg);
|
return cmd_sym_find(cp, arg);
|
||||||
|
|
||||||
fprintf(stderr, "sym: unknown subcommand: %s\n", subcmd);
|
fprintf(stderr, "sym: unknown subcommand: %s\n", subcmd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command command_sym = {
|
static const struct cproc_command commands[] = {
|
||||||
.name = "sym",
|
{
|
||||||
.func = cmd_sym,
|
.name = "=",
|
||||||
.help =
|
.func = cmd_eval,
|
||||||
"sym clear\n"
|
.help =
|
||||||
" Clear the symbol table.\n"
|
"= <expression>\n"
|
||||||
"sym set <name> <value>\n"
|
" Evaluate an expression using the symbol table.\n"
|
||||||
" Set or overwrite the value of a symbol.\n"
|
},
|
||||||
"sym del <name>\n"
|
{
|
||||||
" Delete a symbol from the symbol table.\n"
|
.name = "sym",
|
||||||
"sym import <filename>\n"
|
.func = cmd_sym,
|
||||||
" Load symbols from the given file.\n"
|
.help =
|
||||||
"sym import+ <filename>\n"
|
"sym clear\n"
|
||||||
" Load additional symbols from the given file.\n"
|
" Clear the symbol table.\n"
|
||||||
"sym export <filename>\n"
|
"sym set <name> <value>\n"
|
||||||
" Save the current symbols to a BSD-style symbol file.\n"
|
" Set or overwrite the value of a symbol.\n"
|
||||||
"sym find <regex>\n"
|
"sym del <name>\n"
|
||||||
" Search for symbols by regular expression.\n"
|
" Delete a symbol from the symbol table.\n"
|
||||||
"sym rename <regex> <string>\n"
|
"sym import <filename>\n"
|
||||||
" Replace every occurance of a pattern in symbol names.\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_init(void)
|
int sym_register(cproc_t cp)
|
||||||
{
|
{
|
||||||
register_command(&command_eval);
|
return cproc_register_commands(cp, commands, ARRAY_LEN(commands));
|
||||||
register_command(&command_sym);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
4
sym.h
4
sym.h
|
@ -19,7 +19,9 @@
|
||||||
#ifndef SYM_H_
|
#ifndef SYM_H_
|
||||||
#define SYM_H_
|
#define SYM_H_
|
||||||
|
|
||||||
|
#include "cproc.h"
|
||||||
|
|
||||||
/* Register symbol-table manipulation commands */
|
/* Register symbol-table manipulation commands */
|
||||||
void sym_init(void);
|
int sym_register(cproc_t cp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
22
util.c
22
util.c
|
@ -241,3 +241,25 @@ void debug_hexdump(const char *label, const u_int8_t *data, int len)
|
||||||
offset += i;
|
offset += i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int textlen(const char *text)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (*text == 27) {
|
||||||
|
while (*text && !isalpha(*text))
|
||||||
|
text++;
|
||||||
|
if (*text)
|
||||||
|
text++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*text)
|
||||||
|
break;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
text++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
3
util.h
3
util.h
|
@ -42,4 +42,7 @@ char *get_arg(char **text);
|
||||||
void debug_hexdump(const char *label,
|
void debug_hexdump(const char *label,
|
||||||
const u_int8_t *data, int len);
|
const u_int8_t *data, int len);
|
||||||
|
|
||||||
|
/* Get text length, not including ANSI codes */
|
||||||
|
int textlen(const char *text);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
2
vector.c
2
vector.c
|
@ -57,7 +57,7 @@ int vector_realloc(struct vector *v, int capacity)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vector_push(struct vector *v, void *data, int count)
|
int vector_push(struct vector *v, const void *data, int count)
|
||||||
{
|
{
|
||||||
int needed = v->size + count;
|
int needed = v->size + count;
|
||||||
|
|
||||||
|
|
2
vector.h
2
vector.h
|
@ -45,7 +45,7 @@ int vector_realloc(struct vector *v, int capacity);
|
||||||
/* Append any number of elements to the end of a vector, reallocating if
|
/* Append any number of elements to the end of a vector, reallocating if
|
||||||
* necessary. Returns 0 on success or -1 if memory could not be allocated.
|
* necessary. Returns 0 on success or -1 if memory could not be allocated.
|
||||||
*/
|
*/
|
||||||
int vector_push(struct vector *v, void *data, int count);
|
int vector_push(struct vector *v, const void *data, int count);
|
||||||
|
|
||||||
/* Dereference a vector, giving an expression for the element of type t at
|
/* Dereference a vector, giving an expression for the element of type t at
|
||||||
* position i in vector v. Use as follows:
|
* position i in vector v. Use as follows:
|
||||||
|
|
Loading…
Reference in New Issue