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
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
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
|
bsl.o sim.o symmap.o gdb.o btree.o device.o rtools.o
|
||||||
$(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
$(CC) $(LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
147
dis.c
147
dis.c
|
@ -449,6 +449,70 @@ int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
msp430_op_t op;
|
||||||
|
const char *mnemonic;
|
||||||
|
} opcode_names[] = {
|
||||||
|
/* Single operand */
|
||||||
|
{MSP430_OP_RRC, "RRC"},
|
||||||
|
{MSP430_OP_SWPB, "SWPB"},
|
||||||
|
{MSP430_OP_RRA, "RRA"},
|
||||||
|
{MSP430_OP_SXT, "SXT"},
|
||||||
|
{MSP430_OP_PUSH, "PUSH"},
|
||||||
|
{MSP430_OP_CALL, "CALL"},
|
||||||
|
{MSP430_OP_RETI, "RETI"},
|
||||||
|
|
||||||
|
/* Jump */
|
||||||
|
{MSP430_OP_JNZ, "JNZ"},
|
||||||
|
{MSP430_OP_JZ, "JZ"},
|
||||||
|
{MSP430_OP_JNC, "JNC"},
|
||||||
|
{MSP430_OP_JC, "JC"},
|
||||||
|
{MSP430_OP_JN, "JN"},
|
||||||
|
{MSP430_OP_JL, "JL"},
|
||||||
|
{MSP430_OP_JGE, "JGE"},
|
||||||
|
{MSP430_OP_JMP, "JMP"},
|
||||||
|
|
||||||
|
/* Double operand */
|
||||||
|
{MSP430_OP_MOV, "MOV"},
|
||||||
|
{MSP430_OP_ADD, "ADD"},
|
||||||
|
{MSP430_OP_ADDC, "ADDC"},
|
||||||
|
{MSP430_OP_SUBC, "SUBC"},
|
||||||
|
{MSP430_OP_SUB, "SUB"},
|
||||||
|
{MSP430_OP_CMP, "CMP"},
|
||||||
|
{MSP430_OP_DADD, "DADD"},
|
||||||
|
{MSP430_OP_BIT, "BIT"},
|
||||||
|
{MSP430_OP_BIC, "BIC"},
|
||||||
|
{MSP430_OP_BIS, "BIS"},
|
||||||
|
{MSP430_OP_XOR, "XOR"},
|
||||||
|
{MSP430_OP_AND, "AND"},
|
||||||
|
|
||||||
|
/* Emulated instructions */
|
||||||
|
{MSP430_OP_ADC, "ADC"},
|
||||||
|
{MSP430_OP_BR, "BR"},
|
||||||
|
{MSP430_OP_CLR, "CLR"},
|
||||||
|
{MSP430_OP_CLRC, "CLRC"},
|
||||||
|
{MSP430_OP_CLRN, "CLRN"},
|
||||||
|
{MSP430_OP_CLRZ, "CLRZ"},
|
||||||
|
{MSP430_OP_DADC, "DADC"},
|
||||||
|
{MSP430_OP_DEC, "DEC"},
|
||||||
|
{MSP430_OP_DECD, "DECD"},
|
||||||
|
{MSP430_OP_DINT, "DINT"},
|
||||||
|
{MSP430_OP_EINT, "EINT"},
|
||||||
|
{MSP430_OP_INC, "INC"},
|
||||||
|
{MSP430_OP_INCD, "INCD"},
|
||||||
|
{MSP430_OP_INV, "INV"},
|
||||||
|
{MSP430_OP_NOP, "NOP"},
|
||||||
|
{MSP430_OP_POP, "POP"},
|
||||||
|
{MSP430_OP_RET, "RET"},
|
||||||
|
{MSP430_OP_RLA, "RLA"},
|
||||||
|
{MSP430_OP_RLC, "RLC"},
|
||||||
|
{MSP430_OP_SBC, "SBC"},
|
||||||
|
{MSP430_OP_SETC, "SETC"},
|
||||||
|
{MSP430_OP_SETN, "SETN"},
|
||||||
|
{MSP430_OP_SETZ, "SETZ"},
|
||||||
|
{MSP430_OP_TST, "TST"}
|
||||||
|
};
|
||||||
|
|
||||||
/* Return the mnemonic for an operation, if possible.
|
/* Return the mnemonic for an operation, if possible.
|
||||||
*
|
*
|
||||||
* If the argument is not a valid operation, this function returns the
|
* If the argument is not a valid operation, this function returns the
|
||||||
|
@ -456,74 +520,11 @@ int dis_decode(u_int8_t *code, u_int16_t offset, u_int16_t len,
|
||||||
*/
|
*/
|
||||||
static const char *msp_op_name(msp430_op_t op)
|
static const char *msp_op_name(msp430_op_t op)
|
||||||
{
|
{
|
||||||
static const struct {
|
|
||||||
msp430_op_t op;
|
|
||||||
const char *mnemonic;
|
|
||||||
} ops[] = {
|
|
||||||
/* Single operand */
|
|
||||||
{MSP430_OP_RRC, "RRC"},
|
|
||||||
{MSP430_OP_SWPB, "SWPB"},
|
|
||||||
{MSP430_OP_RRA, "RRA"},
|
|
||||||
{MSP430_OP_SXT, "SXT"},
|
|
||||||
{MSP430_OP_PUSH, "PUSH"},
|
|
||||||
{MSP430_OP_CALL, "CALL"},
|
|
||||||
{MSP430_OP_RETI, "RETI"},
|
|
||||||
|
|
||||||
/* Jump */
|
|
||||||
{MSP430_OP_JNZ, "JNZ"},
|
|
||||||
{MSP430_OP_JZ, "JZ"},
|
|
||||||
{MSP430_OP_JNC, "JNC"},
|
|
||||||
{MSP430_OP_JC, "JC"},
|
|
||||||
{MSP430_OP_JN, "JN"},
|
|
||||||
{MSP430_OP_JL, "JL"},
|
|
||||||
{MSP430_OP_JGE, "JGE"},
|
|
||||||
{MSP430_OP_JMP, "JMP"},
|
|
||||||
|
|
||||||
/* Double operand */
|
|
||||||
{MSP430_OP_MOV, "MOV"},
|
|
||||||
{MSP430_OP_ADD, "ADD"},
|
|
||||||
{MSP430_OP_ADDC, "ADDC"},
|
|
||||||
{MSP430_OP_SUBC, "SUBC"},
|
|
||||||
{MSP430_OP_SUB, "SUB"},
|
|
||||||
{MSP430_OP_CMP, "CMP"},
|
|
||||||
{MSP430_OP_DADD, "DADD"},
|
|
||||||
{MSP430_OP_BIT, "BIT"},
|
|
||||||
{MSP430_OP_BIC, "BIC"},
|
|
||||||
{MSP430_OP_BIS, "BIS"},
|
|
||||||
{MSP430_OP_XOR, "XOR"},
|
|
||||||
{MSP430_OP_AND, "AND"},
|
|
||||||
|
|
||||||
/* Emulated instructions */
|
|
||||||
{MSP430_OP_ADC, "ADC"},
|
|
||||||
{MSP430_OP_BR, "BR"},
|
|
||||||
{MSP430_OP_CLR, "CLR"},
|
|
||||||
{MSP430_OP_CLRC, "CLRC"},
|
|
||||||
{MSP430_OP_CLRN, "CLRN"},
|
|
||||||
{MSP430_OP_CLRZ, "CLRZ"},
|
|
||||||
{MSP430_OP_DADC, "DADC"},
|
|
||||||
{MSP430_OP_DEC, "DEC"},
|
|
||||||
{MSP430_OP_DECD, "DECD"},
|
|
||||||
{MSP430_OP_DINT, "DINT"},
|
|
||||||
{MSP430_OP_EINT, "EINT"},
|
|
||||||
{MSP430_OP_INC, "INC"},
|
|
||||||
{MSP430_OP_INCD, "INCD"},
|
|
||||||
{MSP430_OP_INV, "INV"},
|
|
||||||
{MSP430_OP_NOP, "NOP"},
|
|
||||||
{MSP430_OP_POP, "POP"},
|
|
||||||
{MSP430_OP_RET, "RET"},
|
|
||||||
{MSP430_OP_RLA, "RLA"},
|
|
||||||
{MSP430_OP_RLC, "RLC"},
|
|
||||||
{MSP430_OP_SBC, "SBC"},
|
|
||||||
{MSP430_OP_SETC, "SETC"},
|
|
||||||
{MSP430_OP_SETN, "SETN"},
|
|
||||||
{MSP430_OP_SETZ, "SETZ"},
|
|
||||||
{MSP430_OP_TST, "TST"}
|
|
||||||
};
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LEN(ops); i++)
|
for (i = 0; i < ARRAY_LEN(opcode_names); i++)
|
||||||
if (op == ops[i].op)
|
if (op == opcode_names[i].op)
|
||||||
return ops[i].mnemonic;
|
return opcode_names[i].mnemonic;
|
||||||
|
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
@ -745,3 +746,17 @@ void disassemble(u_int16_t offset, u_int8_t *data, int length)
|
||||||
data += count;
|
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 */
|
/* Print a disassembly on stdout */
|
||||||
void disassemble(u_int16_t offset, u_int8_t *buf, int length);
|
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
|
#endif
|
||||||
|
|
13
main.c
13
main.c
|
@ -29,6 +29,7 @@
|
||||||
#include "stab.h"
|
#include "stab.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
|
#include "rtools.h"
|
||||||
|
|
||||||
static void usage(const char *progname)
|
static void usage(const char *progname)
|
||||||
{
|
{
|
||||||
|
@ -70,6 +71,7 @@ int main(int argc, char **argv)
|
||||||
const char *bsl_device = NULL;
|
const char *bsl_device = NULL;
|
||||||
const struct device *msp430_dev = NULL;
|
const struct device *msp430_dev = NULL;
|
||||||
int opt;
|
int opt;
|
||||||
|
int ret = 0;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
int want_jtag = 0;
|
int want_jtag = 0;
|
||||||
int vcc_mv = 3000;
|
int vcc_mv = 3000;
|
||||||
|
@ -135,6 +137,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
parse_init();
|
parse_init();
|
||||||
gdb_init();
|
gdb_init();
|
||||||
|
rtools_init();
|
||||||
if (stab_init() < 0)
|
if (stab_init() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -171,8 +174,12 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* Process commands */
|
/* Process commands */
|
||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
while (optind < argc)
|
while (optind < argc) {
|
||||||
process_command(argv[optind++], 0);
|
if (process_command(argv[optind++], 0) < 0) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reader_loop();
|
reader_loop();
|
||||||
}
|
}
|
||||||
|
@ -180,5 +187,5 @@ int main(int argc, char **argv)
|
||||||
device_exit();
|
device_exit();
|
||||||
stab_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
|
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
|
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.
|
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]"
|
.IP "\fBmd\fR \fIaddress\fR [\fIlength\fR]"
|
||||||
Read the specified section of device memory and display it as a
|
Read the specified section of device memory and display it as a
|
||||||
canonical\-style hexdump. Both arguments may be address expressions. If
|
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