New opcodes and operations in AVR anal plugin. (#5783)

This commit is contained in:
Gerardo García Peña 2016-09-20 13:48:17 +02:00 committed by radare
parent 5a4d39b65a
commit 91cb15a3e7
3 changed files with 729 additions and 51 deletions

View File

@ -2112,6 +2112,49 @@ static int esil_swap(RAnalEsil *esil) {
return true;
}
static int __esil_generic_pick(RAnalEsil *esil, int rev) {
char *idx = r_anal_esil_pop (esil);
ut64 i;
int ret = false;
if (!idx || !r_anal_esil_get_parm (esil, idx, &i)) {
ERR ("esil_pick: invalid index number");
goto end;
}
if (!esil || !esil->stack) {
ERR ("esil_pick: stack not initialized");
goto end;
}
if (rev) {
i = esil->stackptr + (((st64) i) * -1);
}
if (esil->stackptr < i) {
ERR ("esil_pick: index out of stack bounds");
goto end;
}
if (!esil->stack[esil->stackptr-i]) {
ERR ("esil_pick: undefined element");
goto end;
}
if (!r_anal_esil_push (esil, esil->stack[esil->stackptr-i])) {
ERR ("ESIL stack is full");
esil->trap = 1;
esil->trap_code = 1;
goto end;
}
ret = true;
end:
free (idx);
return ret;
}
static int esil_pick(RAnalEsil *esil) {
return __esil_generic_pick (esil, 0);
}
static int esil_rpick(RAnalEsil *esil) {
return __esil_generic_pick (esil, 1);
}
// NOTE on following comparison functions:
// The push to top of the stack is based on a
// signed compare (as this causes least surprise to the users).
@ -2581,6 +2624,8 @@ static void r_anal_esil_setup_ops(RAnalEsil *esil) {
OP ("CLEAR", esil_clear);
OP ("DUP", esil_dup);
OP ("NUM", esil_num);
OP ("PICK", esil_pick);
OP ("RPICK", esil_rpick);
OP ("SWAP", esil_swap);
OP ("TRAP", esil_trap);
}

View File

@ -17,13 +17,551 @@ https://en.wikipedia.org/wiki/Atmel_AVR_instruction_set
#define AVR_SOFTCAST(x,y) (x+(y*0x100))
typedef struct _cpu_models_tag_ {
const char const *model;
int pc_bits;
int pc_mask;
int pc_size;
int eeprom_size;
} CPU_MODEL;
typedef void (*inst_handler_t) (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, int *fail, CPU_MODEL *cpu);
typedef struct _opcodes_tag_ {
const char const *name;
int mask;
int selector;
inst_handler_t handler;
int cycles;
int size;
int type;
} OPCODE_DESC;
#define CPU_MODEL_DECL(model, pc_bits, eeprom_sz) \
{ \
model, \
(pc_bits), \
(~((~0) << (pc_bits))), \
((pc_bits) >> 3) + (((pc_bits) & 0x07) ? 1 : 0), \
eeprom_sz \
}
#define INST_HANDLER(OPCODE_NAME) static void _inst__ ## OPCODE_NAME (RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, int *fail, CPU_MODEL *cpu)
#define INST_DECL(OP, M, SL, C, SZ, T) { #OP, (M), (SL), _inst__ ## OP, (C), (SZ), R_ANAL_OP_TYPE_ ## T }
#define INST_LAST { "unknown", 0, 0, (void *) 0, 2, 1, R_ANAL_OP_TYPE_UNK }
#define INST_CALL(OPCODE_NAME) _inst__ ## OPCODE_NAME (anal, op, addr, buf, len, fail, cpu)
#define INST_INVALID { *fail = 1; return; }
#define INST_ASSERT(x) { if (!(x)) { INST_INVALID; } }
#define ESIL_A(e, ...) r_strbuf_appendf (&op->esil, e, ##__VA_ARGS__)
CPU_MODEL cpu_models[] = {
CPU_MODEL_DECL ("ATmega48", 11, 512),
CPU_MODEL_DECL ("ATmega8", 12, 512),
CPU_MODEL_DECL ("ATmega88", 12, 512),
CPU_MODEL_DECL ("ATmega168", 13, 512),
CPU_MODEL_DECL ("ATmega640", 16, 512),
CPU_MODEL_DECL ("ATmega1280", 16, 512),
CPU_MODEL_DECL ("ATmega1281", 16, 512),
CPU_MODEL_DECL ("ATmega2560", 22, 512),
CPU_MODEL_DECL ("ATmega2561", 22, 512),
CPU_MODEL_DECL ((char *) 0, 16, 512)
};
void __generic_brxx(RAnalOp *op, const ut8 *buf, const char const *eval) {
op->jump = op->addr
+ ((((buf[0] & 0xf8) >> 2) | (buf[1] & 0x03) << 6)
| (buf[1] & 0x2 ? ~((int) 0x7f) : 0))
+ 2;
op->cycles = 1; // XXX: This is a bug, because depends on eval state,
// so it cannot be really be known until this
// instruction is executed by the ESIL interpreter!!!
// In case of evaluating to true, this instruction
// needs 2 cycles, elsewhere it needs only 1 cycle.
ESIL_A ("%s,?{,%"PFMT64d",pc,=,}", eval, op->jump); // if eval => jump
}
void __generic_bitop_flags(RAnalOp *op) {
ESIL_A ("0,vf,=,"); // V
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("vf,nf,^,sf,=,"); // S
}
INST_HANDLER (adc) { // ADC Rd, Rr
int d = ((buf[0] & 0xf0) >> 4) | ((buf[1] & 1) << 4);
int r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
ESIL_A ("r%d,cf,+,r%d,+,", r, d); // Rd + Rr + C
// FLAGS:
ESIL_A ("r%d,0x08,&,!,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!," "&,"
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!," "&,"
"|,|,hf,=,",
d, r, r, d);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, r, d, r);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!," "&,"
"|,|,cf,=,",
d, r, r, d);
ESIL_A ("vf,nf,^,sf,=,"); // S
ESIL_A ("r%d,=,", d); // Rd = result
}
INST_HANDLER (add) { // ADD Rd, Rr
int d = ((buf[0] & 0xf0) >> 4) | ((buf[1] & 1) << 4);
int r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
ESIL_A ("r%d,r%d,+,", r, d); // Rd + Rr
// FLAGS:
ESIL_A ("r%d,0x08,&,!,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!," "&,"
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!," "&,"
"|,|,hf,=,",
d, r, r, d);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, r, d, r);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!," "&,"
"|,|,cf,=,",
d, r, r, d);
ESIL_A ("vf,nf,^,sf,=,"); // S
ESIL_A ("r%d,=,", d); // Rd = result
}
INST_HANDLER (adiw) { // ADIW Rd+1:Rd, K
int d = ((buf[0] & 0x30) >> 3) + 24;
int k = (buf[0] & 0xf) | ((buf[0] >> 2) & 0x30);
ESIL_A ("r%d:r%d,%d,+,", d + 1, d, k); // Rd+1:Rd + Rr
// FLAGS:
ESIL_A ("r%d,0x80,&,!," // V
"0,RPICK,0x8000,&,!,!,"
"&,", d + 1);
ESIL_A ("0,RPICK,0x8000,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!,!," // C
"0,RPICK,0x8000,&,!,"
"&,", d + 1);
ESIL_A ("vf,nf,^,sf,=,"); // S
ESIL_A ("r%d:r%d,=,", d + 1, d); // Rd = result
}
INST_HANDLER (and) { // AND Rd, Rr
int d = ((buf[0] & 0xf0) >> 4) | ((buf[1] & 1) << 4);
int r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
ESIL_A ("r%d,r%d,&,", r, d); // 0: Rd & Rr
__generic_bitop_flags(op); // up flags
ESIL_A ("r%d,=,", d); // Rd = Result
}
INST_HANDLER (andi) { // ANDI Rd, K
int d = ((buf[0] & 0xf0) >> 4) + 16;
int k = (buf[1] & 0xf0) | (buf[0] & 0x0f);
ESIL_A ("%d,r%d,&,", k, d); // 0: Rd & Rr
__generic_bitop_flags(op); // up flags
ESIL_A ("r%d,=,", d); // Rd = Result
}
INST_HANDLER (bclr) { // BCLR s
// CLC
// CLH
// CLI
// CLN
// CLR
// CLS
// CLT
// CLV
// CLZ
int s = (buf[0] >> 4) & 0x7;
ESIL_A ("0xff,%d,1,<<,^,sreg,&=", s);
}
INST_HANDLER (bset) { // BSET s
// SEC
// SEH
// SEI
// SEN
// SER
// SES
// SET
// SEV
// SEZ
int s = (buf[0] >> 4) & 0x7;
ESIL_A ("%d,1,<<,sreg,|=", s);
}
INST_HANDLER (breq) { __generic_brxx (op, buf, "zf"); } // BREQ raddr
INST_HANDLER (brge) { __generic_brxx (op, buf, "nf,vf,^,!"); } // BRGE raddr
INST_HANDLER (brhc) { __generic_brxx (op, buf, "hf,!"); } // BRHC raddr
INST_HANDLER (brhs) { __generic_brxx (op, buf, "hf"); } // BRHS raddr
INST_HANDLER (brid) { __generic_brxx (op, buf, "if,!"); } // BRID raddr
INST_HANDLER (brie) { __generic_brxx (op, buf, "if"); } // BRIE raddr
INST_HANDLER (brlo) { __generic_brxx (op, buf, "cf"); } // BRLO raddr
INST_HANDLER (brlt) { __generic_brxx (op, buf, "nf,vf,^"); } // BRLT raddr
INST_HANDLER (brmi) { __generic_brxx (op, buf, "nf"); } // BRMI raddr
INST_HANDLER (brne) { __generic_brxx (op, buf, "zf,!"); } // BRNE raddr
INST_HANDLER (brpl) { __generic_brxx (op, buf, "nf,!"); } // BRPL raddr
INST_HANDLER (brsh) { __generic_brxx (op, buf, "cf,!"); } // BRSH raddr
INST_HANDLER (brtc) { __generic_brxx (op, buf, "tf,!"); } // BRTC raddr
INST_HANDLER (brts) { __generic_brxx (op, buf, "tf"); } // BRTS raddr
INST_HANDLER (brvc) { __generic_brxx (op, buf, "vf,!"); } // BRVC raddr
INST_HANDLER (brvs) { __generic_brxx (op, buf, "vf"); } // BRVS raddr
INST_HANDLER (call) { // CALL addr
op->jump = (buf[2] << 1)
| (buf[3] << 9)
| (buf[1] & 0x01) << 23
| (buf[0] & 0x01) << 17
| (buf[0] & 0xf0) << 14;
op->cycles = cpu->pc_bits <= 16 ? 3 : 4;
if (!strncasecmp (anal->cpu, "ATxmega", 7)) {
op->cycles--; // ATxmega optimizes one cycle
}
ESIL_A ("pc,"); // esil is already pointing to
// next instruction (@ret)
ESIL_A ("sp,-%d,+,", cpu->pc_size - 1); // and dec by (PC_SIZE-1) SP
ESIL_A ("_sram,+,"); // and point to the SRAM!
ESIL_A ("=[%d],", cpu->pc_size); // store ret@ in stack
ESIL_A ("sp,-%d,+,", cpu->pc_size); // decrement stack pointer
ESIL_A ("sp,=,"); // store SP
ESIL_A ("%"PFMT64d",pc,=,", op->jump); // jump!
}
INST_HANDLER (cp) { // CP Rd, Rr
int r = (buf[0] & 0x0f) | ((buf[1] << 3) & 0x10);
int d = ((buf[0] >> 4) & 0x0f) | ((buf[1] << 4) & 0x10);
ESIL_A ("r%d,r%d,-,", r, d); // do Rd - Rr
// FLAGS:
ESIL_A ("r%d,0x08,&,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!,!," "&,"
"r%d,0x08,&,!," "0,RPICK,0x08,&,!,!," "&,"
"|,|,hf,=,",
d, r, d, r);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, r, d, r);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!,!," "&,"
"r%d,0x80,&,!," "0,RPICK,0x80,&,!,!," "&,"
"|,|,cf,=,",
d, r, d, r);
ESIL_A ("vf,nf,^,sf,=,"); // S
}
INST_HANDLER (cpc) { // CPC Rd, Rr
int r = (buf[0] & 0x0f) | ((buf[1] << 3) & 0x10);
int d = ((buf[0] >> 4) & 0x0f) | ((buf[1] << 4) & 0x10);
ESIL_A ("r%d,cf,-,r%d,-,", r, d); // Rd - Rr - C
// FLAGS:
ESIL_A ("r%d,0x08,&,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!,!," "&,"
"r%d,0x08,&,!," "0,RPICK,0x08,&,!,!," "&,"
"|,|,hf,=,",
d, r, d, r);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, r, d, r);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,&,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!,!," "&,"
"r%d,0x80,&,!," "0,RPICK,0x80,&,!,!," "&,"
"|,|,cf,=,",
d, r, d, r);
ESIL_A ("vf,nf,^,sf,=,"); // S
}
INST_HANDLER (cpi) { // CPI Rd, K
int d = (buf[1] & 0xf) >> 4;
int k = ((buf[0] & 0xf) << 4) | (buf[1] & 0xf);
ESIL_A ("%d,r%d,-,", k, d); // Rd - k
// FLAGS:
ESIL_A ("r%d,0x08,&,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!,!," "&,"
"r%d,0x08,&,!," "0,RPICK,0x08,&,!,!," "&,"
"|,|,hf,=,",
d, k, d, k);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, k, d, k);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,=,"); // Z
ESIL_A ("r%d,0x80,&,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!,!," "&,"
"r%d,0x80,&,!," "0,RPICK,0x80,&,!,!," "&,"
"|,|,cf,=,",
d, k, d, k);
ESIL_A ("vf,nf,^,sf,=,"); // S
}
INST_HANDLER (eor) { // EOR Rd, Rr
// CLR Rd
int d = ((buf[0] & 0xf0) >> 4) | ((buf[1] & 1) << 4);
int r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
ESIL_A ("r%d,r%d,^,", r, d); // 0: Rd ^ Rr
__generic_bitop_flags(op); // up flags
ESIL_A ("r%d,=,", d); // Rd = Result
}
INST_HANDLER (jmp) { // JMP addr
op->jump = (buf[2] << 1)
| (buf[3] << 9)
| (buf[1] & 0x01) << 23
| (buf[0] & 0x01) << 17
| (buf[0] & 0xf0) << 14;
op->cycles = 3;
ESIL_A ("%"PFMT64d",pc,=,", op->jump); // jump!
}
INST_HANDLER (ldi) { // LDI Rd, K
int k = (buf[0] & 0xf) + ((buf[1] & 0xf) << 4);
int d = ((buf[0] & 0xf0) >> 4) + 16;
ESIL_A ("0x%x,r%d,=,", k, d);
}
INST_HANDLER (in) { // IN Rd, A
int r = ((buf[0] >> 4) & 0x0f) | ((buf[1] & 0x01) << 4);
int a = (buf[0] & 0x0f) | ((buf[1] & 0x6) << 3);
op->type2 = 0;
op->val = a;
switch (a) {
case 0x3f: /* SREG */ ESIL_A ("sreg," "r%d," "=,", r); break;
case 0x3e: /* SPH */ ESIL_A ("sph," "r%d," "=,", r); break;
case 0x3d: /* SPL */ ESIL_A ("spl," "r%d," "=,", r); break;
default:
ESIL_A ("2,$,");
}
}
INST_HANDLER (movw) { // // MOVW Rd+1:Rd, Rr+1Rrd
int d = (buf[0] & 0xf0) >> 3;
int r = (buf[0] & 0x0f) << 1;
ESIL_A ("r%d,r%d,=,r%d,r%d,=,", r, d, r + 1, d + 1);
}
INST_HANDLER (nop) { // NOP
}
INST_HANDLER (out) { // OUT A, Rr
int r = ((buf[0] >> 4) & 0x0f) | ((buf[1] & 0x01) << 4);
int a = (buf[0] & 0x0f) | ((buf[1] & 0x6) << 3);
op->type2 = 1;
op->val = a;
switch (a) {
case 0x3f: /* SREG */ ESIL_A ("r%d," "sreg," "=,", r); break;
case 0x3e: /* SPH */ ESIL_A ("r%d," "sph," "=,", r); break;
case 0x3d: /* SPL */ ESIL_A ("r%d," "spl," "=,", r); break;
default:
ESIL_A ("2,$,");
}
}
INST_HANDLER (pop) { // POP Rd
int d = ((buf[1] & 0x1) << 4) | ((buf[0] & 0xf0) >> 4);
ESIL_A ("1,sp,+=," // increment stack pointer
"sp,_sram,+,[1]," // load SRAM[sp]
"r%d,=,", // store in Rd
d);
}
INST_HANDLER (push) { // PUSH Rr
int r = ((buf[1] & 0x1) << 4) | ((buf[0] & 0xf0) >> 4);
op->cycles = !strncasecmp (anal->cpu, "ATxmega", 7)
? 1 // ATxmega optimizes one cycle
: 2;
ESIL_A ("r%d," // load Rr
"sp,_sram,+," // calc SRAM[sp]
"=[1]," // store Rr in stack
"-1,sp,+=,", // decrement stack pointer
r);
}
INST_HANDLER (rcall) { // RCALL addr
op->jump = op->addr
+ (((((buf[1] & 0xf) << 8) | buf[0]) << 1)
| (((buf[1] & 0x8) ? ~((int) 0x1ff) : 0)))
+ 2;
if (!strncasecmp (anal->cpu, "ATtiny", 6)) {
op->cycles = 4; // ATtiny is always slow
} else {
// PC size decides required runtime!
op->cycles = cpu->pc_bits <= 16 ? 3 : 4;
if (!strncasecmp (anal->cpu, "ATxmega", 7)) {
op->cycles--; // ATxmega optimizes one cycle
}
}
ESIL_A ("pc," // esil is already pointing to the
// next instruction (@ret)
"sp,-%d,+," // and dec by (PC_SIZE-1) SP
"_sram,+," // and point to the SRAM!
"=[%d]," // store ret@ in stack
"sp,-%d,+," // decrement stack pointer
"sp,=," // store SP
"%"PFMT64d",pc,=,", // jump!
cpu->pc_size - 1, cpu->pc_size,
cpu->pc_size, op->jump);
}
INST_HANDLER (ret) { // RET
if (cpu->pc_size > 2) { // if we have a bus bigger than 16 bit
op->cycles++; // (i.e. a 22-bit bus), add one extra cycle
}
op->eob = true;
ESIL_A ("sp," // load stack pointer
"sp,1,+," // and inc by 1 SP
"_sram,+," // and point to the SRAM!
"[%d]," // read ret@ from the stack
"pc,=," // update PC with [SP]
"sp,%d,+," // post increment stack pointer
"sp,=,", // store incremented SP
cpu->pc_size, cpu->pc_size);
}
INST_HANDLER (reti) { // RETI
//XXX: There are not privileged instructions in ATMEL/AVR
op->family = R_ANAL_OP_FAMILY_PRIV;
// first perform a standard 'ret'
INST_CALL (ret);
// RETI: The I-bit is cleared by hardware after an interrupt
// has occurred, and is set by the RETI instruction to enable
// subsequent interrupts
ESIL_A ("1,if,=,");
}
INST_HANDLER (rjmp) {
op->jump = op->addr
+ (((typeof(op->jump)) (((buf[1] & 0xf) << 9) | (buf[0] << 1)))
| (buf[1] & 0x8 ? ~((typeof(op->jump)) 0x1fff) : 0))
+ 2;
ESIL_A ("%"PFMT64d",pc,=,", op->jump);
}
INST_HANDLER (sbc) { // SBC Rd, Rr
int r = (buf[1] & 0x0f) | ((buf[0] & 0x2) >> 1);
int d = ((buf[1] & 0xf0) >> 4) | (buf[0] & 0x1);
ESIL_A ("r%d,cf,-,r%d,-,", r, d); // Rd - Rr - C
// FLAGS:
ESIL_A ("r%d,0x08,&,!," "r%d,0x08,&,!,!," "&," // H
"r%d,0x08,&,!,!," "0,RPICK,0x08,&,!,!," "&,"
"r%d,0x08,&,!," "0,RPICK,0x08,&,!,!," "&,"
"|,|,hf,=,",
d, r, d, r);
ESIL_A ("r%d,0x80,&,!,!," "r%d,0x80,&,!," "&," // V
"" "0,RPICK,0x80,&,!," "&,"
"r%d,0x80,&,!," "r%d,0x80,&,!,!," "&,"
"" "0,RPICK,0x80,&,!,!," "&,"
"|,vf,=,",
d, r, d, r);
ESIL_A ("0,RPICK,0x80,&,!,!,nf,=,"); // N
ESIL_A ("0,RPICK,!,zf,&,zf,=,"); // Z (C)
ESIL_A ("r%d,0x80,&,!," "r%d,0x80,&,!,!," "&," // C
"r%d,0x80,&,!,!," "0,RPICK,0x80,&,!,!," "&,"
"r%d,0x80,&,!," "0,RPICK,0x80,&,!,!," "&,"
"|,|,cf,=,",
d, r, d, r);
ESIL_A ("vf,nf,^,sf,=,"); // S
ESIL_A ("r%d,=,", d); // Rd = Result
}
INST_HANDLER (st) { // ST X, Rr
// ST X+, Rr
// ST -X, Rr
int r = ((buf[1] & 0x01) << 4) | ((buf[0] >> 4) & 0x0f);
ESIL_A ("r%d,", r); // put register on stack
if ((buf[0] & 0xf) == 0xe) { // if predec X
ESIL_A ("1,x,-,x,=,");
}
ESIL_A ("x,_sram,+,=[1],"); // write byte @X
if ((buf[0] & 0xf) == 0xd) { // if postinc X
ESIL_A ("1,x,+,x,=,");
}
}
OPCODE_DESC opcodes[] = {
// op mask select cycles size type
INST_DECL (nop, 0xffff, 0x0000, 1, 2, NOP ), // NOP
INST_DECL (ret, 0xffff, 0x9508, 4, 2, RET ), // RET
INST_DECL (reti, 0xffff, 0x9518, 4, 2, RET ), // RETI
INST_DECL (bclr, 0xff8f, 0x9488, 1, 2, SWI ), // BCLR s
INST_DECL (bset, 0xff8f, 0x9408, 1, 2, SWI ), // BSET s
INST_DECL (adiw, 0xff00, 0x9600, 2, 2, ADD ), // ADIW Rd+1:Rd, K
INST_DECL (movw, 0xff00, 0x0100, 1, 2, MOV ), // MOVW Rd+1:Rd, Rr+1Rrd
INST_DECL (pop, 0xfe0f, 0x900f, 2, 2, POP ), // PUSH Rr
INST_DECL (push, 0xfe0f, 0x920f, 0, 2, PUSH ), // PUSH Rr
INST_DECL (call, 0xfe0e, 0x940e, 0, 4, CALL ), // CALL addr
INST_DECL (jmp, 0xfe0e, 0x940c, 2, 4, JMP ), // JMP addr
INST_DECL (breq, 0xfc07, 0xf001, 0, 2, CJMP ), // BREQ addr
INST_DECL (brge, 0xfc07, 0xf404, 0, 2, CJMP ), // BRGE addr
INST_DECL (brhc, 0xfc07, 0xf405, 0, 2, CJMP ), // BRHC addr
INST_DECL (brhs, 0xfc07, 0xf005, 0, 2, CJMP ), // BRHS addr
INST_DECL (brid, 0xfc07, 0xf407, 0, 2, CJMP ), // BRID addr
INST_DECL (brie, 0xfc07, 0xf007, 0, 2, CJMP ), // BRIE addr
INST_DECL (brlo, 0xfc07, 0xf000, 0, 2, CJMP ), // BRLO addr
INST_DECL (brlt, 0xfc07, 0xf008, 0, 2, CJMP ), // BRLT addr
INST_DECL (brmi, 0xfc07, 0xf002, 0, 2, CJMP ), // BRMI addr
INST_DECL (brne, 0xfc07, 0xf401, 0, 2, CJMP ), // BRNE addr
INST_DECL (brpl, 0xfc07, 0xf402, 0, 2, CJMP ), // BRPL addr
INST_DECL (brsh, 0xfc07, 0xf400, 0, 2, CJMP ), // BRSH addr
INST_DECL (brtc, 0xfc07, 0xf405, 0, 2, CJMP ), // BRTC addr
INST_DECL (brts, 0xfc07, 0xf005, 0, 2, CJMP ), // BRTS addr
INST_DECL (brvc, 0xfc07, 0xf403, 0, 2, CJMP ), // BRVC addr
INST_DECL (brvs, 0xfc07, 0xf003, 0, 2, CJMP ), // BRVS addr
INST_DECL (adc, 0xfc00, 0x1c00, 1, 2, ADD ), // ADC Rd, Rr
INST_DECL (add, 0xfc00, 0x0c00, 1, 2, ADD ), // ADD Rd, Rr
INST_DECL (cp, 0xfc00, 0x1400, 1, 2, CMP ), // CP Rd, Rr
INST_DECL (cpc, 0xfc00, 0x0400, 1, 2, CMP ), // CPC Rd, Rr
INST_DECL (and, 0xfc00, 0x2000, 1, 2, AND ), // AND Rd, Rr
INST_DECL (andi, 0xf000, 0x7000, 1, 2, AND ), // ANDI Rd, K
INST_DECL (eor, 0xfc00, 0x2400, 1, 2, XOR ), // EOR Rd, Rr
INST_DECL (sbc, 0xfc00, 0x0800, 1, 2, SUB ), // SBC Rd, Rr
INST_DECL (in, 0xf800, 0xb000, 1, 2, IO ), // IN Rd, A
INST_DECL (out, 0xf800, 0xb800, 1, 2, IO ), // OUT A, Rr
INST_DECL (st, 0xf00f, 0x900c, 2, 2, STORE ), // ST X, Rr
INST_DECL (st, 0xf00c, 0x900d, 2, 2, STORE ), // ST X+, Rr
INST_DECL (st, 0xf00c, 0x900e, 2, 2, STORE ), // ST -X, Rr
INST_DECL (cpi, 0xf000, 0x3000, 1, 2, CMP ), // CPI Rd, K
INST_DECL (rcall, 0xf000, 0xd000, 0, 2, CALL ), // RCALL addr
INST_DECL (rjmp, 0xf000, 0xc000, 2, 2, JMP ), // RJMP addr
INST_DECL (ldi, 0xf000, 0xe000, 1, 2, LOAD ), // LDI Rd, K
INST_LAST
};
static ut64 rjmp_dest(ut64 addr, const ut8* b) {
uint16_t data = (b[0] + (b[1] << 8)) & 0xfff;
int32_t op = data;
ut32 op = data;
op <<= 1;
if (op & 0x1000) {
short val = (~op) & 0xfff;
return (ut64)(addr - val + 1);
return (ut64) (addr - val + 1);
}
return addr + op + 2;
}
@ -33,11 +571,15 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
int imm = 0, imm2 = 0, d, r, k;
ut8 kbuf[4];
ut16 ins = AVR_SOFTCAST (buf[0], buf[1]);
char *arg, str[32];
char *arg, str[32], *t;
CPU_MODEL *cpu;
OPCODE_DESC *opcode_desc;
if (!op) {
return 2;
}
memset (op, '\0', sizeof (RAnalOp));
op->addr = addr;
op->type = R_ANAL_OP_TYPE_UNK;
op->ptr = UT64_MAX;
op->val = UT64_MAX;
@ -45,6 +587,70 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
op->fail = UT64_MAX;
op->refptr = 0;
op->nopcode = 1; // Necessary??
op->size = 2; // by default most opcodes are 2 bytes len
op->cycles = 1; // by default most opcodes only use 1 cpu cycle
op->family = R_ANAL_OP_FAMILY_CPU;
r_strbuf_init (&op->esil);
op->delay = 0;
op->type = R_ANAL_OP_TYPE_UNK;
// select cpu info
for (cpu = cpu_models; cpu->model; cpu++) {
if (!strcasecmp (anal->cpu, cpu->model)) {
break;
}
}
// set memory layout registers
if (anal->esil) {
r_anal_esil_reg_write (anal->esil, "_eeprom", (1 << cpu->pc_bits));
r_anal_esil_reg_write (anal->esil, "_sram", (1 << cpu->pc_bits) + cpu->eeprom_size);
}
// process opcode
for (opcode_desc = opcodes; opcode_desc->handler; opcode_desc++) {
if ((ins & opcode_desc->mask) == opcode_desc->selector) {
int fail = 0;
// copy default cycles/size values
op->cycles = opcode_desc->cycles;
op->size = opcode_desc->size;
op->type = opcode_desc->type;
// start void esil expression
r_strbuf_setf (&op->esil, "");
// handle opcode
opcode_desc->handler (anal, op, addr, buf, len, &fail, cpu);
if (fail) {
goto INVALID_OP;
}
if (op->cycles <= 0) {
eprintf ("opcode %s @%"PFMT64x" returned 0 cycles.\n", opcode_desc->name, op->addr);
}
if (op->fail <= 0) {
op->fail = addr + op->size;
}
// remove trailing coma (COMETE LA COMA)
t = r_strbuf_get (&op->esil);
if (t && strlen (t) > 0) {
t[strlen(t) - 1] = '\0';
}
return op->size;
}
}
// ignore reserved opcodes (if they have not been caught by the previous loop)
if ((ins & 0xff00) == 0xff00 && (ins & 0xf) > 7) {
goto INVALID_OP;
}
// old and slow implementation
// NOTE: This block should collapse along time... it depends on
// avrdis which does not seem the most efficient and easy way
// to emulate the CPU details :P
op->size = avrdis (str, addr, buf, len);
r_strbuf_init (&op->esil);
arg = strchr (str, ' ');
@ -108,7 +714,7 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
if ((buf[1] & 0xf0) == 0x30) { //CPI
op->type = R_ANAL_OP_TYPE_CMP;
op->cycles = 1;
r_strbuf_setf (&op->esil, "0x%x,r%d,==,$z,ZF,=,$b3,HF,=,$b8,CF,=$o,VF,=,0x%x,r%d,-,0x80,&,!,!,NF,=,VF,NF,^,SF,=", k, d, k, d); //check VF here
r_strbuf_setf (&op->esil, "0x%x,r%d,==,$z,zf,=,$b3,hf,=,$b8,cf,=$o,vf,=,0x%x,r%d,-,0x80,&,!,!,nf,=,vf,nf,^,sf,=", k, d, k, d); //check vf here
}
d = ((buf[0] & 0xf0) >> 4) | ((buf[1] & 1) << 4);
r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
@ -116,22 +722,22 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
op->type = R_ANAL_OP_TYPE_ADD;
op->cycles = 1;
if (buf[1] & 0x10)
r_strbuf_setf (&op->esil, "r%d,r%d,+=,$c7,CF,=,$c3,HF,=,$o,VF,=,r%d,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,VF,NF,^,SF,=", r, d, d, d, d);
else r_strbuf_setf (&op->esil, "r%d,NUM,r%d,CF,+=,r%d,r%d,+=,$c7,CF,=,$c3,HF,=,$o,VF,=,r%d,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,VF,NF,^,SF,=,r%d,=", r, r, r, d, d, d, r);
r_strbuf_setf (&op->esil, "r%d,r%d,+=,$c7,cf,=,$c3,hf,=,$o,vf,=,r%d,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,vf,nf,^,sf,=", r, d, d, d, d);
else r_strbuf_setf (&op->esil, "r%d,NUM,r%d,cf,+=,r%d,r%d,+=,$c7,cf,=,$c3,hf,=,$o,vf,=,r%d,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,vf,nf,^,sf,=,r%d,=", r, r, r, d, d, d, r);
}
if ((buf[1] & 0xec) == 8) { //SUB + SBC
op->type = R_ANAL_OP_TYPE_SUB;
op->cycles = 1;
if (buf[1] & 0x10)
r_strbuf_setf (&op->esil, "r%d,r%d,-=,$b8,CF,=,$b3,HF,=,$o,VF,=,r%d,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,VF,NF,^,SF,=", r, d, d, d, d);
else r_strbuf_setf (&op->esil, "r%d,NUM,r%d,CF,+=,r%d,r%d,-=,$b8,CF,=,$b3,HF,=,$o,VF,=,r%d,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,VF,NF,^,SF,=,r%d,=", r, r, r, d, d, d, r);
r_strbuf_setf (&op->esil, "r%d,r%d,-=,$b8,cf,=,$b3,hf,=,$o,vf,=,r%d,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,vf,nf,^,sf,=", r, d, d, d, d);
else r_strbuf_setf (&op->esil, "r%d,NUM,r%d,cf,+=,r%d,r%d,-=,$b8,cf,=,$b3,hf,=,$o,vf,=,r%d,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,vf,nf,^,sf,=,r%d,=", r, r, r, d, d, d, r);
}
if ((buf[1] & 0xec) == 4) { //CP + CPC
op->type = R_ANAL_OP_TYPE_CMP;
op->cycles = 1;
if (buf[1] & 0xf0) //CP
r_strbuf_setf (&op->esil, "r%d,r%d,==,$z,ZF,=,$b8,CF,=,$b3,HF,=,$o,VF,=,r%d,r%d,-,0x80,&,!,!,NF,=,VF,NF,^,SF,=", r, d, r, d); //check VF here
else r_strbuf_setf (&op->esil, "r%d,CF,r%d,-,0xff,&,-,0x80,&,!,!,NF,=,r%d,CF,r%d,-,0xff,&,==,$z,ZF,=,$b8,CF,=,$b3,HF,=,$o,VF,=,VF,NF,^,SF,=", r, d, r, d);
r_strbuf_setf (&op->esil, "r%d,r%d,==,$z,zf,=,$b8,cf,=,$b3,hf,=,$o,vf,=,r%d,r%d,-,0x80,&,!,!,nf,=,vf,nf,^,sf,=", r, d, r, d); //check vf here
else r_strbuf_setf (&op->esil, "r%d,cf,r%d,-,0xff,&,-,0x80,&,!,!,nf,=,r%d,cf,r%d,-,0xff,&,==,$z,zf,=,$b8,cf,=,$b3,hf,=,$o,vf,=,vf,nf,^,sf,=", r, d, r, d);
}
switch (buf[1] & 0xfc) {
case 0x10: //CPSE
@ -147,17 +753,17 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
case 0x20: //AND
op->type = R_ANAL_OP_TYPE_AND;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,r%d,&=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,NF,SF,=,0,VF,=", r, d, d);
r_strbuf_setf (&op->esil, "r%d,r%d,&=,$z,zf,=,r%d,0x80,&,!,!,nf,=,nf,sf,=,0,vf,=", r, d, d);
break;
case 0x24: //EOR
op->type = R_ANAL_OP_TYPE_XOR;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,r%d,^=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,NF,SF,=,0,VF,=", r, d, d);
r_strbuf_setf (&op->esil, "r%d,r%d,^=,$z,zf,=,r%d,0x80,&,!,!,nf,=,nf,sf,=,0,vf,=", r, d, d);
break;
case 0x28: //OR
op->type = R_ANAL_OP_TYPE_OR;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,r%d,|=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,NF,SF,=,0,VF,=", r, d, d);
r_strbuf_setf (&op->esil, "r%d,r%d,|=,$z,zf,=,r%d,0x80,&,!,!,nf,=,nf,sf,=,0,vf,=", r, d, d);
break;
case 0x2c: //MOV
op->type = R_ANAL_OP_TYPE_MOV;
@ -194,12 +800,12 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
case 0: //COM
op->type = R_ANAL_OP_TYPE_CPL;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,0xff,-,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,NF,SF,=,0,VF,=,1,CF,=", d, d, d);
r_strbuf_setf (&op->esil, "r%d,0xff,-,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,nf,sf,=,0,vf,=,1,cf,=", d, d, d);
break;
case 1: //NEG
op->type = R_ANAL_OP_TYPE_CPL;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,NUM,0,r%d,=,r%d,-=,$b3,HF,=,$b8,CF,=,CF,!,ZF,=,r%d,0x80,&,!,!,NF,=,r%d,0x80,==,$z,VF,=,NF,VF,^,SF,=", d, d, d, d); //Hack for accessing internal vars
r_strbuf_setf (&op->esil, "r%d,NUM,0,r%d,=,r%d,-=,$b3,hf,=,$b8,cf,=,cf,!,zf,=,r%d,0x80,&,!,!,nf,=,r%d,0x80,==,$z,vf,=,nf,vf,^,sf,=", d, d, d, d); //Hack for accessing internal vars
break;
case 2: //SWAP
op->type = R_ANAL_OP_TYPE_ROL;
@ -209,27 +815,27 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
case 3: //INC
op->type = R_ANAL_OP_TYPE_ADD;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,1,+,0xff,&,r%d,=,$z,ZF,=,r%d,0x80,&,!,!,NF,=,r%d,0x80,==,$z,VF,=,NF,VF,^,SF,=", d, d, d, d);
r_strbuf_setf (&op->esil, "r%d,1,+,0xff,&,r%d,=,$z,zf,=,r%d,0x80,&,!,!,nf,=,r%d,0x80,==,$z,vf,=,nf,vf,^,sf,=", d, d, d, d);
break;
case 5: //ASR
op->type = R_ANAL_OP_TYPE_SAR;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,1,&,CF,=,1,r%d,>>,0x80,r%d,&,|,r%d,=,$z,ZF,=,r%d,0x80,&,NF,=,CF,NF,^,VF,=,NF,VF,^,SF,=", d, d, d, d, d);
r_strbuf_setf (&op->esil, "r%d,1,&,cf,=,1,r%d,>>,0x80,r%d,&,|,r%d,=,$z,zf,=,r%d,0x80,&,nf,=,cf,nf,^,vf,=,nf,vf,^,sf,=", d, d, d, d, d);
break;
case 6: //LSR
op->type = R_ANAL_OP_TYPE_SHR;
op->cycles = 1;
r_strbuf_setf (&op->esil, "r%d,1,&,CF,=,1,r%d,>>=,$z,ZF,=,0,NF,=,CF,VF,=,CF,SF,=", d, d);
r_strbuf_setf (&op->esil, "r%d,1,&,cf,=,1,r%d,>>=,$z,zf,=,0,nf,=,cf,vf,=,cf,sf,=", d, d);
break;
case 7: //ROR
op->type = R_ANAL_OP_TYPE_ROR;
op->cycles = 1;
r_strbuf_setf (&op->esil, "CF,NF,=,r%d,1,&,7,CF,<<,1,r%d,>>,|,r%d,=,$z,ZF,=,CF,=,NF,CF,^,VF,=,NF,VF,^,SF,=", d, d, d);
r_strbuf_setf (&op->esil, "cf,nf,=,r%d,1,&,7,cf,<<,1,r%d,>>,|,r%d,=,$z,zf,=,cf,=,nf,cf,^,vf,=,nf,vf,^,sf,=", d, d, d);
break;
case 10: //DEC
op->type = R_ANAL_OP_TYPE_SUB;
op->cycles = 1;
r_strbuf_setf (&op->esil, "1,r%d,-=,$z,ZF,=,r%d,0x80,&,NF,=,r%d,0x80,==,$z,VF,=,NF,VF,^,SF,=", d, d, d);
r_strbuf_setf (&op->esil, "1,r%d,-=,$z,zf,=,r%d,0x80,&,nf,=,r%d,0x80,==,$z,vf,=,nf,vf,^,sf,=", d, d, d);
break;
case 11:
if (d < 16) { //DES
@ -288,7 +894,7 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
memcpy (kbuf, buf+2, 2);
op->size = 4;
//anal->iob.read_at (anal->iob.io, addr+2, kbuf, 2);
op->jump = AVR_SOFTCAST(kbuf[0],kbuf[1])*2;
op->jump = AVR_SOFTCAST (kbuf[0],kbuf[1])*2;
} else {
op->size = 0;
return -1;
@ -312,7 +918,7 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
op->fail = op->addr + 4;
anal->iob.read_at (anal->iob.io, addr + 2, kbuf, 2);
// TODO: check return value
op->jump = AVR_SOFTCAST(kbuf[0], kbuf[1]) * 2;
op->jump = AVR_SOFTCAST (kbuf[0], kbuf[1]) * 2;
//eprintf("addr: %x inst: %x dest: %x fail:%x\n", op->addr, *ins, op->jump, op->fail);
}
if ((buf[1] & 0xf0) == 0xc0) { // rjmp (relative)
@ -335,6 +941,19 @@ static int avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len)
op->eob = true;
}
return op->size;
INVALID_OP:
// An unknown or invalid option has appeared.
// -- Throw pokeball!
op->type = R_ANAL_OP_TYPE_UNK;
op->family = R_ANAL_OP_FAMILY_UNKNOWN;
op->size = 2;
op->cycles = 1;
// launch esil trap (for communicating upper layers about this weird
// and stinky situation
r_strbuf_set (&op->esil, "1,$");
return op->size;
}
static int avr_custom_des (RAnalEsil *esil) {
@ -369,6 +988,7 @@ static int esil_avr_init (RAnalEsil *esil) {
if (!esil)
return false;
r_anal_esil_set_op (esil, "des", avr_custom_des);
return true;
}
@ -378,7 +998,7 @@ static int esil_avr_fini (RAnalEsil *esil) {
static int set_reg_profile(RAnal *anal) {
const char *p =
"=PC pc\n"
"=PC pcl\n"
"=SP sp\n"
// explained in http://www.nongnu.org/avr-libc/user-manual/FAQ.html
// and http://www.avrfreaks.net/forum/function-calling-convention-gcc-generated-assembly-file
@ -429,39 +1049,45 @@ RAMPX, RAMPY, RAMPZ, RAMPD and EIND:
"gpr r30 .8 30 0\n"
"gpr r31 .8 31 0\n"
// 16 bit overlapped registers for 16 bit math
"gpr r25:r24 .16 24 0\n"
"gpr r27:r26 .16 26 0\n"
"gpr r29:r28 .16 28 0\n"
"gpr r31:r30 .16 30 0\n"
// 16 bit overlapped registers for memory addressing
"gpr x .16 26 0\n"
"gpr y .16 28 0\n"
"gpr z .16 30 0\n"
// program counter
// NOTE: program counter size in AVR depends on the CPU model. It seems that
// the PC may range from 16 bits to 22 bits.
"gpr pc .32 32 0\n"
"gpr pcl .16 32 0\n"
"gpr pch .16 34 0\n"
// special purpose registers
"gpr pc .16 32 0\n"
"gpr sp .8 34 0\n"
"gpr sreg .8 36 0\n"
"gpr sp .16 36 0\n"
"gpr spl .8 36 0\n"
"gpr sph .8 37 0\n"
// status bit register (SREG)
"gpr sreg .8 38 0\n"
"gpr cf .1 38.0 0\n" // Carry. This is a borrow flag on subtracts.
"gpr zf .1 38.1 0\n" // Zero. Set to 1 when an arithmetic result is zero.
"gpr nf .1 38.2 0\n" // Negative. Set to a copy of the most significant bit of an arithmetic result.
"gpr vf .1 38.3 0\n" // Overflow flag. Set in case of two's complement overflow.
"gpr sf .1 38.4 0\n" // Sign flag. Unique to AVR, this is always (N ^ V) (xor), and shows the true sign of a comparison.
"gpr hf .1 38.5 0\n" // Half carry. This is an internal carry from additions and is used to support BCD arithmetic.
"gpr tf .1 38.6 0\n" // Bit copy. Special bit load and bit store instructions use this bit.
"gpr if .1 38.7 0\n" // Interrupt flag. Set when interrupts are enabled.
// 8bit segment registers to be added to X, Y, Z to get 24bit offsets
"gpr rampx .8 37 0\n"
"gpr rampy .8 38 0\n"
"gpr rampz .8 39 0\n"
"gpr rampd .8 40 0\n"
"gpr eind .8 41 0\n"
// status bit register stored in SREG
/*
C Carry flag. This is a borrow flag on subtracts.
Z Zero flag. Set to 1 when an arithmetic result is zero.
N Negative flag. Set to a copy of the most significant bit of an arithmetic result.
V Overflow flag. Set in case of two's complement overflow.
S Sign flag. Unique to AVR, this is always NV, and shows the true sign of a comparison.
H Half carry. This is an internal carry from additions and is used to support BCD arithmetic.
T Bit copy. Special bit load and bit store instructions use this bit.
I Interrupt flag. Set when interrupts are enabled.
*/
"gpr cf .1 288 0\n" // 288 = (offsetof(SREG))*8= 36 * 8
"gpr zf .1 289 0\n"
"gpr nf .1 290 0\n"
"gpr vf .1 291 0\n"
"gpr sf .1 292 0\n"
"gpr hf .1 293 0\n"
"gpr tf .1 294 0\n"
"gpr if .1 295 0\n"
"gpr rampx .8 39 0\n"
"gpr rampy .8 40 0\n"
"gpr rampz .8 41 0\n"
"gpr rampd .8 42 0\n"
"gpr eind .8 43 0\n"
// memory mapping emulator registers
"gpr _eeprom .32 44 0\n"
"gpr _sram .32 48 0\n"
;
return r_reg_set_profile_string (anal->reg, p);

View File

@ -416,7 +416,14 @@ RAsmPlugin r_asm_plugin_avr = {
.endian = R_SYS_ENDIAN_LITTLE | R_SYS_ENDIAN_BIG,
.desc = "AVR Atmel",
.disassemble = &disassemble,
.assemble = &assemble
.assemble = &assemble,
.cpus = "ATmega168,"
"ATmega328p,"
"ATmega32u4,"
"ATmega1280,"
"ATmega2560,"
"ATmega48",
"ATmega8"
};
#ifndef CORELIB