Rizin
unix-like reverse engineering framework and cli tools
io_ihex.c File Reference
#include "rz_io.h"
#include "rz_lib.h"
#include "rz_util.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

Go to the source code of this file.

Classes

struct  Rihex
 

Macros

#define SEC_MAX   (sec_size < INT_MAX) ? sec_size : INT_MAX
 

Functions

static bool ihex_write (RzIODesc *desc, Rihex *rih)
 
static int __write (RzIO *io, RzIODesc *fd, const ut8 *buf, int count)
 
static int fw04b (FILE *fd, ut16 eaddr)
 
static int fwblock (FILE *fd, ut8 *b, ut32 start_addr, ut32 size)
 
static int __read (RzIO *io, RzIODesc *fd, ut8 *buf, int count)
 
static int __close (RzIODesc *fd)
 
static ut64 __lseek (struct rz_io_t *io, RzIODesc *fd, ut64 offset, int whence)
 
static bool __plugin_open (RzIO *io, const char *pathname, bool many)
 
static bool ihex_parse (RzBuffer *rbuf, char *str)
 
static RzIODesc__open (RzIO *io, const char *pathname, int rw, int mode)
 
static bool __resize (RzIO *io, RzIODesc *fd, ut64 size)
 

Variables

RzIOPlugin rz_io_plugin_ihex
 
RZ_API RzLibStruct rizin_plugin
 

Macro Definition Documentation

◆ SEC_MAX

#define SEC_MAX   (sec_size < INT_MAX) ? sec_size : INT_MAX

Function Documentation

◆ __close()

static int __close ( RzIODesc fd)
static

Definition at line 139 of file io_ihex.c.

139  {
140  if (!fd || !fd->data) {
141  return -1;
142  }
143  Rihex *rih = fd->data;
144  rz_buf_free(rih->rbuf);
145  free(rih);
146  fd->data = NULL;
147  return 0;
148 }
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
Definition: io_ihex.c:39
RzBuffer * rbuf
Definition: io_ihex.c:41
static const z80_opcode fd[]
Definition: z80_tab.h:997

References fd, free(), NULL, Rihex::rbuf, and rz_buf_free().

◆ __lseek()

static ut64 __lseek ( struct rz_io_t io,
RzIODesc fd,
ut64  offset,
int  whence 
)
static

Definition at line 150 of file io_ihex.c.

150  {
151  Rihex *rih;
152  if (!fd || !fd->data) {
153  return -1;
154  }
155  rih = fd->data;
156  io->off = rz_buf_seek(rih->rbuf, offset, whence);
157  return io->off;
158 }
voidpf uLong offset
Definition: ioapi.h:144
RZ_API st64 rz_buf_seek(RZ_NONNULL RzBuffer *b, st64 addr, int whence)
Modify the current cursor position in the buffer.
Definition: buf.c:1166
ut64 off
Definition: rz_io.h:61

References fd, rz_io_t::off, Rihex::rbuf, and rz_buf_seek().

◆ __open()

static RzIODesc* __open ( RzIO io,
const char *  pathname,
int  rw,
int  mode 
)
static

Definition at line 389 of file io_ihex.c.

389  {
390  Rihex *mal = NULL;
391  char *str = NULL;
392  if (__plugin_open(io, pathname, 0)) {
393  str = rz_file_slurp(pathname + 7, NULL);
394  if (!str) {
395  return NULL;
396  }
397  mal = RZ_NEW0(Rihex);
398  if (!mal) {
399  free(str);
400  return NULL;
401  }
402  mal->rbuf = rz_buf_new_sparse(io->Oxff);
403  if (!mal->rbuf) {
404  free(str);
405  free(mal);
406  return NULL;
407  }
408  if (!ihex_parse(mal->rbuf, str)) {
409  eprintf("ihex: failed to parse file\n");
410  free(str);
411  rz_buf_free(mal->rbuf);
412  free(mal);
413  return NULL;
414  }
415  free(str);
416  return rz_io_desc_new(io, &rz_io_plugin_ihex,
417  pathname, rw, mode, mal);
418  }
419  return NULL;
420 }
RzIOPlugin rz_io_plugin_ihex
Definition: io_ihex.c:436
static bool __plugin_open(RzIO *io, const char *pathname, bool many)
Definition: io_ihex.c:160
static bool ihex_parse(RzBuffer *rbuf, char *str)
Definition: io_ihex.c:167
const char int mode
Definition: ioapi.h:137
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char pathname
Definition: sflib.h:66
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API RZ_OWN RzBuffer * rz_buf_new_sparse(ut8 Oxff)
Creates a sparse buffer.
Definition: buf.c:408
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
RZ_API RzIODesc * rz_io_desc_new(RzIO *io, RzIOPlugin *plugin, const char *uri, int flags, int mode, void *data)
Definition: io_desc.c:11
#define RZ_NEW0(x)
Definition: rz_types.h:284
int Oxff
Definition: rz_io.h:65
static struct @626 mal

References __plugin_open(), eprintf, free(), ihex_parse(), mal, NULL, rz_io_t::Oxff, pathname, rz_buf_free(), rz_buf_new_sparse(), rz_file_slurp(), rz_io_desc_new(), rz_io_plugin_ihex, RZ_NEW0, and cmd_descs_generate::str.

◆ __plugin_open()

static bool __plugin_open ( RzIO io,
const char *  pathname,
bool  many 
)
static

Definition at line 160 of file io_ihex.c.

160  {
161  return (!strncmp(pathname, "ihex://", 7));
162 }

References pathname.

Referenced by __open().

◆ __read()

static int __read ( RzIO io,
RzIODesc fd,
ut8 buf,
int  count 
)
static

Definition at line 124 of file io_ihex.c.

124  {
125  if (!fd || !fd->data || (count <= 0)) {
126  return -1;
127  }
128  Rihex *rih = fd->data;
129  memset(buf, io->Oxff, count);
130  int r = rz_buf_read_at(rih->rbuf, io->off, buf, count);
131  if (r >= 0) {
132  rz_buf_seek(rih->rbuf, r, RZ_BUF_CUR);
133  }
134  // sparse read return >= 0 but < count still means everything was read successfully,
135  // just maybe not entirely populated by chunks:
136  return r < 0 ? -1 : count;
137 }
#define r
Definition: crypto_rc6.c:12
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 count
Definition: sflib.h:98
voidpf void * buf
Definition: ioapi.h:138
return memset(p, 0, total)
#define RZ_BUF_CUR
Definition: rz_buf.h:15
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

References count, fd, memset(), rz_io_t::off, rz_io_t::Oxff, r, Rihex::rbuf, RZ_BUF_CUR, rz_buf_read_at(), and rz_buf_seek().

◆ __resize()

static bool __resize ( RzIO io,
RzIODesc fd,
ut64  size 
)
static

Definition at line 422 of file io_ihex.c.

422  {
423  if (!fd) {
424  return false;
425  }
426  Rihex *rih = fd->data;
427  if (!rih) {
428  return false;
429  }
430  if (!rz_buf_resize(rih->rbuf, size)) {
431  return false;
432  }
433  return ihex_write(fd, rih);
434 }
static bool ihex_write(RzIODesc *desc, Rihex *rih)
Definition: io_ihex.c:330
voidpf void uLong size
Definition: ioapi.h:138
RZ_API bool rz_buf_resize(RZ_NONNULL RzBuffer *b, ut64 newsize)
Resize the buffer size.
Definition: buf.c:890

References fd, ihex_write(), Rihex::rbuf, and rz_buf_resize().

◆ __write()

static int __write ( RzIO io,
RzIODesc fd,
const ut8 buf,
int  count 
)
static

Definition at line 46 of file io_ihex.c.

46  {
47  if (!fd || !fd->data || (fd->perm & RZ_PERM_W) == 0 || count <= 0) {
48  return -1;
49  }
50  Rihex *rih = fd->data;
51  /* mem write */
52  if (rz_buf_write_at(rih->rbuf, io->off, buf, count) != count) {
53  eprintf("ihex:write(): sparse write failed\n");
54  return -1;
55  }
57  if (!ihex_write(fd, rih)) {
58  return -1;
59  }
60  return count;
61 }
RZ_API st64 rz_buf_write_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the specified address.
Definition: buf.c:1197
#define RZ_PERM_W
Definition: rz_types.h:94

References count, eprintf, fd, ihex_write(), rz_io_t::off, Rihex::rbuf, RZ_BUF_CUR, rz_buf_seek(), rz_buf_write_at(), and RZ_PERM_W.

◆ fw04b()

static int fw04b ( FILE *  fd,
ut16  eaddr 
)
static

Definition at line 64 of file io_ihex.c.

64  {
65  ut8 cks = 0 - (6 + (eaddr >> 8) + (eaddr & 0xff));
66  return fprintf(fd, ":02000004%04X%02X\n", eaddr, cks);
67 }
uint8_t ut8
Definition: lh5801.h:11

References fd.

Referenced by fwblock(), and ihex_write().

◆ fwblock()

static int fwblock ( FILE *  fd,
ut8 b,
ut32  start_addr,
ut32  size 
)
static

Definition at line 71 of file io_ihex.c.

71  {
72  ut8 cks;
73  char linebuf[80];
74  ut16 last_addr;
75  int j;
76  ut32 i; // has to be bigger than size !
77 
78  if (size < 1 || size > 0x10000 || !fd || !b) {
79  return -1;
80  }
81 
82  for (i = 0; (i + 0x10) < size; i += 0x10) {
83  cks = 0x10;
84  cks += (i + start_addr) >> 8;
85  cks += (i + start_addr);
86  for (j = 0; j < 0x10; j++) {
87  cks += b[j];
88  }
89  cks = 0 - cks;
90  if (fprintf(fd, ":10%04x00%02x%02x%02x%02x%02x%02x%02x"
91  "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
92  (i + start_addr) & 0xffff, b[0], b[1], b[2], b[3], b[4], b[5], b[6],
93  b[7], b[8], b[9], b[10], b[11], b[12], b[13],
94  b[14], b[15], cks) < 0) {
95  return -1;
96  }
97  b += 0x10;
98  if (((i + start_addr) & 0xffff) < 0x10) {
99  // addr rollover: write ext address record
100  if (fw04b(fd, (i + start_addr) >> 16) < 0) {
101  return -1;
102  }
103  }
104  }
105  if (i == size) {
106  return 0;
107  }
108  // write crumbs
109  last_addr = i + start_addr;
110  cks = -last_addr;
111  cks -= last_addr >> 8;
112  for (j = 0; i < size; i++, j++) {
113  cks -= b[j];
114  sprintf(linebuf + (2 * j), "%02X", b[j]);
115  }
116  cks -= j;
117 
118  if (fprintf(fd, ":%02X%04X00%.*s%02X\n", j, last_addr, 2 * j, linebuf, cks) < 0) {
119  return -1;
120  }
121  return 0;
122 }
lzma_index ** i
Definition: index.h:629
uint16_t ut16
uint32_t ut32
static int fw04b(FILE *fd, ut16 eaddr)
Definition: io_ihex.c:64
sprintf
Definition: kernel.h:365
#define b(i)
Definition: sha256.c:42

References b, fd, fw04b(), i, and sprintf.

Referenced by ihex_write().

◆ ihex_parse()

static bool ihex_parse ( RzBuffer rbuf,
char *  str 
)
static

Definition at line 167 of file io_ihex.c.

167  {
168  ut8 *sec_tmp;
169  ut32 sec_start = 0; // addr for next section write
170  ut32 segreg = 0; // basis for addr fields
171  ut32 addr_tmp = 0; // addr for record
172  ut16 next_addr = 0; // for checking if records are sequential
173  char *eol;
174  ut8 cksum;
175  int extH, extL;
176  int bc = 0, type, byte, i, l;
177  // fugly macro to prevent an overflow of rz_buf_write_at() len
178 #define SEC_MAX (sec_size < INT_MAX) ? sec_size : INT_MAX
179  ut32 sec_size = 0;
180  const int sec_count = UT16_MAX;
181  sec_tmp = calloc(1, sec_count);
182  if (!sec_tmp) {
183  goto fail;
184  }
185  do {
186  l = sscanf(str, ":%02x%04x%02x", &bc, &addr_tmp, &type);
187  if (l != 3) {
188  eprintf("Invalid data in ihex file (%.*s)\n", 80, str);
189  goto fail;
190  }
191  bc &= 0xff;
192  addr_tmp &= 0xffff;
193  type &= 0xff;
194 
195  switch (type) {
196  case 0: // DATA
197  eol = strchr(str + 1, ':');
198  if (eol) {
199  *eol = 0;
200  }
201  cksum = bc;
202  cksum += addr_tmp >> 8;
203  cksum += addr_tmp;
204  cksum += type;
205 
206  if ((next_addr != addr_tmp) || ((sec_size + bc) > SEC_MAX)) {
207  // previous block is not contiguous, or
208  // section buffer is full => write a sparse chunk
209  if (sec_size && sec_size < UT16_MAX) {
210  if (rz_buf_write_at(rbuf, sec_start, sec_tmp, (int)sec_size) != sec_size) {
211  eprintf("sparse buffer problem, giving up\n");
212  goto fail;
213  }
214  }
215  // advance cursor, reset section
216  sec_start = segreg + addr_tmp;
217  next_addr = addr_tmp;
218  sec_size = 0;
219  }
220 
221  for (i = 0; i < bc; i++) {
222  if (sscanf(str + 9 + (i * 2), "%02x", &byte) != 1) {
223  eprintf("unparsable data !\n");
224  goto fail;
225  }
226  if (sec_size + i < sec_count) {
227  sec_tmp[sec_size + i] = (ut8)byte & 0xff;
228  }
229  cksum += byte;
230  }
231  sec_size += bc;
232  next_addr += bc;
233  if (eol) {
234  // checksum
235  if (sscanf(str + 9 + (i * 2), "%02x", &byte) != 1) {
236  eprintf("unparsable data !\n");
237  goto fail;
238  }
239  cksum += byte;
240  if (cksum != 0) {
241  ut8 fixedcksum = 0 - (cksum - byte);
242  eprintf("Checksum failed %02x (got %02x expected %02x)\n",
243  cksum, byte, fixedcksum);
244  goto fail;
245  }
246  *eol = ':';
247  }
248  str = eol;
249  break;
250  case 1: // EOF. we don't validate checksum here
251  if (sec_size) {
252  if (rz_buf_write_at(rbuf, sec_start, sec_tmp, sec_size) != sec_size) {
253  eprintf("sparse buffer problem, giving up. ssiz=%X, sstart=%X\n", sec_size, sec_start);
254  goto fail;
255  }
256  }
257  str = NULL;
258  break;
259  case 2: // extended segment record
260  case 4: // extended linear address rec
261  // both rec types are handled the same except :
262  // new address = seg_reg <<4 for type 02; new address = lin_addr <<16 for type 04.
263  // write current section
264  if (sec_size) {
265  if (rz_buf_write_at(rbuf, sec_start, sec_tmp, sec_size) != sec_size) {
266  eprintf("sparse buffer problem, giving up\n");
267  goto fail;
268  }
269  }
270  sec_size = 0;
271 
272  eol = strchr(str + 1, ':');
273  if (eol) {
274  *eol = 0;
275  }
276  cksum = bc;
277  cksum += addr_tmp >> 8;
278  cksum += addr_tmp;
279  cksum += type;
280  if ((bc != 2) || (addr_tmp != 0)) {
281  eprintf("invalid type 02/04 record!\n");
282  goto fail;
283  }
284  if ((sscanf(str + 9 + 0, "%02x", &extH) != 1) ||
285  (sscanf(str + 9 + 2, "%02x", &extL) != 1)) {
286  eprintf("unparsable data !\n");
287  goto fail;
288  }
289  extH &= 0xff;
290  extL &= 0xff;
291  cksum += extH + extL;
292 
293  segreg = extH << 8 | extL;
294 
295  // segment rec(02) gives bits 4..19; linear rec(04) is bits 16..31
296  segreg = segreg << ((type == 2) ? 4 : 16);
297  next_addr = 0;
298  sec_start = segreg;
299 
300  if (eol) {
301  // checksum
302  byte = 0; // break checksum if sscanf failed
303  if (sscanf(str + 9 + 4, "%02x", &byte) != 1) {
304  cksum = 1;
305  }
306  cksum += byte;
307  if (cksum != 0) {
308  ut8 fixedcksum = 0 - (cksum - byte);
309  eprintf("Checksum failed %02x (got %02x expected %02x)\n",
310  cksum, byte, fixedcksum);
311  goto fail;
312  }
313  *eol = ':';
314  }
315  str = eol;
316  break;
317  case 3: // undefined rec. Just skip.
318  case 5: // non-standard, sometimes "start linear address"
319  str = strchr(str + 1, ':');
320  break;
321  }
322  } while (str);
323  free(sec_tmp);
324  return true;
325 fail:
326  free(sec_tmp);
327  return false;
328 }
#define ut8
Definition: dcpu16.h:8
#define SEC_MAX
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
int type
Definition: mipsasm.c:17
#define UT16_MAX
#define fail(test)
Definition: tests.h:29

References calloc(), eprintf, fail, free(), i, NULL, rz_buf_write_at(), SEC_MAX, cmd_descs_generate::str, type, UT16_MAX, and ut8.

Referenced by __open().

◆ ihex_write()

static bool ihex_write ( RzIODesc desc,
Rihex rih 
)
static

Definition at line 330 of file io_ihex.c.

330  {
331  const char *pathname = desc->name + 7;
332  FILE *out = rz_sys_fopen(pathname, "w");
333  if (!out) {
334  eprintf("Cannot open '%s' for writing\n", pathname);
335  return false;
336  }
337  // disk write : process each sparse chunk
338  size_t chunks_count;
339  const RzBufferSparseChunk *chunks = rz_buf_sparse_get_chunks(rih->rbuf, &chunks_count);
340  ut64 addh_cur = 0;
341  for (size_t i = 0; i < chunks_count; i++) {
342  const RzBufferSparseChunk *rbs = &chunks[i];
343  ut64 from = rbs->from;
344  while (from >> 16 != rbs->to >> 16) {
345  // we cross a 64k boundary, so write in multiple steps
346  ut16 addl = from & 0xffff;
347  ut16 addh = from >> 16;
348  if (addh != addh_cur) {
349  addh_cur = addh;
350  // 04 record (ext address)
351  if (fw04b(out, addh) < 0) {
352  eprintf("ihex:write: file error\n");
353  fclose(out);
354  return false;
355  }
356  }
357  // 00 records (data)
358  ut32 tsiz = (ut32)0x10000 - (ut32)addl;
359  if (fwblock(out, rbs->data + (from - rbs->from), from, tsiz)) {
360  eprintf("ihex:fwblock error\n");
361  fclose(out);
362  return false;
363  }
364  from = ((from >> 16) + 1) << 16;
365  }
366  ut16 addh = from >> 16;
367  if (addh != addh_cur) {
368  addh_cur = addh;
369  // 04 record (ext address)
370  if (fw04b(out, addh) < 0) {
371  eprintf("ihex:write: file error\n");
372  fclose(out);
373  return false;
374  }
375  }
376  // 00 records (remaining data)
377  if (fwblock(out, rbs->data + (from - rbs->from), from, rbs->to - from + 1)) {
378  eprintf("ihex:fwblock error 2\n");
379  fclose(out);
380  return false;
381  }
382  }
383 
384  fprintf(out, ":00000001FF\n");
385  fclose(out);
386  return true;
387 }
const char * desc
Definition: bin_vsf.c:19
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static int fwblock(FILE *fd, ut8 *b, ut32 start_addr, ut32 size)
Definition: io_ihex.c:71
string FILE
Definition: benchmark.py:21
RZ_API const RzBufferSparseChunk * rz_buf_sparse_get_chunks(RzBuffer *b, RZ_NONNULL size_t *count)
Only for sparse RzBuffers, get all sparse data chunks currently populated.
Definition: buf_sparse.c:313
RZ_API FILE * rz_sys_fopen(const char *path, const char *mode)
Definition: sys.c:1815
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
ut8 * data
size == to - from + 1
Definition: rz_buf.h:56
ut64 from
inclusive
Definition: rz_buf.h:54
ut64 to
inclusive, there can't be chunks with size == 0
Definition: rz_buf.h:55
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References rz_buf_sparse_chunk_t::data, desc, eprintf, benchmark::FILE, rz_buf_sparse_chunk_t::from, from, fw04b(), fwblock(), i, out, pathname, Rihex::rbuf, rz_buf_sparse_get_chunks(), rz_sys_fopen(), rz_buf_sparse_chunk_t::to, and ut64().

Referenced by __resize(), and __write().

Variable Documentation

◆ rizin_plugin

RZ_API RzLibStruct rizin_plugin
Initial value:
= {
.type = RZ_LIB_TYPE_IO,
}
@ RZ_LIB_TYPE_IO
Definition: rz_lib.h:69
#define RZ_VERSION
Definition: rz_version.h:8
const char * version
Definition: rz_io.h:117

Definition at line 451 of file io_ihex.c.

◆ rz_io_plugin_ihex

RzIOPlugin rz_io_plugin_ihex
Initial value:
= {
.name = "ihex",
.desc = "Open intel HEX file",
.uris = "ihex://",
.license = "LGPL",
.open = __open,
.close = __close,
.read = __read,
.check = __plugin_open,
.lseek = __lseek,
.write = __write,
.resize = __resize
}
static ut64 __lseek(struct rz_io_t *io, RzIODesc *fd, ut64 offset, int whence)
Definition: io_ihex.c:150
static int __read(RzIO *io, RzIODesc *fd, ut8 *buf, int count)
Definition: io_ihex.c:124
static RzIODesc * __open(RzIO *io, const char *pathname, int rw, int mode)
Definition: io_ihex.c:389
static bool __resize(RzIO *io, RzIODesc *fd, ut64 size)
Definition: io_ihex.c:422
static int __write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count)
Definition: io_ihex.c:46
static int __close(RzIODesc *fd)
Definition: io_ihex.c:139

Definition at line 436 of file io_ihex.c.

Referenced by __open().