Rizin
unix-like reverse engineering framework and cli tools
bin_sfc.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017-2019 usrshare
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_bin.h>
5 #include <rz_lib.h>
6 #include "sfc/sfc_specs.h"
7 #include <rz_endian.h>
8 
9 static bool check_buffer(RzBuffer *b) {
11  // FIXME: this was commented out because it always evaluates to false.
12  // Need to be fixed by someone with SFC knowledge
13  // if ((length & 0x8000) == 0x200) {
14  // buf_hdr += 0x200;
15  // }
16  if (length < 0x8000) {
17  return false;
18  }
19  // determine if ROM is headered, and add a 0x200 gap if so.
20  ut16 cksum1;
21  if (!rz_buf_read_le16_at(b, 0x7fdc, &cksum1)) {
22  return false;
23  }
24 
25  ut16 cksum2;
26  if (!rz_buf_read_le16_at(b, 0x7fde, &cksum2)) {
27  return false;
28  }
29 
30  if (cksum1 == (ut16)~cksum2) {
31  return true;
32  }
33  if (length < 0xffee) {
34  return false;
35  }
36 
37  if (!rz_buf_read_le16_at(b, 0xffdc, &cksum1)) {
38  return false;
39  }
40 
41  if (!rz_buf_read_le16_at(b, 0xffde, &cksum2)) {
42  return false;
43  }
44 
45  return (cksum1 == (ut16)~cksum2);
46 }
47 
48 static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
49  return check_buffer(b);
50 }
51 
52 static RzBinInfo *info(RzBinFile *bf) {
53  sfc_int_hdr sfchdr = { { 0 } };
54  RzBinInfo *ret = NULL;
55  int hdroffset = 0;
56 #if THIS_IS_ALWAYS_FALSE_WTF
57  if ((bf->size & 0x8000) == 0x200) {
58  hdroffset = 0x200;
59  }
60 #endif
61  int reat = rz_buf_read_at(bf->buf, 0x7FC0 + hdroffset,
62  (ut8 *)&sfchdr, SFC_HDR_SIZE);
63  if (reat != SFC_HDR_SIZE) {
64  RZ_LOG_ERROR("Unable to read SFC/SNES header\n");
65  return NULL;
66  }
67 
68  if ((sfchdr.comp_check != (ut16) ~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 0)) {
69 
70  // if the fixed 0x33 byte or the LoROM indication are not found, then let's try interpreting the ROM as HiROM
71 
72  reat = rz_buf_read_at(bf->buf, 0xFFC0 + hdroffset, (ut8 *)&sfchdr, SFC_HDR_SIZE);
73  if (reat != SFC_HDR_SIZE) {
74  RZ_LOG_ERROR("Unable to read SFC/SNES header\n");
75  return NULL;
76  }
77 
78  if ((sfchdr.comp_check != (ut16) ~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 1)) {
79 
80  RZ_LOG_ERROR("Cannot determine if this is a LoROM or HiROM file\n");
81  return NULL;
82  }
83  }
84 
85  if (!(ret = RZ_NEW0(RzBinInfo))) {
86  return NULL;
87  }
88  ret->file = strdup(bf->file);
89  ret->type = strdup("ROM");
90  ret->machine = strdup("Super NES / Super Famicom");
91  ret->os = strdup("snes");
92  ret->arch = strdup("snes");
93  ret->bits = 16;
94  ret->has_va = 1;
95  return ret;
96 }
97 
98 static void addrom(RzList *ret, const char *name, int i, ut64 paddr, ut64 vaddr, ut32 size) {
100  if (!ptr) {
101  return;
102  }
103  ptr->name = rz_str_newf("%s_%02x", name, i);
104  ptr->paddr = paddr;
105  ptr->vaddr = vaddr;
106  ptr->size = ptr->vsize = size;
107  ptr->perm = RZ_PERM_RX;
108  rz_list_append(ret, ptr);
109 }
110 
111 #if 0
112 static void addsym(RzList *ret, const char *name, ut64 addr, ut32 size) {
114  if (!ptr) {
115  return;
116  }
117  ptr->name = strdup (name? name: "");
118  ptr->paddr = ptr->vaddr = addr;
119  ptr->size = size;
120  ptr->ordinal = 0;
121  rz_list_append (ret, ptr);
122 }
123 #endif
124 
125 static RzList *symbols(RzBinFile *bf) {
126  return NULL;
127 }
128 
129 static RzList *sections(RzBinFile *bf) {
130  RzList *ret = NULL;
131  // RzBinSection *ptr = NULL;
132  int hdroffset = 0;
133  bool is_hirom = false;
134  int i = 0; // 0x8000-long bank number for loops
135 #if THIS_IS_ALWAYS_FALSE_WTF
136  if ((bf->size & 0x8000) == 0x200) {
137  hdroffset = 0x200;
138  }
139 #endif
140  sfc_int_hdr sfchdr = { { 0 } };
141 
142  int reat = rz_buf_read_at(bf->buf, 0x7FC0 + hdroffset, (ut8 *)&sfchdr, SFC_HDR_SIZE);
143  if (reat != SFC_HDR_SIZE) {
144  RZ_LOG_ERROR("Unable to read SFC/SNES header\n");
145  return NULL;
146  }
147 
148  if ((sfchdr.comp_check != (ut16) ~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 0)) {
149 
150  // if the fixed 0x33 byte or the LoROM indication are not found, then let's try interpreting the ROM as HiROM
151 
152  reat = rz_buf_read_at(bf->buf, 0xFFC0 + hdroffset, (ut8 *)&sfchdr, SFC_HDR_SIZE);
153  if (reat != SFC_HDR_SIZE) {
154  RZ_LOG_ERROR("Unable to read SFC/SNES header\n");
155  return NULL;
156  }
157 
158  if ((sfchdr.comp_check != (ut16) ~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 1)) {
159 
160  RZ_LOG_ERROR("Cannot determine if this is a LoROM or HiROM file\n");
161  return NULL;
162  }
163  is_hirom = true;
164  }
165 
166  if (!(ret = rz_list_new())) {
167  return NULL;
168  }
169 
170  if (is_hirom) {
171  for (i = 0; i < ((bf->size - hdroffset) / 0x8000); i++) {
172  // XXX check integer overflow here
173  addrom(ret, "ROM", i, hdroffset + i * 0x8000, 0x400000 + (i * 0x8000), 0x8000);
174  if (i % 2) {
175  addrom(ret, "ROM_MIRROR", i, hdroffset + i * 0x8000, (i * 0x8000), 0x8000);
176  }
177  }
178 
179  } else {
180  for (i = 0; i < ((bf->size - hdroffset) / 0x8000); i++) {
181 
182  addrom(ret, "ROM", i, hdroffset + i * 0x8000, 0x8000 + (i * 0x10000), 0x8000);
183  }
184  }
185  return ret;
186 }
187 
188 static RzList *mem(RzBinFile *bf) {
189  RzList *ret;
190  RzBinMem *m;
191  RzBinMem *m_bak;
192  if (!(ret = rz_list_new())) {
193  return NULL;
194  }
195  ret->free = free;
196  if (!(m = RZ_NEW0(RzBinMem))) {
197  rz_list_free(ret);
198  return NULL;
199  }
200  m->name = strdup("LOWRAM");
201  m->addr = LOWRAM_START_ADDRESS;
202  m->size = LOWRAM_SIZE;
203  m->perms = rz_str_rwx("rwx");
204  rz_list_append(ret, m);
205 
206  if (!(m = RZ_NEW0(RzBinMem))) {
207  return ret;
208  }
209  m->mirrors = rz_list_new();
210  m->name = strdup("LOWRAM_MIRROR");
212  m->size = LOWRAM_MIRROR_SIZE;
213  m->perms = rz_str_rwx("rwx");
214  rz_list_append(m->mirrors, m);
215  m_bak = m;
216  if (!(m = RZ_NEW0(RzBinMem))) {
217  rz_list_free(m_bak->mirrors);
218  return ret;
219  }
220  m->name = strdup("HIRAM");
221  m->addr = HIRAM_START_ADDRESS;
222  m->size = HIRAM_SIZE;
223  m->perms = rz_str_rwx("rwx");
224  rz_list_append(ret, m);
225  if (!(m = RZ_NEW0(RzBinMem))) {
226  return ret;
227  }
228  m->name = strdup("EXTRAM");
229  m->addr = EXTRAM_START_ADDRESS;
230  m->size = EXTRAM_SIZE;
231  m->perms = rz_str_rwx("rwx");
232  rz_list_append(ret, m);
233  if (!(m = RZ_NEW0(RzBinMem))) {
234  return ret;
235  }
236  m->name = strdup("PPU1_REG");
237  m->addr = PPU1_REG_ADDRESS;
238  m->size = PPU1_REG_SIZE;
239  m->perms = rz_str_rwx("rwx");
240  rz_list_append(ret, m);
241  if (!(m = RZ_NEW0(RzBinMem))) {
242  rz_list_free(ret);
243  return NULL;
244  }
245  m->name = strdup("DSP_REG");
246  m->addr = DSP_REG_ADDRESS;
247  m->size = DSP_REG_SIZE;
248  m->perms = rz_str_rwx("rwx");
249  rz_list_append(ret, m);
250  if (!(m = RZ_NEW0(RzBinMem))) {
251  rz_list_free(ret);
252  return NULL;
253  }
254  m->name = strdup("OLDJOY_REG");
255  m->addr = OLDJOY_REG_ADDRESS;
256  m->size = OLDJOY_REG_SIZE;
257  m->perms = rz_str_rwx("rwx");
258  rz_list_append(ret, m);
259  if (!(m = RZ_NEW0(RzBinMem))) {
260  rz_list_free(ret);
261  return NULL;
262  }
263  m->name = strdup("PPU2_REG");
264  m->addr = PPU2_REG_ADDRESS;
265  m->size = PPU2_REG_SIZE;
266  m->perms = rz_str_rwx("rwx");
267  rz_list_append(ret, m);
268  return ret;
269 }
270 
271 static RzList *entries(RzBinFile *bf) { // Should be 3 offsets pointed by NMI, RESET, IRQ after mapping && default = 1st CHR
272  RzList *ret;
273  if (!(ret = rz_list_new())) {
274  return NULL;
275  }
276  /*
277  RzBinAddr *ptr = NULL;
278  if (!(ptr = RZ_NEW0 (RzBinAddr))) {
279  return ret;
280  }
281  ptr->paddr = INES_HDR_SIZE;
282  ptr->vaddr = ROM_START_ADDRESS;
283  rz_list_append (ret, ptr);
284  */
285  return ret;
286 }
287 
289  .name = "sfc",
290  .desc = "Super NES / Super Famicom ROM file",
291  .license = "LGPL3",
292  .load_buffer = &load_buffer,
293  .check_buffer = &check_buffer,
294  .entries = &entries,
296  .sections = sections,
297  .symbols = &symbols,
298  .info = &info,
299  .mem = &mem,
300 };
301 
302 #ifndef RZ_PLUGIN_INCORE
305  .data = &rz_bin_plugin_sfc,
307 };
308 #endif
lzma_index ** i
Definition: index.h:629
RZ_API RZ_OWN RzList * rz_bin_maps_of_file_sections(RZ_NONNULL RzBinFile *binfile)
Create a list of RzBinMap from RzBinSections queried from the given file.
Definition: bin.c:1040
static void addsym(RzList *ret, const char *name, ut64 addr)
Definition: bin_avr.c:160
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb)
Definition: bin_sfc.c:48
static RzList * mem(RzBinFile *bf)
Definition: bin_sfc.c:188
static RzList * symbols(RzBinFile *bf)
Definition: bin_sfc.c:125
RzBinPlugin rz_bin_plugin_sfc
Definition: bin_sfc.c:288
RZ_API RzLibStruct rizin_plugin
Definition: bin_sfc.c:303
static bool check_buffer(RzBuffer *b)
Definition: bin_sfc.c:9
static RzBinInfo * info(RzBinFile *bf)
Definition: bin_sfc.c:52
static void addrom(RzList *ret, const char *name, int i, ut64 paddr, ut64 vaddr, ut32 size)
Definition: bin_sfc.c:98
static RzList * entries(RzBinFile *bf)
Definition: bin_sfc.c:271
static RzList * sections(RzBinFile *bf)
Definition: bin_sfc.c:129
#define RZ_API
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
uint16_t ut16
uint32_t ut32
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
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")
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
@ RZ_LIB_TYPE_BIN
Definition: rz_lib.h:75
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API int rz_str_rwx(const char *str)
Definition: str.c:318
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_RX
Definition: rz_types.h:97
#define RZ_VERSION
Definition: rz_version.h:8
#define OLDJOY_REG_SIZE
Definition: sfc_specs.h:29
#define OLDJOY_REG_ADDRESS
Definition: sfc_specs.h:28
#define EXTRAM_START_ADDRESS
Definition: sfc_specs.h:43
#define SFC_HDR_SIZE
Definition: sfc_specs.h:13
#define LOWRAM_SIZE
Definition: sfc_specs.h:35
#define HIRAM_START_ADDRESS
Definition: sfc_specs.h:40
#define DSP_REG_ADDRESS
Definition: sfc_specs.h:25
#define PPU1_REG_ADDRESS
Definition: sfc_specs.h:22
#define PPU2_REG_ADDRESS
Definition: sfc_specs.h:31
#define PPU2_REG_SIZE
Definition: sfc_specs.h:32
#define DSP_REG_SIZE
Definition: sfc_specs.h:26
#define PPU1_REG_SIZE
Definition: sfc_specs.h:23
#define EXTRAM_SIZE
Definition: sfc_specs.h:44
#define LOWRAM_START_ADDRESS
Definition: sfc_specs.h:34
#define LOWRAM_MIRROR_START_ADDRESS
Definition: sfc_specs.h:37
#define LOWRAM_MIRROR_SIZE
Definition: sfc_specs.h:38
#define HIRAM_SIZE
Definition: sfc_specs.h:41
#define b(i)
Definition: sha256.c:42
Definition: z80asm.h:102
XX curplugin == o->plugin.
Definition: rz_bin.h:298
char * file
Definition: rz_bin.h:299
RzBuffer * buf
Definition: rz_bin.h:303
int has_va
Definition: rz_bin.h:228
char * type
Definition: rz_bin.h:211
char * os
Definition: rz_bin.h:219
char * machine
Definition: rz_bin.h:216
char * file
Definition: rz_bin.h:210
char * arch
Definition: rz_bin.h:214
RzList * mirrors
Definition: rz_bin.h:784
char * name
Definition: rz_bin.h:509
char * version
Definition: rz_bin.h:512
char * name
Definition: rz_bin.h:619
char * name
Definition: rz_bin.h:675
ut32 ordinal
Definition: rz_bin.h:692
RzListFree free
Definition: rz_list.h:21
Definition: sdb.h:63
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58