rdoff: use nasm-provided safe memory allocation and I/O
[nasm.git] / rdoff / rdoff.c
bloba015acdc7fca362fafbcd63484f34ebef7d9b199
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2014 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * rdoff.c library of routines for manipulating rdoff files
38 /* TODO: The functions in this module assume they are running
39 * on a little-endian machine. This should be fixed to
40 * make it portable.
43 #include "compiler.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
50 #include "rdfutils.h"
53 * Comment this out to allow the module to read & write header record types
54 * that it isn't aware of. With this defined, unrecognised header records
55 * will generate error number 8, reported as 'unknown extended header record'.
58 #define STRICT_ERRORS
60 /* ========================================================================
61 * Code for memory buffers (for delayed writing of header until we know
62 * how int32_t it is).
63 * ======================================================================== */
65 static memorybuffer *newmembuf(void)
67 memorybuffer *t;
69 t = nasm_malloc(sizeof(memorybuffer));
70 if (!t)
71 return NULL;
73 t->length = 0;
74 t->next = NULL;
75 return t;
78 static void membufwrite(memorybuffer * const b, void *data, int bytes)
80 uint16_t w;
81 int32_t l;
82 char *c;
84 if (b->next) { /* memory buffer full - use next buffer */
85 membufwrite(b->next, data, bytes);
86 return;
89 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
90 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
92 /* buffer full and no next allocated... allocate and initialise next
93 * buffer */
94 b->next = newmembuf();
95 membufwrite(b->next, data, bytes);
96 return;
99 switch (bytes) {
100 case -4: /* convert to little-endian */
101 l = *(int32_t *)data;
102 b->buffer[b->length++] = l & 0xFF;
103 l >>= 8;
104 b->buffer[b->length++] = l & 0xFF;
105 l >>= 8;
106 b->buffer[b->length++] = l & 0xFF;
107 l >>= 8;
108 b->buffer[b->length++] = l & 0xFF;
109 break;
111 case -2:
112 w = *(uint16_t *) data;
113 b->buffer[b->length++] = w & 0xFF;
114 w >>= 8;
115 b->buffer[b->length++] = w & 0xFF;
116 break;
118 default:
119 c = data;
120 while (bytes--)
121 b->buffer[b->length++] = *c++;
122 break;
126 static void membufdump(memorybuffer * b, FILE * fp)
128 if (!b)
129 return;
131 nasm_write(b->buffer, b->length, fp);
132 membufdump(b->next, fp);
135 static int membuflength(memorybuffer * b)
137 if (!b)
138 return 0;
139 return b->length + membuflength(b->next);
142 static void freemembuf(memorybuffer * b)
144 if (!b)
145 return;
146 freemembuf(b->next);
147 nasm_free(b);
150 /* =========================================================================
151 General purpose routines and variables used by the library functions
152 ========================================================================= */
155 * translateint32_t() and translateint16_t()
157 * translate from little endian to local representation
159 int32_t translateint32_t(int32_t in)
161 int32_t r;
162 uint8_t *i;
164 i = (uint8_t *)&in;
165 r = i[3];
166 r = (r << 8) + i[2];
167 r = (r << 8) + i[1];
168 r = (r << 8) + *i;
170 return r;
173 uint16_t translateint16_t(uint16_t in)
175 uint16_t r;
176 uint8_t *i;
178 i = (uint8_t *)&in;
179 r = (i[1] << 8) + i[0];
181 return r;
184 /* Segment types */
185 static char *knownsegtypes[8] = {
186 "NULL", "text", "data", "object comment",
187 "linked comment", "loader comment",
188 "symbolic debug", "line number debug"
191 /* Get a textual string describing the segment type */
192 char *translatesegmenttype(uint16_t type)
194 if (type < 8)
195 return knownsegtypes[type];
196 if (type < 0x0020)
197 return "reserved";
198 if (type < 0x1000)
199 return "reserved - Moscow";
200 if (type < 0x8000)
201 return "reserved - system dependant";
202 if (type < 0xFFFF)
203 return "reserved - other";
204 if (type == 0xFFFF)
205 return "invalid type code";
206 return "type code out of range";
209 /* This signature is written to the start of RDOFF files */
210 const char *RDOFFId = RDOFF2_SIGNATURE;
212 /* Error messages. Must correspond to the codes defined in rdoff.h */
213 const char *rdf_errors[11] = {
214 /* 0 */ "no error occurred",
215 /* 1 */ "could not open file",
216 /* 2 */ "invalid file format",
217 /* 3 */ "error reading file",
218 /* 4 */ "unknown error",
219 /* 5 */ "header not read",
220 /* 6 */ "out of memory",
221 /* 7 */ "RDOFF v1 not supported",
222 /* 8 */ "unknown extended header record",
223 /* 9 */ "header record of known type but unknown length",
224 /* 10 */ "no such segment"
227 int rdf_errno = 0;
229 /* ========================================================================
230 * Hook for nasm_error() to work
231 * ======================================================================== */
232 static void rdoff_verror(int severity, const char *fmt, va_list val)
234 vfprintf(stderr, fmt, val);
236 if ((severity & ERR_MASK) >= ERR_FATAL)
237 exit(1);
240 void rdoff_init(void)
242 nasm_set_verror(rdoff_verror);
245 /* ========================================================================
246 The library functions
247 ======================================================================== */
249 int rdfopen(rdffile * f, const char *name)
251 FILE *fp;
253 fp = fopen(name, "rb");
254 if (!fp)
255 return rdf_errno = RDF_ERR_OPEN;
257 return rdfopenhere(f, fp, NULL, name);
260 int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name)
262 char buf[8];
263 int32_t initpos;
264 int32_t l;
265 uint16_t s;
267 if (translateint32_t(0x01020304) != 0x01020304) {
268 /* fix this to be portable! */
269 fputs("*** this program requires a little endian machine\n",
270 stderr);
271 fprintf(stderr, "01020304h = %08"PRIx32"h\n", translateint32_t(0x01020304));
272 exit(3);
275 f->fp = fp;
276 initpos = ftell(fp);
278 fread(buf, 6, 1, f->fp); /* read header */
279 buf[6] = 0;
281 if (strcmp(buf, RDOFFId)) {
282 fclose(f->fp);
283 if (!strcmp(buf, "RDOFF1"))
284 return rdf_errno = RDF_ERR_VER;
285 return rdf_errno = RDF_ERR_FORMAT;
288 if (fread(&l, 1, 4, f->fp) != 4
289 || fread(&f->header_len, 1, 4, f->fp) != 4) {
290 fclose(f->fp);
291 return rdf_errno = RDF_ERR_READ;
294 f->header_ofs = ftell(f->fp);
295 f->eof_offset = f->header_ofs + translateint32_t(l) - 4;
297 if (fseek(f->fp, f->header_len, SEEK_CUR)) {
298 fclose(f->fp);
299 return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
302 if (fread(&s, 1, 2, f->fp) != 2) {
303 fclose(f->fp);
304 return rdf_errno = RDF_ERR_READ;
307 f->nsegs = 0;
309 while (s != 0) {
310 f->seg[f->nsegs].type = s;
311 if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 ||
312 fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 ||
313 fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) {
314 fclose(f->fp);
315 return rdf_errno = RDF_ERR_READ;
318 f->seg[f->nsegs].offset = ftell(f->fp);
319 if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) {
320 fclose(f->fp);
321 return rdf_errno = RDF_ERR_FORMAT;
323 f->nsegs++;
325 if (fread(&s, 1, 2, f->fp) != 2) {
326 fclose(f->fp);
327 return rdf_errno = RDF_ERR_READ;
331 if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
332 fprintf(stderr, "warning: eof_offset [%"PRId32"] and actual eof offset "
333 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
335 fseek(f->fp, initpos, SEEK_SET);
336 f->header_loc = NULL;
338 f->name = nasm_strdup(name);
339 f->refcount = refcount;
340 if (refcount)
341 (*refcount)++;
342 return RDF_OK;
345 int rdfclose(rdffile * f)
347 if (!f->refcount || !--(*f->refcount)) {
348 fclose(f->fp);
349 f->fp = NULL;
351 nasm_free(f->name);
353 return 0;
357 * Print the message for last error (from rdf_errno)
359 void rdfperror(const char *app, const char *name)
361 fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]);
362 if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
363 perror(app);
368 * Find the segment by its number.
369 * Returns segment array index, or -1 if segment with such number was not found.
371 int rdffindsegment(rdffile * f, int segno)
373 int i;
374 for (i = 0; i < f->nsegs; i++)
375 if (f->seg[i].number == segno)
376 return i;
377 return -1;
381 * Load the segment. Returns status.
383 int rdfloadseg(rdffile * f, int segment, void *buffer)
385 int32_t fpos;
386 size_t slen;
388 switch (segment) {
389 case RDOFF_HEADER:
390 fpos = f->header_ofs;
391 slen = f->header_len;
392 f->header_loc = (uint8_t *) buffer;
393 f->header_fp = 0;
394 break;
395 default:
396 if (segment < f->nsegs) {
397 fpos = f->seg[segment].offset;
398 slen = f->seg[segment].length;
399 f->seg[segment].data = (uint8_t *) buffer;
400 } else {
401 return rdf_errno = RDF_ERR_SEGMENT;
405 if (fseek(f->fp, fpos, SEEK_SET))
406 return rdf_errno = RDF_ERR_UNKNOWN;
408 if (fread(buffer, 1, slen, f->fp) != slen)
409 return rdf_errno = RDF_ERR_READ;
411 return RDF_OK;
414 /* Macros for reading integers from header in memory */
416 #define RI8(v) v = f->header_loc[f->header_fp++]
417 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
418 (f->header_loc[f->header_fp+1] << 8)); \
419 f->header_fp += 2; }
421 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
422 (f->header_loc[f->header_fp+1] << 8) + \
423 (f->header_loc[f->header_fp+2] << 16) + \
424 (f->header_loc[f->header_fp+3] << 24)); \
425 f->header_fp += 4; }
427 #define RS(str,max) { for(i=0;i<max;i++){\
428 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
431 * Read a header record.
432 * Returns the address of record, or NULL in case of error.
434 rdfheaderrec *rdfgetheaderrec(rdffile * f)
436 static rdfheaderrec r;
437 int i;
439 if (!f->header_loc) {
440 rdf_errno = RDF_ERR_HEADER;
441 return NULL;
444 if (f->header_fp >= f->header_len)
445 return 0;
447 RI8(r.type);
448 RI8(r.g.reclen);
450 switch (r.type) {
451 case RDFREC_RELOC: /* Relocation record */
452 case RDFREC_SEGRELOC:
453 if (r.r.reclen != 8) {
454 rdf_errno = RDF_ERR_RECLEN;
455 return NULL;
457 RI8(r.r.segment);
458 RI32(r.r.offset);
459 RI8(r.r.length);
460 RI16(r.r.refseg);
461 break;
463 case RDFREC_IMPORT: /* Imported symbol record */
464 case RDFREC_FARIMPORT:
465 RI8(r.i.flags);
466 RI16(r.i.segment);
467 RS(r.i.label, EXIM_LABEL_MAX);
468 break;
470 case RDFREC_GLOBAL: /* Exported symbol record */
471 RI8(r.e.flags);
472 RI8(r.e.segment);
473 RI32(r.e.offset);
474 RS(r.e.label, EXIM_LABEL_MAX);
475 break;
477 case RDFREC_DLL: /* DLL record */
478 RS(r.d.libname, MODLIB_NAME_MAX);
479 break;
481 case RDFREC_BSS: /* BSS reservation record */
482 if (r.r.reclen != 4) {
483 rdf_errno = RDF_ERR_RECLEN;
484 return NULL;
486 RI32(r.b.amount);
487 break;
489 case RDFREC_MODNAME: /* Module name record */
490 RS(r.m.modname, MODLIB_NAME_MAX);
491 break;
493 case RDFREC_COMMON: /* Common variable */
494 RI16(r.c.segment);
495 RI32(r.c.size);
496 RI16(r.c.align);
497 RS(r.c.label, EXIM_LABEL_MAX);
498 break;
500 default:
501 #ifdef STRICT_ERRORS
502 rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
503 return NULL;
504 #else
505 for (i = 0; i < r.g.reclen; i++)
506 RI8(r.g.data[i]);
507 #endif
509 return &r;
513 * Rewind to the beginning of the file
515 void rdfheaderrewind(rdffile * f)
517 f->header_fp = 0;
520 rdf_headerbuf *rdfnewheader(void)
522 rdf_headerbuf *hb = nasm_malloc(sizeof(rdf_headerbuf));
523 if (hb == NULL)
524 return NULL;
526 hb->buf = newmembuf();
527 hb->nsegments = 0;
528 hb->seglength = 0;
530 return hb;
533 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
535 #ifndef STRICT_ERRORS
536 int i;
537 #endif
538 membufwrite(h->buf, &r->type, 1);
539 membufwrite(h->buf, &r->g.reclen, 1);
541 switch (r->type) {
542 case RDFREC_GENERIC: /* generic */
543 membufwrite(h->buf, &r->g.data, r->g.reclen);
544 break;
545 case RDFREC_RELOC:
546 case RDFREC_SEGRELOC:
547 membufwrite(h->buf, &r->r.segment, 1);
548 membufwrite(h->buf, &r->r.offset, -4);
549 membufwrite(h->buf, &r->r.length, 1);
550 membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */
551 break;
553 case RDFREC_IMPORT: /* import */
554 case RDFREC_FARIMPORT:
555 membufwrite(h->buf, &r->i.flags, 1);
556 membufwrite(h->buf, &r->i.segment, -2);
557 membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1);
558 break;
560 case RDFREC_GLOBAL: /* export */
561 membufwrite(h->buf, &r->e.flags, 1);
562 membufwrite(h->buf, &r->e.segment, 1);
563 membufwrite(h->buf, &r->e.offset, -4);
564 membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1);
565 break;
567 case RDFREC_DLL: /* DLL */
568 membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1);
569 break;
571 case RDFREC_BSS: /* BSS */
572 membufwrite(h->buf, &r->b.amount, -4);
573 break;
575 case RDFREC_MODNAME: /* Module name */
576 membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1);
577 break;
579 default:
580 #ifdef STRICT_ERRORS
581 return rdf_errno = RDF_ERR_RECTYPE;
582 #else
583 for (i = 0; i < r->g.reclen; i++)
584 membufwrite(h->buf, r->g.data[i], 1);
585 #endif
587 return 0;
590 int rdfaddsegment(rdf_headerbuf * h, int32_t seglength)
592 h->nsegments++;
593 h->seglength += seglength;
594 return 0;
597 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
599 int32_t l, l2;
601 nasm_write(RDOFFId, strlen(RDOFFId), fp);
603 l = membuflength(h->buf);
604 l2 = l + 14 + 10 * h->nsegments + h->seglength;
605 fwriteint32_t(l, fp);
606 fwriteint32_t(l2, fp);
608 membufdump(h->buf, fp);
610 return 0; /* no error handling in here... CHANGE THIS! */
613 void rdfdoneheader(rdf_headerbuf * h)
615 freemembuf(h->buf);
616 nasm_free(h);