Rizin
unix-like reverse engineering framework and cli tools
analysis_6502.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2019-2020 condret <condr3t@protonmail.com>
3 // SPDX-FileCopyrightText: 2019-2020 riq <ricardoquesada@gmail.com>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 /* 6502 info taken from http://unusedino.de/ec64/technical/aay/c64/bchrt651.htm
7  *
8  * Mnemonics logic based on:
9  * http://homepage.ntlworld.com/cyborgsystems/CS_Main/6502/6502.htm
10  * and:
11  * http://vice-emu.sourceforge.net/
12  */
13 
14 #include <string.h>
15 #include <rz_types.h>
16 #include <rz_lib.h>
17 #include <rz_asm.h>
18 #include <rz_analysis.h>
19 #include "../../asm/arch/snes/snes_op_table.h"
20 #include "../../asm/arch/6502/6502_il.inc"
21 
22 enum {
23  _6502_FLAGS_C = (1 << 0),
24  _6502_FLAGS_B = (1 << 1),
25  _6502_FLAGS_Z = (1 << 2),
26  _6502_FLAGS_N = (1 << 3),
27 
31 };
32 
34  /* FIXME: 9,$b instead of 8,$b to prevent the bug triggered by: A = 0 - 0xff - 1 */
35  if (flags & _6502_FLAGS_B) {
36  rz_strbuf_append(&op->esil, ",9,$b,C,:=");
37  }
38  if (flags & _6502_FLAGS_C) {
39  rz_strbuf_append(&op->esil, ",7,$c,C,:=");
40  }
41  if (flags & _6502_FLAGS_Z) {
42  rz_strbuf_append(&op->esil, ",$z,Z,:=");
43  }
44  if (flags & _6502_FLAGS_N) {
45  rz_strbuf_append(&op->esil, ",7,$s,N,:=");
46  }
47 }
48 
49 /* ORA, AND, EOR, ADC, STA, LDA, CMP and SBC share this pattern */
50 static void _6502_analysis_esil_get_addr_pattern1(RzAnalysisOp *op, const ut8 *data, size_t len,
51  RZ_NULLABLE char *esiladdr_out, int esiladdr_size,
52  RZ_NULLABLE _6502ILAddr *il_out) {
53  if (len < 1) {
54  return;
55  }
56  // turn off bits 5, 6 and 7
57  ut16 imm = 0;
58  switch (data[0] & 0x1f) { // 0x1f = b00011111
59  case 0x09: // op #$ff
60  op->cycles = 2;
61  imm = len > 1 ? data[1] : 0;
62  if (esiladdr_out) {
63  snprintf(esiladdr_out, esiladdr_size, "0x%02x", (unsigned int)imm);
64  }
65  if (il_out) {
66  _6502_il_immediate(il_out, imm);
67  }
68  break;
69  case 0x05: // op $ff
70  op->cycles = 3;
71  imm = len > 1 ? data[1] : 0;
72  if (esiladdr_out) {
73  snprintf(esiladdr_out, esiladdr_size, "0x%02x", (unsigned int)imm);
74  }
75  if (il_out) {
76  _6502_il_addr_absolute(il_out, imm);
77  }
78  break;
79  case 0x15: // op $ff,x
80  op->cycles = 4;
81  imm = len > 1 ? data[1] : 0;
82  if (esiladdr_out) {
83  snprintf(esiladdr_out, esiladdr_size, "x,0x%02x,+", (unsigned int)imm);
84  }
85  if (il_out) {
86  _6502_il_addr_zero_page_reg(il_out, imm, "x");
87  }
88  break;
89  case 0x0d: // op $ffff
90  op->cycles = 4;
91  imm = (len > 2) ? ((ut16)data[1] | (ut16)data[2] << 8) : 0;
92  if (esiladdr_out) {
93  snprintf(esiladdr_out, esiladdr_size, "0x%04x", (unsigned int)imm);
94  }
95  if (il_out) {
96  _6502_il_addr_absolute(il_out, imm);
97  }
98  break;
99  case 0x1d: // op $ffff,x
100  // FIXME: Add 1 if page boundary is crossed.
101  op->cycles = 4;
102  imm = (len > 2) ? ((ut16)data[1] | (ut16)data[2] << 8) : 0;
103  if (esiladdr_out) {
104  snprintf(esiladdr_out, esiladdr_size, "x,0x%04x,+", (unsigned int)imm);
105  }
106  if (il_out) {
107  _6502_il_addr_reg(il_out, imm, "x");
108  }
109  break;
110  case 0x19: // op $ffff,y
111  // FIXME: Add 1 if page boundary is crossed.
112  op->cycles = 4;
113  imm = (len > 2) ? ((ut16)data[1] | (ut16)data[2] << 8) : 0;
114  if (esiladdr_out) {
115  snprintf(esiladdr_out, esiladdr_size, "y,0x%04x,+", (unsigned int)imm);
116  }
117  if (il_out) {
118  _6502_il_addr_reg(il_out, imm, "y");
119  }
120  break;
121  case 0x01: // op ($ff,x)
122  op->cycles = 6;
123  imm = data[1];
124  if (esiladdr_out) {
125  snprintf(esiladdr_out, esiladdr_size, "x,0x%02x,+,[2]", (unsigned int)imm);
126  }
127  if (il_out) {
128  _6502_il_addr_indirect_x(il_out, imm);
129  }
130  break;
131  case 0x11: // op ($ff),y
132  // FIXME: Add 1 if page boundary is crossed.
133  op->cycles = 5;
134  imm = len > 1 ? data[1] : 0;
135  if (esiladdr_out) {
136  snprintf(esiladdr_out, esiladdr_size, "y,0x%02x,[2],+", (unsigned int)imm);
137  }
138  if (il_out) {
139  _6502_il_addr_indirect_y(il_out, imm);
140  }
141  break;
142  }
143 }
144 
145 /* ASL, ROL, LSR, ROR, STX, LDX, DEC and INC share this pattern */
146 static void _6502_analysis_esil_get_addr_pattern2(RzAnalysisOp *op, const ut8 *data, size_t len,
147  char *addrbuf, int addrsize, const char *reg,
148  RZ_NULLABLE _6502ILAddr *il_out) {
149  // turn off bits 5, 6 and 7
150  if (len < 1) {
151  return;
152  }
153  ut16 imm = 0;
154  switch (data[0] & 0x1f) { // 0x1f = b00111111
155  case 0x02: // op #$ff
156  op->cycles = 2;
157  imm = (len > 1) ? data[1] : 0;
158  snprintf(addrbuf, addrsize, "0x%02x", (unsigned int)imm);
159  if (il_out) {
160  _6502_il_immediate(il_out, imm);
161  }
162  break;
163  case 0x0a: // op a
164  op->cycles = 2;
165  snprintf(addrbuf, addrsize, "a");
166  if (il_out) {
167  _6502_il_accumulator(il_out);
168  }
169  break;
170  case 0x06: // op $ff
171  op->cycles = 5;
172  imm = (len > 1) ? data[1] : 0;
173  snprintf(addrbuf, addrsize, "0x%02x", (unsigned int)imm);
174  if (il_out) {
175  _6502_il_addr_absolute(il_out, imm);
176  }
177  break;
178  case 0x16: // op $ff,x (or op $ff,y)
179  op->cycles = 6;
180  imm = (len > 1) ? data[1] : 0;
181  snprintf(addrbuf, addrsize, "%s,0x%02x,+", reg, imm);
182  if (il_out) {
183  _6502_il_addr_zero_page_reg(il_out, imm, reg);
184  }
185  break;
186  case 0x0e: // op $ffff
187  op->cycles = 6;
188  imm = (len > 2) ? data[1] | data[2] << 8 : 0;
189  snprintf(addrbuf, addrsize, "0x%04x", imm);
190  if (il_out) {
191  _6502_il_addr_absolute(il_out, imm);
192  }
193  break;
194  case 0x1e: // op $ffff,x (or op $ffff,y)
195  op->cycles = 7;
196  imm = (len > 2) ? data[1] | data[2] << 8 : 0;
197  snprintf(addrbuf, addrsize, "%s,0x%04x,+", reg, imm);
198  if (il_out) {
199  _6502_il_addr_reg(il_out, imm, reg);
200  }
201  break;
202  }
203 }
204 
205 /* BIT, JMP, JMP(), STY, LDY, CPY, and CPX share this pattern */
206 static void _6502_analysis_esil_get_addr_pattern3(RzAnalysisOp *op, const ut8 *data, size_t len,
207  char *addrbuf, int addrsize, const char *reg,
208  RZ_NULLABLE _6502ILAddr *il_out) {
209  // turn off bits 5, 6 and 7
210  if (len < 1) {
211  return;
212  }
213  ut16 imm;
214  switch (data[0] & 0x1f) { // 0x1f = b00111111
215  case 0x00: // op #$ff
216  op->cycles = 2;
217  imm = (len > 1) ? data[1] : 0;
218  snprintf(addrbuf, addrsize, "0x%02x", imm);
219  if (il_out) {
220  _6502_il_immediate(il_out, imm);
221  }
222  break;
223  case 0x08: // op a
224  op->cycles = 2;
225  snprintf(addrbuf, addrsize, "a");
226  if (il_out) {
227  _6502_il_accumulator(il_out);
228  }
229  break;
230  case 0x04: // op $ff
231  op->cycles = 5;
232  imm = (len > 1) ? data[1] : 0;
233  snprintf(addrbuf, addrsize, "0x%02x", imm);
234  if (il_out) {
235  _6502_il_addr_absolute(il_out, imm);
236  }
237  break;
238  case 0x14: // op $ff,x
239  op->cycles = 6;
240  imm = (len > 1) ? data[1] : 0;
241  snprintf(addrbuf, addrsize, "%s,0x%02x,+", reg, imm);
242  if (il_out) {
243  _6502_il_addr_zero_page_reg(il_out, imm, reg);
244  }
245  break;
246  case 0x0c: // op $ffff
247  op->cycles = 6;
248  imm = (len > 2) ? data[1] | data[2] << 8 : 0;
249  snprintf(addrbuf, addrsize, "0x%04x", imm);
250  if (il_out) {
251  _6502_il_addr_absolute(il_out, imm);
252  }
253  break;
254  case 0x1c: // op $ffff,x
255  op->cycles = 7;
256  imm = (len > 2) ? data[1] | data[2] << 8 : 0;
257  snprintf(addrbuf, addrsize, "%s,0x%04x,+", reg, imm);
258  if (il_out) {
259  _6502_il_addr_reg(il_out, imm, reg);
260  }
261  break;
262  }
263 }
264 
266  char *flag;
267  switch (data0) {
268  case 0x10: // bpl $ffff
269  flag = "N,!";
270  break;
271  case 0x30: // bmi $ffff
272  flag = "N";
273  break;
274  case 0x50: // bvc $ffff
275  flag = "V,!";
276  break;
277  case 0x70: // bvs $ffff
278  flag = "V";
279  break;
280  case 0x90: // bcc $ffff
281  flag = "C,!";
282  break;
283  case 0xb0: // bcs $ffff
284  flag = "C";
285  break;
286  case 0xd0: // bne $ffff
287  flag = "Z,!";
288  break;
289  case 0xf0: // beq $ffff
290  flag = "Z";
291  break;
292  default:
293  // FIXME: should not happen
294  flag = "unk";
295  break;
296  }
297  rz_strbuf_setf(&op->esil, "%s,?{,0x%04x,pc,=,}", flag, (ut32)(op->jump & 0xffff));
298 }
299 
300 // inc register
301 static void _6502_analysis_esil_inc_reg(RzAnalysisOp *op, ut8 data0, char *sign) {
302  char *reg = NULL;
303 
304  switch (data0) {
305  case 0xe8: // inx
306  case 0xca: // dex
307  reg = "x";
308  break;
309  case 0xc8: // iny
310  case 0x88: // dey
311  reg = "y";
312  break;
313  }
314  rz_strbuf_setf(&op->esil, "%s,%s%s=", reg, sign, sign);
316 }
317 
319  const char *src = "unk";
320  const char *dst = "unk";
321  switch (data0) {
322  case 0xaa: // tax
323  src = "a";
324  dst = "x";
325  break;
326  case 0x8a: // txa
327  src = "x";
328  dst = "a";
329  break;
330  case 0xa8: // tay
331  src = "a";
332  dst = "y";
333  break;
334  case 0x98: // tya
335  src = "y";
336  dst = "a";
337  break;
338  case 0x9a: // txs
339  src = "x";
340  dst = "sp";
341  break;
342  case 0xba: // tsx
343  src = "sp";
344  dst = "x";
345  break;
346  default:
347  // FIXME: should not happen
348  break;
349  }
350  rz_strbuf_setf(&op->esil, "%s,%s,=", src, dst);
351 
352  // don't update NZ on txs
353  if (data0 != 0x9a) {
355  }
356 }
357 
359  // case 0x08: // php
360  // case 0x48: // pha
361  char *reg = (data0 == 0x08) ? "flags" : "a";
362  // stack is on page one: sp + 0x100
363  rz_strbuf_setf(&op->esil, "%s,sp,0x100,+,=[1],sp,--=", reg);
364 }
365 
367  // case 0x28: // plp
368  // case 0x68: // pla
369  char *reg = (data0 == 0x28) ? "flags" : "a";
370  // stack is on page one: sp + 0x100
371  rz_strbuf_setf(&op->esil, "sp,++=,sp,0x100,+,[1],%s,=", reg);
372 
373  if (data0 == 0x68) {
375  }
376 }
377 
379  int enabled = 0;
380  char flag = 'u';
381  switch (data0) {
382  case 0x78: // sei
383  enabled = 1;
384  flag = 'I';
385  break;
386  case 0x58: // cli
387  enabled = 0;
388  flag = 'I';
389  break;
390  case 0x38: // sec
391  enabled = 1;
392  flag = 'C';
393  break;
394  case 0x18: // clc
395  enabled = 0;
396  flag = 'C';
397  break;
398  case 0xf8: // sed
399  enabled = 1;
400  flag = 'D';
401  break;
402  case 0xd8: // cld
403  enabled = 0;
404  flag = 'D';
405  break;
406  case 0xb8: // clv
407  enabled = 0;
408  flag = 'V';
409  break;
410  break;
411  }
412  rz_strbuf_setf(&op->esil, "%d,%c,=", enabled, flag);
413 }
414 
415 static int _6502_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) {
416  char addrbuf[64];
417  const int buffsize = sizeof(addrbuf) - 1;
418  if (len < 1) {
419  return -1;
420  }
421 
422  op->size = snes_op_get_size(1, 1, &snes_op[data[0]]); // snes-arch is similar to nes/6502
423  op->addr = addr;
424  op->type = RZ_ANALYSIS_OP_TYPE_UNK;
425  op->id = data[0];
426  rz_strbuf_init(&op->esil);
427  _6502ILAddr il_addr = { 0 };
428  _6502ILAddr *il_addr_ptr = (mask & RZ_ANALYSIS_OP_MASK_IL) ? &il_addr : NULL;
429  switch (data[0]) {
430  case 0x02:
431  case 0x03:
432  case 0x04:
433  case 0x07:
434  case 0x0b:
435  case 0x0c:
436  case 0x0f:
437  case 0x12:
438  case 0x13:
439  case 0x14:
440  case 0x17:
441  case 0x1a:
442  case 0x1b:
443  case 0x1c:
444  case 0x1f:
445  case 0x22:
446  case 0x23:
447  case 0x27:
448  case 0x2b:
449  case 0x2f:
450  case 0x32:
451  case 0x33:
452  case 0x34:
453  case 0x37:
454  case 0x3a:
455  case 0x3b:
456  case 0x3c:
457  case 0x3f:
458  case 0x42:
459  case 0x43:
460  case 0x44:
461  case 0x47:
462  case 0x4b:
463  case 0x4f:
464  case 0x52:
465  case 0x53:
466  case 0x54:
467  case 0x57:
468  case 0x5a:
469  case 0x5b:
470  case 0x5c:
471  case 0x5f:
472  case 0x62:
473  case 0x63:
474  case 0x64:
475  case 0x67:
476  case 0x6b:
477  case 0x6f:
478  case 0x72:
479  case 0x73:
480  case 0x74:
481  case 0x77:
482  case 0x7a:
483  case 0x7b:
484  case 0x7c:
485  case 0x7f:
486  case 0x80:
487  case 0x82:
488  case 0x83:
489  case 0x87:
490  case 0x89:
491  case 0x8b:
492  case 0x8f:
493  case 0x92:
494  case 0x93:
495  case 0x97:
496  case 0x9b:
497  case 0x9c:
498  case 0x9e:
499  case 0x9f:
500  case 0xa3:
501  case 0xa7:
502  case 0xab:
503  case 0xaf:
504  case 0xb2:
505  case 0xb3:
506  case 0xb7:
507  case 0xbb:
508  case 0xbf:
509  case 0xc2:
510  case 0xc3:
511  case 0xc7:
512  case 0xcb:
513  case 0xcf:
514  case 0xd2:
515  case 0xd3:
516  case 0xd4:
517  case 0xd7:
518  case 0xda:
519  case 0xdb:
520  case 0xdc:
521  case 0xdf:
522  case 0xe2:
523  case 0xe3:
524  case 0xe7:
525  case 0xeb:
526  case 0xef:
527  case 0xf2:
528  case 0xf3:
529  case 0xf4:
530  case 0xf7:
531  case 0xfa:
532  case 0xfb:
533  case 0xfc:
534  case 0xff:
535  // undocumented or not-implemented opcodes for 6502.
536  // some of them might be implemented in 65816
537  op->size = 1;
538  op->type = RZ_ANALYSIS_OP_TYPE_ILL;
539  break;
540 
541  // BRK
542  case 0x00: // brk
543  op->cycles = 7;
544  op->type = RZ_ANALYSIS_OP_TYPE_SWI;
545  // override 65816 code which seems to be wrong: size is 1, but pc = pc + 2
546  op->size = 1;
547  // PC + 2 to Stack, P to Stack B=1 D=0 I=1. "B" is not a flag. Only its bit is pushed on the stack
548  // PC was already incremented by one at this point. Needs to incremented once more
549  // New PC is Interrupt Vector: $fffe. (FIXME: Confirm this is valid for all 6502)
550  rz_strbuf_set(&op->esil, ",1,I,=,0,D,=,flags,0x10,|,0x100,sp,+,=[1],pc,1,+,0xfe,sp,+,=[2],3,sp,-=,0xfffe,[2],pc,=");
552  op->il_op = _6502_il_op_brk((ut16)addr);
553  }
554  break;
555 
556  // FLAGS
557  case 0x78: // sei
558  case 0x58: // cli
559  case 0x38: // sec
560  case 0x18: // clc
561  case 0xf8: // sed
562  case 0xd8: // cld
563  case 0xb8: // clv
564  op->cycles = 2;
565  // FIXME: what opcode for this?
566  op->type = RZ_ANALYSIS_OP_TYPE_NOP;
567  _6502_analysis_esil_flags(op, data[0]);
569  op->il_op = _6502_il_op_flag(data[0]);
570  }
571  break;
572  // BIT
573  case 0x24: // bit $ff
574  case 0x2c: // bit $ffff
575  op->type = RZ_ANALYSIS_OP_TYPE_MOV;
576  _6502_analysis_esil_get_addr_pattern3(op, data, len, addrbuf, buffsize, NULL, il_addr_ptr);
577  rz_strbuf_setf(&op->esil, "%s,[1],0x80,&,!,!,N,=,%s,[1],0x40,&,!,!,V,=,a,%s,[1],&,0xff,&,!,Z,=", addrbuf, addrbuf, addrbuf);
579  op->il_op = _6502_il_op_bit(il_addr_ptr);
580  }
581  break;
582  // ADC
583  case 0x69: // adc #$ff
584  case 0x65: // adc $ff
585  case 0x75: // adc $ff,x
586  case 0x6d: // adc $ffff
587  case 0x7d: // adc $ffff,x
588  case 0x79: // adc $ffff,y
589  case 0x61: // adc ($ff,x)
590  case 0x71: // adc ($ff,y)
591  // FIXME: update V
592  // FIXME: support BCD mode
593  op->type = RZ_ANALYSIS_OP_TYPE_ADD;
594  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
595  if (data[0] == 0x69) { // immediate mode
596  rz_strbuf_setf(&op->esil, "%s,a,+=,7,$c,C,a,+=,7,$c,|,C,:=", addrbuf);
597  } else {
598  rz_strbuf_setf(&op->esil, "%s,[1],a,+=,7,$c,C,a,+=,7,$c,|,C,:=", addrbuf);
599  }
601  // fix Z
602  rz_strbuf_append(&op->esil, ",a,a,=,$z,Z,:=");
604  op->il_op = _6502_il_op_adc(il_addr_ptr);
605  }
606  break;
607  // SBC
608  case 0xe9: // sbc #$ff
609  case 0xe5: // sbc $ff
610  case 0xf5: // sbc $ff,x
611  case 0xed: // sbc $ffff
612  case 0xfd: // sbc $ffff,x
613  case 0xf9: // sbc $ffff,y
614  case 0xe1: // sbc ($ff,x)
615  case 0xf1: // sbc ($ff,y)
616  // FIXME: update V
617  // FIXME: support BCD mode
618  op->type = RZ_ANALYSIS_OP_TYPE_SUB;
619  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
620  if (data[0] == 0xe9) { // immediate mode
621  rz_strbuf_setf(&op->esil, "C,!,%s,+,a,-=", addrbuf);
622  } else {
623  rz_strbuf_setf(&op->esil, "C,!,%s,[1],+,a,-=", addrbuf);
624  }
626  // fix Z and revert C
627  rz_strbuf_append(&op->esil, ",a,a,=,$z,Z,:=,C,!=");
629  op->il_op = _6502_il_op_sbc(il_addr_ptr);
630  }
631  break;
632  // ORA
633  case 0x09: // ora #$ff
634  case 0x05: // ora $ff
635  case 0x15: // ora $ff,x
636  case 0x0d: // ora $ffff
637  case 0x1d: // ora $ffff,x
638  case 0x19: // ora $ffff,y
639  case 0x01: // ora ($ff,x)
640  case 0x11: { // ora ($ff),y
641  op->type = RZ_ANALYSIS_OP_TYPE_OR;
642  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
643  bool is_immediate = data[0] == 0x09;
644  if (is_immediate) { // immediate mode
645  rz_strbuf_setf(&op->esil, "%s,a,|=", addrbuf);
646  } else {
647  rz_strbuf_setf(&op->esil, "%s,[1],a,|=", addrbuf);
648  }
651  op->il_op = _6502_il_op_ora(il_addr_ptr);
652  }
653  break;
654  }
655  // AND
656  case 0x29: // and #$ff
657  case 0x25: // and $ff
658  case 0x35: // and $ff,x
659  case 0x2d: // and $ffff
660  case 0x3d: // and $ffff,x
661  case 0x39: // and $ffff,y
662  case 0x21: // and ($ff,x)
663  case 0x31: // and ($ff),y
664  op->type = RZ_ANALYSIS_OP_TYPE_AND;
665  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
666  bool is_immediate = data[0] == 0x29;
667  if (is_immediate) { // immediate mode
668  rz_strbuf_setf(&op->esil, "%s,a,&=", addrbuf);
669  } else {
670  rz_strbuf_setf(&op->esil, "%s,[1],a,&=", addrbuf);
671  }
674  op->il_op = _6502_il_op_and(il_addr_ptr);
675  }
676  break;
677  // EOR
678  case 0x49: // eor #$ff
679  case 0x45: // eor $ff
680  case 0x55: // eor $ff,x
681  case 0x4d: // eor $ffff
682  case 0x5d: // eor $ffff,x
683  case 0x59: // eor $ffff,y
684  case 0x41: // eor ($ff,x)
685  case 0x51: // eor ($ff),y
686  op->type = RZ_ANALYSIS_OP_TYPE_XOR;
687  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
688  if (data[0] == 0x49) { // immediate mode
689  rz_strbuf_setf(&op->esil, "%s,a,^=", addrbuf);
690  } else {
691  rz_strbuf_setf(&op->esil, "%s,[1],a,^=", addrbuf);
692  }
695  op->il_op = _6502_il_op_eor(il_addr_ptr);
696  }
697  break;
698  // ASL
699  case 0x0a: // asl a
700  case 0x06: // asl $ff
701  case 0x16: // asl $ff,x
702  case 0x0e: // asl $ffff
703  case 0x1e: // asl $ffff,x
704  op->type = RZ_ANALYSIS_OP_TYPE_SHL;
705  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
706  if (data[0] == 0x0a) {
707  rz_strbuf_set(&op->esil, "1,a,<<=,7,$c,C,:=,a,a,=");
708  } else {
709  rz_strbuf_setf(&op->esil, "1,%s,[1],<<,%s,=[1],7,$c,C,:=", addrbuf, addrbuf);
710  }
713  op->il_op = _6502_il_op_asl(il_addr_ptr);
714  }
715  break;
716  // LSR
717  case 0x4a: // lsr a
718  case 0x46: // lsr $ff
719  case 0x56: // lsr $ff,x
720  case 0x4e: // lsr $ffff
721  case 0x5e: // lsr $ffff,x
722  op->type = RZ_ANALYSIS_OP_TYPE_SHR;
723  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
724  if (data[0] == 0x4a) {
725  rz_strbuf_set(&op->esil, "1,a,&,C,=,1,a,>>=");
726  } else {
727  rz_strbuf_setf(&op->esil, "1,%s,[1],&,C,=,1,%s,[1],>>,%s,=[1]", addrbuf, addrbuf, addrbuf);
728  }
731  op->il_op = _6502_il_op_lsr(il_addr_ptr);
732  }
733  break;
734  // ROL
735  case 0x2a: // rol a
736  case 0x26: // rol $ff
737  case 0x36: // rol $ff,x
738  case 0x2e: // rol $ffff
739  case 0x3e: // rol $ffff,x
740  op->type = RZ_ANALYSIS_OP_TYPE_ROL;
741  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
742  if (data[0] == 0x2a) {
743  rz_strbuf_set(&op->esil, "1,a,<<,C,|,a,=,7,$c,C,:=,a,a,=");
744  } else {
745  rz_strbuf_setf(&op->esil, "1,%s,[1],<<,C,|,%s,=[1],7,$c,C,:=", addrbuf, addrbuf);
746  }
749  op->il_op = _6502_il_op_rol(il_addr_ptr);
750  }
751  break;
752  // ROR
753  case 0x6a: // ror a
754  case 0x66: // ror $ff
755  case 0x76: // ror $ff,x
756  case 0x6e: // ror $ffff
757  case 0x7e: // ror $ffff,x
758  // uses N as temporary to hold C value. but in fact,
759  // it is not temporary since in all ROR ops, N will have the value of C
760  op->type = RZ_ANALYSIS_OP_TYPE_ROR;
761  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
762  if (data[0] == 0x6a) {
763  rz_strbuf_set(&op->esil, "C,N,=,1,a,&,C,=,1,a,>>,7,N,<<,|,a,=");
764  } else {
765  rz_strbuf_setf(&op->esil, "C,N,=,1,%s,[1],&,C,=,1,%s,[1],>>,7,N,<<,|,%s,=[1]", addrbuf, addrbuf, addrbuf);
766  }
769  op->il_op = _6502_il_op_ror(il_addr_ptr);
770  }
771  break;
772  // INC
773  case 0xe6: // inc $ff
774  case 0xf6: // inc $ff,x
775  case 0xee: // inc $ffff
776  case 0xfe: // inc $ffff,x
778  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
779  rz_strbuf_setf(&op->esil, "%s,++=[1]", addrbuf);
782  op->il_op = _6502_il_op_inc(il_addr_ptr, true);
783  }
784  break;
785  // DEC
786  case 0xc6: // dec $ff
787  case 0xd6: // dec $ff,x
788  case 0xce: // dec $ffff
789  case 0xde: // dec $ffff,x
791  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
792  rz_strbuf_setf(&op->esil, "%s,--=[1]", addrbuf);
795  op->il_op = _6502_il_op_inc(il_addr_ptr, false);
796  }
797  break;
798  // INX, INY
799  case 0xe8: // inx
800  case 0xc8: // iny
801  op->cycles = 2;
803  _6502_analysis_esil_inc_reg(op, data[0], "+");
805  op->il_op = _6502_il_op_inc_reg(data[0] == 0xe8 ? "x" : "y", true);
806  }
807  break;
808  // DEX, DEY
809  case 0xca: // dex
810  case 0x88: // dey
811  op->cycles = 2;
813  _6502_analysis_esil_inc_reg(op, data[0], "-");
815  op->il_op = _6502_il_op_inc_reg(data[0] == 0xca ? "x" : "y", false);
816  }
817  break;
818  // CMP
819  case 0xc9: // cmp #$ff
820  case 0xc5: // cmp $ff
821  case 0xd5: // cmp $ff,x
822  case 0xcd: // cmp $ffff
823  case 0xdd: // cmp $ffff,x
824  case 0xd9: // cmp $ffff,y
825  case 0xc1: // cmp ($ff,x)
826  case 0xd1: // cmp ($ff),y
827  op->type = RZ_ANALYSIS_OP_TYPE_CMP;
828  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
829  if (data[0] == 0xc9) { // immediate mode
830  rz_strbuf_setf(&op->esil, "%s,a,==", addrbuf);
831  } else {
832  rz_strbuf_setf(&op->esil, "%s,[1],a,==", addrbuf);
833  }
835  // invert C, since C=1 when A-M >= 0
836  rz_strbuf_append(&op->esil, ",C,!,C,=");
838  op->il_op = _6502_il_op_cmp("a", il_addr_ptr);
839  }
840  break;
841  // CPX
842  case 0xe0: // cpx #$ff
843  case 0xe4: // cpx $ff
844  case 0xec: // cpx $ffff
845  op->type = RZ_ANALYSIS_OP_TYPE_CMP;
846  _6502_analysis_esil_get_addr_pattern3(op, data, len, addrbuf, buffsize, NULL, il_addr_ptr);
847  if (data[0] == 0xe0) { // immediate mode
848  rz_strbuf_setf(&op->esil, "%s,x,==", addrbuf);
849  } else {
850  rz_strbuf_setf(&op->esil, "%s,[1],x,==", addrbuf);
851  }
853  // invert C, since C=1 when A-M >= 0
854  rz_strbuf_append(&op->esil, ",C,!,C,=");
856  op->il_op = _6502_il_op_cmp("x", il_addr_ptr);
857  }
858  break;
859  // CPY
860  case 0xc0: // cpy #$ff
861  case 0xc4: // cpy $ff
862  case 0xcc: // cpy $ffff
863  op->type = RZ_ANALYSIS_OP_TYPE_CMP;
864  _6502_analysis_esil_get_addr_pattern3(op, data, len, addrbuf, buffsize, NULL, il_addr_ptr);
865  if (data[0] == 0xc0) { // immediate mode
866  rz_strbuf_setf(&op->esil, "%s,y,==", addrbuf);
867  } else {
868  rz_strbuf_setf(&op->esil, "%s,[1],y,==", addrbuf);
869  }
871  // invert C, since C=1 when A-M >= 0
872  rz_strbuf_append(&op->esil, ",C,!,C,=");
874  op->il_op = _6502_il_op_cmp("y", il_addr_ptr);
875  }
876  break;
877  // BRANCHES
878  case 0x10: // bpl $ffff
879  case 0x30: // bmi $ffff
880  case 0x50: // bvc $ffff
881  case 0x70: // bvs $ffff
882  case 0x90: // bcc $ffff
883  case 0xb0: // bcs $ffff
884  case 0xd0: // bne $ffff
885  case 0xf0: // beq $ffff
886  // FIXME: Add 1 if branch occurs to same page.
887  // FIXME: Add 2 if branch occurs to different page
888  op->cycles = 2;
889  op->failcycles = 3;
891  if (len > 1) {
892  if (data[1] <= 127) {
893  op->jump = addr + data[1] + op->size;
894  } else {
895  op->jump = addr - (256 - data[1]) + op->size;
896  }
897  } else {
898  op->jump = addr;
899  }
900  op->fail = addr + op->size;
901  // FIXME: add a type of conditional
902  // op->cond = RZ_TYPE_COND_LE;
903  _6502_analysis_esil_ccall(op, data[0]);
905  op->il_op = _6502_il_op_branch(data[0], op->jump);
906  }
907  break;
908  // JSR
909  case 0x20: // jsr $ffff
910  op->cycles = 6;
912  op->jump = (len > 2) ? data[1] | data[2] << 8 : 0;
913  op->stackop = RZ_ANALYSIS_STACK_INC;
914  op->stackptr = 2;
915  // JSR pushes the address-1 of the next operation on to the stack before transferring program
916  // control to the following address
917  // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
918  rz_strbuf_setf(&op->esil, "1,pc,-,0xff,sp,+,=[2],0x%04" PFMT64x ",pc,=,2,sp,-=", op->jump);
920  op->il_op = _6502_il_op_jsr(op->jump, addr);
921  }
922  break;
923  // JMP
924  case 0x4c: // jmp $ffff
925  op->cycles = 3;
926  op->type = RZ_ANALYSIS_OP_TYPE_JMP;
927  op->jump = (len > 2) ? data[1] | data[2] << 8 : 0;
928  rz_strbuf_setf(&op->esil, "0x%04" PFMT64x ",pc,=", op->jump);
930  op->il_op = _6502_il_op_jmp(op->jump, false);
931  }
932  break;
933  case 0x6c: { // jmp ($ffff)
934  op->cycles = 5;
936  ut16 imm = len > 2 ? data[1] | data[2] << 8 : 0;
937  rz_strbuf_setf(&op->esil, "0x%04x,[2],pc,=", imm);
939  op->il_op = _6502_il_op_jmp(imm, true);
940  }
941  break;
942  }
943  // RTS
944  case 0x60: // rts
945  op->eob = true;
946  op->type = RZ_ANALYSIS_OP_TYPE_RET;
947  op->cycles = 6;
948  op->stackop = RZ_ANALYSIS_STACK_INC;
949  op->stackptr = -2;
950  // Operation: PC from Stack, PC + 1 -> PC
951  // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
952  rz_strbuf_set(&op->esil, "0x101,sp,+,[2],pc,=,pc,++=,2,sp,+=");
954  op->il_op = _6502_il_op_rts();
955  }
956  break;
957  // RTI
958  case 0x40: // rti
959  op->eob = true;
960  op->type = RZ_ANALYSIS_OP_TYPE_RET;
961  op->cycles = 6;
962  op->stackop = RZ_ANALYSIS_STACK_INC;
963  op->stackptr = -3;
964  // Operation: P from Stack, PC from Stack
965  // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100
966  rz_strbuf_set(&op->esil, "0x101,sp,+,[1],flags,=,0x102,sp,+,[2],pc,=,3,sp,+=");
968  op->il_op = _6502_il_op_rti();
969  }
970  break;
971  // NOP
972  case 0xea: // nop
973  op->type = RZ_ANALYSIS_OP_TYPE_NOP;
974  op->cycles = 2;
976  op->il_op = rz_il_op_new_nop();
977  }
978  break;
979  // LDA
980  case 0xa9: // lda #$ff
981  case 0xa5: // lda $ff
982  case 0xb5: // lda $ff,x
983  case 0xad: // lda $ffff
984  case 0xbd: // lda $ffff,x
985  case 0xb9: // lda $ffff,y
986  case 0xa1: // lda ($ff,x)
987  case 0xb1: // lda ($ff),y
989  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
990  if (data[0] == 0xa9) {
991  rz_strbuf_setf(&op->esil, "%s,a,=", addrbuf);
992  } else {
993  rz_strbuf_setf(&op->esil, "%s,[1],a,=", addrbuf);
994  }
997  op->il_op = _6502_il_op_ld("a", il_addr_ptr);
998  }
999  break;
1000  // LDX
1001  case 0xa2: // ldx #$ff
1002  case 0xa6: // ldx $ff
1003  case 0xb6: // ldx $ff,y
1004  case 0xae: // ldx $ffff
1005  case 0xbe: // ldx $ffff,y
1006  op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
1007  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "y", il_addr_ptr);
1008  if (data[0] == 0xa2) { // immediate mode
1009  rz_strbuf_setf(&op->esil, "%s,x,=", addrbuf);
1010  } else {
1011  rz_strbuf_setf(&op->esil, "%s,[1],x,=", addrbuf);
1012  }
1014  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1015  op->il_op = _6502_il_op_ld("x", il_addr_ptr);
1016  }
1017  break;
1018  // LDY
1019  case 0xa0: // ldy #$ff
1020  case 0xa4: // ldy $ff
1021  case 0xb4: // ldy $ff,x
1022  case 0xac: // ldy $ffff
1023  case 0xbc: // ldy $ffff,x
1024  op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
1025  _6502_analysis_esil_get_addr_pattern3(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
1026  if (data[0] == 0xa0) { // immediate mode
1027  rz_strbuf_setf(&op->esil, "%s,y,=", addrbuf);
1028  } else {
1029  rz_strbuf_setf(&op->esil, "%s,[1],y,=", addrbuf);
1030  }
1032  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1033  op->il_op = _6502_il_op_ld("y", il_addr_ptr);
1034  }
1035  break;
1036  // STA
1037  case 0x85: // sta $ff
1038  case 0x95: // sta $ff,x
1039  case 0x8d: // sta $ffff
1040  case 0x9d: // sta $ffff,x
1041  case 0x99: // sta $ffff,y
1042  case 0x81: // sta ($ff,x)
1043  case 0x91: // sta ($ff),y
1044  op->type = RZ_ANALYSIS_OP_TYPE_STORE;
1045  _6502_analysis_esil_get_addr_pattern1(op, data, len, addrbuf, buffsize, il_addr_ptr);
1046  rz_strbuf_setf(&op->esil, "a,%s,=[1]", addrbuf);
1047  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1048  op->il_op = _6502_il_op_st("a", il_addr_ptr);
1049  }
1050  break;
1051  // STX
1052  case 0x86: // stx $ff
1053  case 0x96: // stx $ff,y
1054  case 0x8e: // stx $ffff
1055  op->type = RZ_ANALYSIS_OP_TYPE_STORE;
1056  _6502_analysis_esil_get_addr_pattern2(op, data, len, addrbuf, buffsize, "y", il_addr_ptr);
1057  rz_strbuf_setf(&op->esil, "x,%s,=[1]", addrbuf);
1058  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1059  op->il_op = _6502_il_op_st("x", il_addr_ptr);
1060  }
1061  break;
1062  // STY
1063  case 0x84: // sty $ff
1064  case 0x94: // sty $ff,x
1065  case 0x8c: // sty $ffff
1066  op->type = RZ_ANALYSIS_OP_TYPE_STORE;
1067  _6502_analysis_esil_get_addr_pattern3(op, data, len, addrbuf, buffsize, "x", il_addr_ptr);
1068  rz_strbuf_setf(&op->esil, "y,%s,=[1]", addrbuf);
1069  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1070  op->il_op = _6502_il_op_st("y", il_addr_ptr);
1071  }
1072  break;
1073  // PHP/PHA
1074  case 0x08: // php
1075  case 0x48: // pha
1076  op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
1077  op->cycles = 3;
1078  op->stackop = RZ_ANALYSIS_STACK_INC;
1079  op->stackptr = 1;
1080  _6502_analysis_esil_push(op, data[0]);
1081  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1082  if (data[0] == 0x08) {
1083  op->il_op = _6502_il_op_php();
1084  } else {
1085  op->il_op = _6502_il_op_pha();
1086  }
1087  }
1088  break;
1089  // PLP,PLA
1090  case 0x28: // plp
1091  case 0x68: // plp
1092  op->type = RZ_ANALYSIS_OP_TYPE_POP;
1093  op->cycles = 4;
1094  op->stackop = RZ_ANALYSIS_STACK_INC;
1095  op->stackptr = -1;
1096  _6502_analysis_esil_pop(op, data[0]);
1097  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1098  if (data[0] == 0x28) {
1099  op->il_op = _6502_il_op_plp();
1100  } else {
1101  op->il_op = _6502_il_op_pla();
1102  }
1103  }
1104  break;
1105  // TAX,TYA,...
1106  case 0xaa: // tax
1107  case 0x8a: // txa
1108  case 0xa8: // tay
1109  case 0x98: // tya
1110  op->type = RZ_ANALYSIS_OP_TYPE_MOV;
1111  op->cycles = 2;
1112  _6502_analysis_esil_mov(op, data[0]);
1113  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1114  op->il_op = _6502_il_op_transfer(
1115  data[0] == 0xaa ? "x" : (data[0] == 0xa8 ? "y" : "a"),
1116  data[0] == 0x8a ? "x" : (data[0] == 0x98 ? "y" : "a"),
1117  true);
1118  }
1119  break;
1120  case 0x9a: // txs
1121  op->type = RZ_ANALYSIS_OP_TYPE_MOV;
1122  op->cycles = 2;
1123  op->stackop = RZ_ANALYSIS_STACK_SET;
1124  // FIXME: should I get register X a place it here?
1125  // op->stackptr = get_register_x();
1126  _6502_analysis_esil_mov(op, data[0]);
1127  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1128  op->il_op = _6502_il_op_transfer("sp", "x", false);
1129  }
1130  break;
1131  case 0xba: // tsx
1132  op->type = RZ_ANALYSIS_OP_TYPE_MOV;
1133  op->cycles = 2;
1134  op->stackop = RZ_ANALYSIS_STACK_GET;
1135  _6502_analysis_esil_mov(op, data[0]);
1136  if (mask & RZ_ANALYSIS_OP_MASK_IL) {
1137  op->il_op = _6502_il_op_transfer("x", "sp", true);
1138  }
1139  break;
1140  }
1141  return op->size;
1142 }
1143 
1144 static char *get_reg_profile(RzAnalysis *analysis) {
1145  char *p =
1146  "=PC pc\n"
1147  "=SP sp\n"
1148  "=A0 y\n"
1149  "=A1 y\n"
1150  "gpr a .8 0 0\n"
1151  "gpr x .8 1 0\n"
1152  "gpr y .8 2 0\n"
1153 
1154  "gpr flags .8 3 0\n"
1155  "gpr C .1 .24 0\n"
1156  "gpr Z .1 .25 0\n"
1157  "gpr I .1 .26 0\n"
1158  "gpr D .1 .27 0\n"
1159  // bit 4 (.28) is NOT a real flag.
1160  // "gpr B .1 .28 0\n"
1161  // bit 5 (.29) is not used
1162  "gpr V .1 .30 0\n"
1163  "gpr N .1 .31 0\n"
1164  "gpr sp .8 4 0\n"
1165  "gpr pc .16 5 0\n";
1166  return strdup(p);
1167 }
1168 
1169 static int esil_6502_init(RzAnalysisEsil *esil) {
1170  if (esil->analysis && esil->analysis->reg) { // initial values
1171  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "pc", -1), 0x0000);
1172  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "sp", -1), 0xff);
1173  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "a", -1), 0x00);
1174  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "x", -1), 0x00);
1175  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "y", -1), 0x00);
1176  rz_reg_set_value(esil->analysis->reg, rz_reg_get(esil->analysis->reg, "flags", -1), 0x00);
1177  }
1178  return true;
1179 }
1180 
1181 static int esil_6502_fini(RzAnalysisEsil *esil) {
1182  return true;
1183 }
1184 
1185 static int address_bits(RzAnalysis *analysis, int bits) {
1186  return 16;
1187 }
1188 
1190  return rz_analysis_il_config_new(16, false, 16);
1191 }
1192 
1194  .name = "6502",
1195  .desc = "6502/NES analysis plugin",
1196  .license = "LGPL3",
1197  .arch = "6502",
1198  .bits = 8,
1199  .address_bits = address_bits,
1200  .op = &_6502_op,
1201  .get_reg_profile = &get_reg_profile,
1202  .esil = true,
1203  .esil_init = esil_6502_init,
1204  .esil_fini = esil_6502_fini,
1205  .il_config = il_config
1206 };
1207 
1208 #ifndef RZ_PLUGIN_INCORE
1211  .data = &rz_analysis_plugin_6502,
1212  .version = RZ_VERSION
1213 };
1214 #endif
size_t len
Definition: 6502dis.c:15
static void _6502_analysis_esil_push(RzAnalysisOp *op, ut8 data0)
static void _6502_analysis_esil_get_addr_pattern3(RzAnalysisOp *op, const ut8 *data, size_t len, char *addrbuf, int addrsize, const char *reg, RZ_NULLABLE _6502ILAddr *il_out)
static char * get_reg_profile(RzAnalysis *analysis)
static RzAnalysisILConfig * il_config(RzAnalysis *analysis)
RzAnalysisPlugin rz_analysis_plugin_6502
static void _6502_analysis_esil_get_addr_pattern2(RzAnalysisOp *op, const ut8 *data, size_t len, char *addrbuf, int addrsize, const char *reg, RZ_NULLABLE _6502ILAddr *il_out)
static void _6502_analysis_esil_ccall(RzAnalysisOp *op, ut8 data0)
RZ_API RzLibStruct rizin_plugin
static void _6502_analysis_esil_update_flags(RzAnalysisOp *op, int flags)
Definition: analysis_6502.c:33
static int esil_6502_fini(RzAnalysisEsil *esil)
static int address_bits(RzAnalysis *analysis, int bits)
@ _6502_FLAGS_N
Definition: analysis_6502.c:26
@ _6502_FLAGS_BNZ
Definition: analysis_6502.c:30
@ _6502_FLAGS_Z
Definition: analysis_6502.c:25
@ _6502_FLAGS_B
Definition: analysis_6502.c:24
@ _6502_FLAGS_C
Definition: analysis_6502.c:23
@ _6502_FLAGS_NZ
Definition: analysis_6502.c:28
@ _6502_FLAGS_CNZ
Definition: analysis_6502.c:29
static void _6502_analysis_esil_get_addr_pattern1(RzAnalysisOp *op, const ut8 *data, size_t len, RZ_NULLABLE char *esiladdr_out, int esiladdr_size, RZ_NULLABLE _6502ILAddr *il_out)
Definition: analysis_6502.c:50
static void _6502_analysis_esil_mov(RzAnalysisOp *op, ut8 data0)
static int _6502_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
static void _6502_analysis_esil_flags(RzAnalysisOp *op, ut8 data0)
static int esil_6502_init(RzAnalysisEsil *esil)
static void _6502_analysis_esil_inc_reg(RzAnalysisOp *op, ut8 data0, char *sign)
static void _6502_analysis_esil_pop(RzAnalysisOp *op, ut8 data0)
#define mask()
#define imm
RZ_API RZ_OWN RzAnalysisILConfig * rz_analysis_il_config_new(ut32 pc_size, bool big_endian, ut32 mem_key_size)
Definition: analysis_il.c:53
lzma_index * src
Definition: index.h:567
int bits(struct state *s, int need)
Definition: blast.c:72
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint16_t ut16
uint32_t ut32
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_nop()
Definition: il_opcodes.c:566
snprintf
Definition: kernel.h:364
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
char * dst
Definition: lz4.h:724
static int is_immediate(ut32 instr)
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
Definition: reg.c:344
RZ_API bool rz_reg_set_value(RzReg *reg, RzRegItem *item, ut64 value)
Definition: rvalue.c:186
@ RZ_ANALYSIS_STACK_SET
Definition: rz_analysis.h:459
@ RZ_ANALYSIS_STACK_GET
Definition: rz_analysis.h:458
@ RZ_ANALYSIS_STACK_INC
Definition: rz_analysis.h:457
RzAnalysisOpMask
Definition: rz_analysis.h:439
@ RZ_ANALYSIS_OP_MASK_IL
Definition: rz_analysis.h:446
@ RZ_ANALYSIS_OP_TYPE_CMP
Definition: rz_analysis.h:399
@ RZ_ANALYSIS_OP_TYPE_SUB
Definition: rz_analysis.h:402
@ RZ_ANALYSIS_OP_TYPE_LOAD
Definition: rz_analysis.h:416
@ RZ_ANALYSIS_OP_TYPE_UNK
Definition: rz_analysis.h:388
@ RZ_ANALYSIS_OP_TYPE_ROL
Definition: rz_analysis.h:420
@ RZ_ANALYSIS_OP_TYPE_JMP
Definition: rz_analysis.h:368
@ RZ_ANALYSIS_OP_TYPE_AND
Definition: rz_analysis.h:411
@ RZ_ANALYSIS_OP_TYPE_UJMP
Definition: rz_analysis.h:369
@ RZ_ANALYSIS_OP_TYPE_ROR
Definition: rz_analysis.h:419
@ RZ_ANALYSIS_OP_TYPE_SWI
Definition: rz_analysis.h:393
@ RZ_ANALYSIS_OP_TYPE_CALL
Definition: rz_analysis.h:378
@ RZ_ANALYSIS_OP_TYPE_ADD
Definition: rz_analysis.h:401
@ RZ_ANALYSIS_OP_TYPE_OR
Definition: rz_analysis.h:410
@ RZ_ANALYSIS_OP_TYPE_STORE
Definition: rz_analysis.h:415
@ RZ_ANALYSIS_OP_TYPE_PUSH
Definition: rz_analysis.h:397
@ RZ_ANALYSIS_OP_TYPE_SHR
Definition: rz_analysis.h:406
@ RZ_ANALYSIS_OP_TYPE_POP
Definition: rz_analysis.h:398
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
@ RZ_ANALYSIS_OP_TYPE_MOV
Definition: rz_analysis.h:390
@ RZ_ANALYSIS_OP_TYPE_SHL
Definition: rz_analysis.h:407
@ RZ_ANALYSIS_OP_TYPE_ILL
Definition: rz_analysis.h:387
@ RZ_ANALYSIS_OP_TYPE_RET
Definition: rz_analysis.h:385
@ RZ_ANALYSIS_OP_TYPE_NOP
Definition: rz_analysis.h:389
@ RZ_ANALYSIS_OP_TYPE_XOR
Definition: rz_analysis.h:412
@ RZ_LIB_TYPE_ANALYSIS
Definition: rz_lib.h:73
RZ_API const char * rz_strbuf_set(RzStrBuf *sb, const char *s)
Definition: strbuf.c:153
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API const char * rz_strbuf_setf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
#define RZ_NULLABLE
Definition: rz_types.h:65
#define PFMT64x
Definition: rz_types.h:393
#define RZ_VERSION
Definition: rz_version.h:8
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
static snes_op_t snes_op[]
Definition: snes_op_table.h:33
static int snes_op_get_size(int M_flag, int X_flag, snes_op_t *op)
Definition: snes_op_table.h:24
RzAnalysis * analysis
Definition: rz_analysis.h:1043
Description of the global context of an RzAnalysisILVM.
Definition: rz_analysis.h:1134
const char * version
Definition: rz_analysis.h:1239
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58