Implemented isearch command.
This commit is contained in:
parent
188efdca10
commit
757a9fb799
2
Makefile
2
Makefile
|
@ -40,7 +40,7 @@ install: mspdebug mspdebug.man
|
|||
.SUFFIXES: .c .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
|
||||
bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||
|
||||
.c.o:
|
||||
|
|
41
dis.c
41
dis.c
|
@ -449,17 +449,10 @@ int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Return the mnemonic for an operation, if possible.
|
||||
*
|
||||
* If the argument is not a valid operation, this function returns the
|
||||
* string "???".
|
||||
*/
|
||||
static const char *msp_op_name(msp430_op_t op)
|
||||
{
|
||||
static const struct {
|
||||
static const struct {
|
||||
msp430_op_t op;
|
||||
const char *mnemonic;
|
||||
} ops[] = {
|
||||
} opcode_names[] = {
|
||||
/* Single operand */
|
||||
{MSP430_OP_RRC, "RRC"},
|
||||
{MSP430_OP_SWPB, "SWPB"},
|
||||
|
@ -518,12 +511,20 @@ static const char *msp_op_name(msp430_op_t op)
|
|||
{MSP430_OP_SETN, "SETN"},
|
||||
{MSP430_OP_SETZ, "SETZ"},
|
||||
{MSP430_OP_TST, "TST"}
|
||||
};
|
||||
};
|
||||
|
||||
/* Return the mnemonic for an operation, if possible.
|
||||
*
|
||||
* 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;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(ops); i++)
|
||||
if (op == ops[i].op)
|
||||
return ops[i].mnemonic;
|
||||
for (i = 0; i < ARRAY_LEN(opcode_names); i++)
|
||||
if (op == opcode_names[i].op)
|
||||
return opcode_names[i].mnemonic;
|
||||
|
||||
return "???";
|
||||
}
|
||||
|
@ -745,3 +746,17 @@ void disassemble(u_int16_t offset, u_int8_t *data, int length)
|
|||
data += count;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
3
dis.h
3
dis.h
|
@ -208,4 +208,7 @@ int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
|||
/* Print a disassembly on stdout */
|
||||
void disassemble(u_int16_t offset, u_int8_t *buf, int length);
|
||||
|
||||
/* Look up an opcode by name. Returns 0 if successful, -1 otherwise. */
|
||||
int dis_opcode_by_name(const char *name, msp430_op_t *op);
|
||||
|
||||
#endif
|
||||
|
|
13
main.c
13
main.c
|
@ -29,6 +29,7 @@
|
|||
#include "stab.h"
|
||||
#include "util.h"
|
||||
#include "gdb.h"
|
||||
#include "rtools.h"
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
|
@ -70,6 +71,7 @@ int main(int argc, char **argv)
|
|||
const char *bsl_device = NULL;
|
||||
const struct device *msp430_dev = NULL;
|
||||
int opt;
|
||||
int ret = 0;
|
||||
int flags = 0;
|
||||
int want_jtag = 0;
|
||||
int vcc_mv = 3000;
|
||||
|
@ -135,6 +137,7 @@ int main(int argc, char **argv)
|
|||
|
||||
parse_init();
|
||||
gdb_init();
|
||||
rtools_init();
|
||||
if (stab_init() < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -171,8 +174,12 @@ int main(int argc, char **argv)
|
|||
|
||||
/* Process commands */
|
||||
if (optind < argc) {
|
||||
while (optind < argc)
|
||||
process_command(argv[optind++], 0);
|
||||
while (optind < argc) {
|
||||
if (process_command(argv[optind++], 0) < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader_loop();
|
||||
}
|
||||
|
@ -180,5 +187,5 @@ int main(int argc, char **argv)
|
|||
device_exit();
|
||||
stab_exit();
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
|
65
mspdebug.man
65
mspdebug.man
|
@ -118,6 +118,71 @@ If the specified file already exists, then it will be overwritten. If
|
|||
you need to dump memory from several disjoint memory regions, you can
|
||||
do this by saving each section to a separate file. The resulting files
|
||||
can then be concatenated together to form a single valid HEX file.
|
||||
.IP "\fBisearch\fR \fIaddress\fR \fIlength\fR [\fIoptions\fR ...]"
|
||||
Search over the given range for an instruction which matches the specified
|
||||
search criteria. The search may be narrowed by specifying one or more of
|
||||
the following terms:
|
||||
.RS
|
||||
.IP "\fBopcode\fR \fIopcode\fR"
|
||||
Match the specified opcode. Byte/word specifiers are not recognised, as
|
||||
they are specified with other options.
|
||||
.IP "\fBbyte\fR"
|
||||
Match only byte operations.
|
||||
.IP "\fBword\fR"
|
||||
Match only word operations.
|
||||
.IP "\fBjump\fR"
|
||||
Match only jump instructions (conditional and unconditional jumps, but
|
||||
not instructions such as BR which load the program counter explicitly).
|
||||
.IP "\fBsingle\fR"
|
||||
Match only single-operand instructions.
|
||||
.IP "\fBdouble\fR"
|
||||
Match only double-operand instructions.
|
||||
.IP "\fBnoarg\fR"
|
||||
Match only instructions with no arguments.
|
||||
.IP "\fBsrc\fR \fIaddress\fR"
|
||||
Match instructions with the specified value in the source operand. The value
|
||||
may be given as an address expression. Specifying this option implies matching
|
||||
of only double-operand instructions.
|
||||
.IP "\fBdst\fR \fIaddress\fR"
|
||||
Match instructions with the specified value in the destination
|
||||
operand. This option implies that no-argument instructions are not
|
||||
matched.
|
||||
.IP "\fBsrcreg\fR \fIregister\fR"
|
||||
Match instructions using the specified register in the source operand. This
|
||||
option implies matching of only double-operand instructions.
|
||||
.IP "\fBdstreg\fR \fIregister\fR"
|
||||
Match instructions using the specified register in the destination operand.
|
||||
This option implies that no-argument instructions are not matched.
|
||||
.IP "\fBsrcmode\fR \fImode\fR"
|
||||
Match instructions using the specified mode in the source operand. See
|
||||
below for a list of modes recognised. This option implies matching of
|
||||
only double-operand instructions.
|
||||
.IP "\fBdstmode\fR \fImode\fR"
|
||||
Match instructions using the specified mode in the destination operand. See
|
||||
below for a list of modes. This option implies that no-argument instructions
|
||||
are not matched.
|
||||
.RE
|
||||
For single-operand instructions, the operand is considered to be the
|
||||
destination operand.
|
||||
|
||||
The seven addressing modes used by the MSP430 are represented by single
|
||||
characters, and are listed here:
|
||||
.RS
|
||||
.IP "\fBR\fR"
|
||||
Register mode.
|
||||
.IP "\fBI\fR"
|
||||
Indexed mode.
|
||||
.IP "\fBS\fR"
|
||||
Symbolic mode.
|
||||
.IP "\fB&\fR"
|
||||
Absolute mode.
|
||||
.IP "\fB@\fR"
|
||||
Register-indirect mode.
|
||||
.IP "\fB+\fR"
|
||||
Register-indirect mode with auto-increment.
|
||||
.IP "\fB#\fR"
|
||||
Immediate mode.
|
||||
.RE
|
||||
.IP "\fBmd\fR \fIaddress\fR [\fIlength\fR]"
|
||||
Read the specified section of device memory and display it as a
|
||||
canonical\-style hexdump. Both arguments may be address expressions. If
|
||||
|
|
|
@ -0,0 +1,441 @@
|
|||
/* 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "device.h"
|
||||
#include "dis.h"
|
||||
#include "rtools.h"
|
||||
|
||||
#define ISEARCH_OPCODE 0x0001
|
||||
#define ISEARCH_BW 0x0002
|
||||
#define ISEARCH_SRC_ADDR 0x0004
|
||||
#define ISEARCH_DST_ADDR 0x0008
|
||||
#define ISEARCH_SRC_MODE 0x0010
|
||||
#define ISEARCH_DST_MODE 0x0020
|
||||
#define ISEARCH_SRC_REG 0x0040
|
||||
#define ISEARCH_DST_REG 0x0080
|
||||
#define ISEARCH_TYPE 0x0100
|
||||
|
||||
struct isearch_query {
|
||||
int flags;
|
||||
struct msp430_instruction insn;
|
||||
};
|
||||
|
||||
static int isearch_opcode(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
const char *opname = get_arg(arg);
|
||||
|
||||
if (q->flags & ISEARCH_OPCODE) {
|
||||
fprintf(stderr, "isearch: opcode already specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!opname) {
|
||||
fprintf(stderr, "isearch: opcode name expected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dis_opcode_by_name(opname, &q->insn.op) < 0) {
|
||||
fprintf(stderr, "isearch: unknown opcode: %s\n", opname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->flags |= ISEARCH_OPCODE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_bw(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
if (q->flags & ISEARCH_BW) {
|
||||
fprintf(stderr, "isearch: operand size already specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->flags |= ISEARCH_BW;
|
||||
q->insn.is_byte_op = (toupper(*term) == 'B');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_type(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
if (q->flags & ISEARCH_TYPE) {
|
||||
fprintf(stderr, "isearch: instruction type already "
|
||||
"specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->flags |= ISEARCH_TYPE;
|
||||
|
||||
switch (toupper(*term)) {
|
||||
case 'J':
|
||||
q->insn.itype = MSP430_ITYPE_JUMP;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
q->insn.itype = MSP430_ITYPE_SINGLE;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
q->insn.itype = MSP430_ITYPE_DOUBLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
q->insn.itype = MSP430_ITYPE_NOARG;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_addr(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
int which = toupper(*term) == 'S' ?
|
||||
ISEARCH_SRC_ADDR : ISEARCH_DST_ADDR;
|
||||
const char *addr_text;
|
||||
int addr;
|
||||
|
||||
if (q->flags & which) {
|
||||
fprintf(stderr, "isearch: address already specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_text = get_arg(arg);
|
||||
if (!addr_text) {
|
||||
fprintf(stderr, "isearch: address expected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_exp(addr_text, &addr) < 0)
|
||||
return -1;
|
||||
|
||||
q->flags |= which;
|
||||
if (which == ISEARCH_SRC_ADDR)
|
||||
q->insn.src_addr = addr;
|
||||
else
|
||||
q->insn.dst_addr = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_reg(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
int which = toupper(*term) == 'S' ?
|
||||
ISEARCH_SRC_REG : ISEARCH_DST_REG;
|
||||
const char *reg_text;
|
||||
int reg;
|
||||
|
||||
if (q->flags & which) {
|
||||
fprintf(stderr, "isearch: register already specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg_text = get_arg(arg);
|
||||
if (!reg_text) {
|
||||
fprintf(stderr, "isearch: register expected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*reg_text && !isdigit(*reg_text))
|
||||
reg_text++;
|
||||
reg = atoi(reg_text);
|
||||
|
||||
q->flags |= which;
|
||||
if (which == ISEARCH_SRC_REG)
|
||||
q->insn.src_reg = reg;
|
||||
else
|
||||
q->insn.dst_reg = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_mode(const char *term, char **arg,
|
||||
struct isearch_query *q)
|
||||
{
|
||||
int which = toupper(*term) == 'S' ?
|
||||
ISEARCH_SRC_MODE : ISEARCH_DST_MODE;
|
||||
const char *what_text;
|
||||
int what;
|
||||
|
||||
if (q->flags & which) {
|
||||
fprintf(stderr, "isearch: mode already specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
what_text = get_arg(arg);
|
||||
if (!what_text) {
|
||||
fprintf(stderr, "isearch: mode must be specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (toupper(*what_text)) {
|
||||
case 'R':
|
||||
what = MSP430_AMODE_REGISTER;
|
||||
break;
|
||||
|
||||
case '@':
|
||||
what = MSP430_AMODE_INDIRECT;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
what = MSP430_AMODE_INDIRECT_INC;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
what = MSP430_AMODE_IMMEDIATE;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
what = MSP430_AMODE_INDEXED;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
what = MSP430_AMODE_ABSOLUTE;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
what = MSP430_AMODE_SYMBOLIC;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "isearch: unknown address mode: %s\n",
|
||||
what_text);
|
||||
return -1;
|
||||
}
|
||||
|
||||
q->flags |= which;
|
||||
if (which == ISEARCH_SRC_MODE)
|
||||
q->insn.src_mode = what;
|
||||
else
|
||||
q->insn.dst_mode = what;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isearch_match(const struct msp430_instruction *insn,
|
||||
const struct isearch_query *q)
|
||||
{
|
||||
if ((q->flags & (ISEARCH_SRC_ADDR | ISEARCH_SRC_MODE |
|
||||
ISEARCH_SRC_REG)) &&
|
||||
insn->itype != MSP430_ITYPE_DOUBLE)
|
||||
return 0;
|
||||
|
||||
if ((q->flags & (ISEARCH_DST_ADDR | ISEARCH_DST_MODE |
|
||||
ISEARCH_DST_REG)) &&
|
||||
insn->itype == MSP430_ITYPE_NOARG)
|
||||
return 0;
|
||||
|
||||
if ((q->flags & ISEARCH_OPCODE) &&
|
||||
insn->op != q->insn.op)
|
||||
return 0;
|
||||
|
||||
if ((q->flags & ISEARCH_BW) &&
|
||||
(q->insn.is_byte_op ? 1 : 0) != (insn->is_byte_op ? 1 : 0))
|
||||
return 0;
|
||||
|
||||
if (q->flags & ISEARCH_SRC_ADDR) {
|
||||
if (insn->src_mode != MSP430_AMODE_INDEXED &&
|
||||
insn->src_mode != MSP430_AMODE_SYMBOLIC &&
|
||||
insn->src_mode != MSP430_AMODE_ABSOLUTE &&
|
||||
insn->src_mode != MSP430_AMODE_IMMEDIATE)
|
||||
return 0;
|
||||
if (insn->src_addr != q->insn.src_addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q->flags & ISEARCH_DST_ADDR) {
|
||||
if (insn->dst_mode != MSP430_AMODE_INDEXED &&
|
||||
insn->dst_mode != MSP430_AMODE_SYMBOLIC &&
|
||||
insn->dst_mode != MSP430_AMODE_ABSOLUTE &&
|
||||
insn->dst_mode != MSP430_AMODE_IMMEDIATE)
|
||||
return 0;
|
||||
if (insn->dst_addr != q->insn.dst_addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((q->flags & ISEARCH_SRC_MODE) &&
|
||||
insn->src_mode != q->insn.src_mode)
|
||||
return 0;
|
||||
|
||||
if ((q->flags & ISEARCH_DST_MODE) &&
|
||||
insn->dst_mode != q->insn.dst_mode)
|
||||
return 0;
|
||||
|
||||
if (q->flags & ISEARCH_SRC_REG) {
|
||||
if (insn->src_mode != MSP430_AMODE_REGISTER &&
|
||||
insn->src_mode != MSP430_AMODE_INDIRECT &&
|
||||
insn->src_mode != MSP430_AMODE_INDIRECT_INC &&
|
||||
insn->src_mode != MSP430_AMODE_INDEXED)
|
||||
return 0;
|
||||
if (insn->src_reg != q->insn.src_reg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q->flags & ISEARCH_DST_REG) {
|
||||
if (insn->dst_mode != MSP430_AMODE_REGISTER &&
|
||||
insn->dst_mode != MSP430_AMODE_INDIRECT &&
|
||||
insn->dst_mode != MSP430_AMODE_INDIRECT_INC &&
|
||||
insn->dst_mode != MSP430_AMODE_INDEXED)
|
||||
return 0;
|
||||
if (insn->dst_reg != q->insn.dst_reg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((q->flags & ISEARCH_TYPE) &&
|
||||
insn->itype != q->insn.itype)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int do_isearch(int addr, int len, const struct isearch_query *q)
|
||||
{
|
||||
u_int8_t *mbuf;
|
||||
const struct device *dev = device_active();
|
||||
int i;
|
||||
|
||||
if (len <= 0 || len > 0x10000 ||
|
||||
addr <= 0 || addr >= 0x10000 ||
|
||||
addr + len > 0x10000) {
|
||||
fprintf(stderr, "isearch: invalid memory range\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbuf = malloc(len);
|
||||
if (!mbuf) {
|
||||
fprintf(stderr, "isearch: couldn't allocate memory: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev->readmem(addr, mbuf, len) < 0) {
|
||||
fprintf(stderr, "isearch: couldn't read device memory\n");
|
||||
free(mbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
struct msp430_instruction insn;
|
||||
int count = dis_decode(mbuf + i, addr + i, len - i, &insn);
|
||||
|
||||
if (count >= 0 && isearch_match(&insn, q))
|
||||
disassemble(addr + i, mbuf + i, count);
|
||||
}
|
||||
|
||||
free(mbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_isearch(char **arg)
|
||||
{
|
||||
const static struct {
|
||||
const char *name;
|
||||
int (*func)(const char *term, char **arg,
|
||||
struct isearch_query *q);
|
||||
} term_handlers[] = {
|
||||
{"opcode", isearch_opcode},
|
||||
{"byte", isearch_bw},
|
||||
{"word", isearch_bw},
|
||||
{"jump", isearch_type},
|
||||
{"single", isearch_type},
|
||||
{"double", isearch_type},
|
||||
{"src", isearch_addr},
|
||||
{"dst", isearch_addr},
|
||||
{"srcreg", isearch_reg},
|
||||
{"dstreg", isearch_reg},
|
||||
{"srcmode", isearch_mode},
|
||||
{"dstmode", isearch_mode}
|
||||
};
|
||||
|
||||
struct isearch_query q;
|
||||
const char *addr_text;
|
||||
const char *len_text;
|
||||
int addr;
|
||||
int len;
|
||||
|
||||
addr_text = get_arg(arg);
|
||||
len_text = get_arg(arg);
|
||||
|
||||
if (!(addr_text && len_text)) {
|
||||
fprintf(stderr, "isearch: address and length expected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr_exp(addr_text, &addr) < 0 ||
|
||||
addr_exp(len_text, &len) < 0)
|
||||
return -1;
|
||||
|
||||
q.flags = 0;
|
||||
for (;;) {
|
||||
const char *term = get_arg(arg);
|
||||
int i;
|
||||
|
||||
if (!term)
|
||||
break;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(term_handlers); i++)
|
||||
if (!strcasecmp(term_handlers[i].name, term)) {
|
||||
if (term_handlers[i].func(term, arg, &q) < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!q.flags) {
|
||||
fprintf(stderr, "isearch: no query terms given "
|
||||
"(perhaps you mean \"dis\"?)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return do_isearch(addr, len, &q);
|
||||
}
|
||||
|
||||
static struct command isearch_command = {
|
||||
.name = "isearch",
|
||||
.func = cmd_isearch,
|
||||
.help =
|
||||
"isearch <address> <length> [options ...]\n"
|
||||
" Search for an instruction matching certain search terms. These\n"
|
||||
" terms may be any of the following:\n"
|
||||
" opcode <opcode>\n"
|
||||
" byte|word\n"
|
||||
" jump|single|double|noarg\n"
|
||||
" src <value>\n"
|
||||
" dst <value>\n"
|
||||
" srcreg <register>\n"
|
||||
" dstreg <register>\n"
|
||||
" srcmode R|I|S|&|@|+|#\n"
|
||||
" dstmode R|I|S|&|@|+|#\n"
|
||||
" For single-operand instructions, the operand is considered the\n"
|
||||
" destination operand.\n"
|
||||
};
|
||||
|
||||
void rtools_init(void)
|
||||
{
|
||||
register_command(&isearch_command);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* 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 RTOOLS_H_
|
||||
#define RTOOLS_H_
|
||||
|
||||
/* Register reverse-engineering tool commands. */
|
||||
void rtools_init(void);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue