source: rtems/tools/build/unhex.c @ dad79bb9

5
Last change on this file since dad79bb9 was dad79bb9, checked in by Joel Sherrill <joel@…>, on 02/07/18 at 17:18:38

unhex.c: Remove unnecessary extern of errno

Closes #2610.

  • Property mode set to 100644
File size: 19.0 KB
Line 
1/*
2 * unhex
3 *      convert a hex file to binary equivalent.  If more than one file name
4 *      is given, then the output will be logically concatenated together.
5 *      stdin and stdout are defaults. Verbose will enable checksum output.
6 *
7 *  Supported input formats are Intel hex, Motorola S records, and TI 'B'
8 *  records.
9 *
10 * Intel hex input format is
11 *      Byte
12 *       1          Colon :
13 *       2..3       Record length, eg: "20"
14 *       4..7       load address nibbles
15 *       8..9       record type: "00" (data) or "02" base addr
16 *       10..x      data bytes in ascii-hex
17 *       x+1..x+2   cksum (2's compl of (len+addr+data))
18 *       x+3        \n -- newline
19 */
20
21char *USAGE = "\
22usage:    unhex [-va] [ -o file ] [ file [file ... ] ]\n\
23                -v          -- verbose\n\
24                -a base     -- 1st byte of output corresponds to this address\n\
25                -l          -- linear, just writes data out\n\
26                -o file     -- output file; must not be input file\n\
27                -F k_bits   -- \"holes\" in input will be filled with 0xFF's\n\
28                                  up to \"k_bits\" * 1024 bits\n\
29";
30
31#include <stdio.h>
32#include <fcntl.h>
33#include <ctype.h>
34#include <string.h>
35#include <unistd.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <errno.h>
39#include <assert.h>
40
41#include "config.h"
42
43#ifndef VMS
44#ifndef HAVE_STRERROR
45extern int sys_nerr;
46extern char *sys_errlist[];
47
48#define strerror( _err ) \
49  ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
50
51#else   /* HAVE_STRERROR */
52char *strerror ();
53#endif
54#else   /* VMS */
55char *strerror (int,...);
56#endif
57
58
59#define OK      0
60#define FAILURE (-1)
61#define Failed(x)       ((x) == FAILURE)
62#define TRUE    1
63#define FALSE   0
64typedef char bool;
65#define STREQ(a,b)      (strcmp(a,b) == 0)
66
67typedef unsigned char u8;
68typedef unsigned short u16;
69typedef unsigned long u32;
70
71/*
72 * Pick out designated bytes
73 */
74
75#define B0(x)       (((u32)x) & 0xff)
76#define B1(x)       B0(((u32)x) >> 8)
77#define B2(x)       B0(((u32)x) >> 16)
78#define B3(x)       B0(((u32)x) >> 24)
79
80typedef struct buffer_rec {
81    u32 dl_destaddr;
82    u32 dl_jumpaddr;
83    int dl_count;
84    u8  dl_buf[512];
85} buffer_rec;
86
87/*
88 * vars controlled by command line options
89 */
90
91bool verbose = FALSE;                   /* be verbose */
92bool linear = FALSE;                    /* just write out linear data */
93char *outfilename = "-";                /* default output is stdout */
94u32 base = 0L;                         /* base address */
95u32 FFfill = 0L;                       /* how far to fill w 0xFF's */
96
97extern char *optarg;                    /* getopt(3) control vars */
98extern int optind;
99
100char *progname;                         /* for error() */
101
102void error(int errn, ...);
103#define ERR_ERRNO  (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
104#define ERR_FATAL  (ERR_ERRNO / 2)              /* error is fatal; no return */
105#define ERR_ABORT  (ERR_ERRNO / 4)              /* error is fatal; abort */
106#define ERR_MASK   (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
107
108#ifdef HAVE_STRTOUL
109#define stol(p) strtoul(p, (char **) NULL, 0)
110#else
111#define stol(p) strtol(p, (char **) NULL, 0)
112#endif
113
114int   unhex(FILE *ifp, char *inm, FILE *ofp, char *onm);
115int   convert_Intel_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
116int   convert_S_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
117int   convert_TI_records(FILE *ifp, char *inm, FILE *ofp, char *onm);
118void  write_record(buffer_rec *tb, FILE *fp);
119int   getnibble(char **p);
120int   getbyte(char **p);
121long  getNbytes(char **p, int n);
122void  badformat(char *s, char *fname, char *msg);
123void  fix_string_from_gets(char *s, size_t max);
124
125#define get1bytes(p)    (getbyte(p))
126#define get2bytes(p)    getNbytes(p, 2)
127#define get3bytes(p)    getNbytes(p, 3)
128#define get4bytes(p)    getNbytes(p, 4)
129
130char *BADADDR = "Invalid record address";
131char *BADLEN  = "Invalid record length";
132char *BADBASE = "Bad base or starting address";
133char *BADFMT =  "Unrecognized record type";
134char *BADDATA = "Invalid data byte";
135char *BADCSUM = "Invalid checksum";
136char *MISCSUM = "Checksum mismatch";
137char *BADTYPE = "Unrecognized record type";
138char *MISTYPE = "Incompatible record types";
139
140int main(
141  int argc,
142  char **argv
143)
144{
145    int c;
146    bool showusage = FALSE;                     /* usage error? */
147    int rc = 0;
148    FILE *outfp, *infp;
149    long base_long = 0;
150
151    /*
152     * figure out invocation leaf-name
153     */
154    if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
155        progname = argv[0];
156    else
157        progname++;
158
159    argv[0] = progname;                         /* for getopt err reporting */
160
161    /*
162     *  Check options and arguments.
163     */
164    progname = argv[0];
165    while ((c = getopt(argc, argv, "F:a:o:vl")) != EOF) {
166        switch (c) {
167            case 'a':                           /* base address */
168                base_long = stol(optarg);
169                if (base_long < 0) {
170                    (void) fprintf(stderr, "%s", USAGE);
171                    (void) fprintf(stderr, "\n*** base is an illegal value\n" );
172                    exit(1);
173                }
174                base = (u32) base_long;
175
176                break;
177
178            case 'l':                           /* linear output */
179                linear = TRUE;
180                break;
181
182            case 'v':                           /* toggle verbose */
183                verbose = ! verbose;
184                break;
185
186            case 'o':                           /* output file */
187                outfilename = optarg;
188                break;
189
190            case 'F':                           /* 0xFF fill amount (bytes) */
191                FFfill = stol(optarg) * 1024L / 8L;
192                break;
193
194            case '?':
195                showusage = TRUE;
196        }
197    }
198
199    if (showusage) {
200        (void) fprintf(stderr, "%s", USAGE);
201        exit(1);
202    }
203
204    if (linear && (base != 0)) {
205        error(0, "-l and -a may not be specified in combination");
206        exit(1);
207    }
208
209    if (STREQ(outfilename, "-")) {
210        outfp = stdout;
211        outfilename = "stdout";
212    } else if ((outfp = fopen(outfilename, "w")) == (FILE *) NULL) {
213        error(-1, "couldn't open '%s' for output", outfilename);
214        exit(1);
215    }
216
217    /*
218     * Now process the input files (or stdin, if none specified)
219     */
220    if (argc == optind)          /* just stdin */
221        exit(unhex(stdin, "stdin", outfp, outfilename));
222    else
223        for (; optind < argc ; optind++) {
224            optarg = argv[optind];
225            if (STREQ(optarg, "-")) {
226                rc += unhex(stdin, "stdin", outfp, outfilename);
227            } else {
228                if ((infp = fopen(optarg, "r")) == (FILE *) NULL) {
229                    error(-1, "couldn't open '%s' for input", optarg);
230                    exit(1);
231                }
232                rc += unhex(infp, optarg, outfp, outfilename);
233                fclose(infp);
234            }
235        }
236
237    fclose(outfp);
238    return(rc);
239}
240
241u16 filesum;
242
243int
244unhex(FILE *ifp,
245      char *inm,
246      FILE *ofp,
247      char *onm)
248{
249    int c;
250
251    filesum = 0;
252
253    /*
254     * Make sure holes will be filled with 0xFF's if requested.  We
255     *  do this the easy way by just filling the file with FF's before
256     *  getting started.  To do it more optimally would be quite a bit
257     *  more difficult since the user can skip around as much as he/she
258     *  likes in the input hex file addressing.
259     *
260     *  We'll clean this up later (after this program has run) with
261     *  'stripffs'
262     */
263
264    if (FFfill) {
265        (void) fseek(ofp, 0, 0);
266        for (c = FFfill; c > 0; c--)
267            (void) fputc(0xFF, ofp);
268    }
269
270    /*
271     * Read the first char from file and determine record types
272     */
273
274    if ((c = getc(ifp)) != EOF) {
275        ungetc(c, ifp);
276        switch(c) {
277            case 'S':
278                convert_S_records(ifp, inm, ofp, onm);
279                break;
280
281            case ':':
282                convert_Intel_records(ifp, inm, ofp, onm);
283                break;
284
285            case '9':
286            case 'B':
287                convert_TI_records(ifp, inm, ofp, onm);
288                break;
289
290            default:
291            {
292                char tmp[2];
293                tmp[0] = (char) (c & 0x7f);
294                tmp[1] = 0;
295                badformat(tmp, inm, BADFMT);
296            }
297        }
298    }
299
300    if (verbose)
301        fprintf(stderr, "'%s' checksum is 0x%04x\n", inm, filesum);
302
303    return 0;
304}
305
306int
307convert_Intel_records(
308    FILE *ifp,
309    char *inm,
310    FILE *ofp,
311    char *onm)
312{
313    char buff[512];
314    char *p;
315    u8 cksum;
316    int incksum;
317    int c;
318    int rectype;                    /* record type */
319    long len;                        /* data length of current line */
320    u32 addr;
321    u32 base_address = 0;
322    bool endrecord = FALSE;
323    buffer_rec tb;
324    long getBytesStatus;
325
326    while ( !endrecord && (fgets(buff, sizeof(buff), ifp)) ) {
327        p = &buff[0];
328
329        fix_string_from_gets(p, sizeof(buff));
330
331        tb.dl_count = 0;
332
333        if (*p != ':')
334            badformat(p, inm, BADFMT);
335        p++;
336
337        if ((len = getbyte(&p)) == -1)      /* record len */
338            badformat(buff, inm, BADLEN);
339
340        if ((getBytesStatus = get2bytes(&p)) == -1L)          /* record addr */
341            badformat(buff, inm, BADADDR);
342        addr = (u32) getBytesStatus;
343
344        rectype = getbyte(&p);
345
346        cksum = len + B0(addr) + B1(addr) + rectype;
347
348        switch (rectype) {
349            case 0x00:                  /* normal data record */
350                tb.dl_destaddr = (u32) base_address + addr;
351                while (len--)
352                {
353                    if ((c = getbyte(&p)) == -1)
354                        badformat(buff, inm, BADDATA);
355                    cksum += c;
356                    filesum += c;
357                    tb.dl_buf[tb.dl_count++] = c;
358                }
359                break;
360
361            case 0x01:                  /* execution start address */
362                base_address = addr;
363                endrecord = TRUE;
364                break;
365
366            case 0x02:                  /* new base */
367            {
368                long blong;
369                if ((blong = get2bytes(&p)) == -1L)
370                    badformat(buff, inm, BADBASE);
371                base_address = (u32) blong;
372                cksum += B0(base_address) + B1(base_address);
373                base_address <<= 4;
374                break;
375            }
376            case 0x03:                  /* seg/off execution start address */
377            {
378                long seg, off;
379
380                seg = get2bytes(&p);
381                off = get2bytes(&p);
382                if ((seg == -1L) || (off == -1L))
383                    badformat(buff, inm, BADADDR);
384
385                cksum += B0(seg) + B1(seg) + B0(off) + B1(off);
386
387                tb.dl_jumpaddr = (seg << 4) + off;
388                break;
389            }
390
391            default:
392                error(0, "unknown Intel-hex record type: 0x%02x", rectype);
393                badformat(buff, inm, BADTYPE);
394        }
395
396        /*
397         * Verify checksums are correct in file.
398         */
399
400        cksum = (-cksum) & 0xff;
401        if ((incksum = getbyte(&p)) == -1)
402            badformat(buff, inm, BADCSUM);
403        if (((u8) incksum) != cksum)
404            badformat(buff, inm, MISCSUM);
405
406        if (tb.dl_count)
407            write_record(&tb, ofp);
408    }
409    return 0;
410}
411
412int
413convert_S_records(
414    FILE *ifp,
415    char *inm,
416    FILE *ofp,
417    char *onm)
418{
419    char buff[512];
420    char *p;
421    u8 cksum;
422    int incksum;
423    int c;
424    long len;                        /* data length of current line */
425    int rectype;                    /* record type */
426    long addr;
427    bool endrecord = FALSE;
428    buffer_rec tb;
429
430    while ( !endrecord && (fgets(buff, sizeof(buff), ifp)) ) {
431        p = &buff[0];
432
433        fix_string_from_gets(p, sizeof(buff));
434
435        tb.dl_count = 0;
436
437        if (*p != 'S')
438            badformat(p, inm, BADFMT);
439        p++;
440
441        if ((rectype = getnibble(&p)) == -1)        /* record type */
442            badformat(buff, inm, BADTYPE);
443
444        if ((len = getbyte(&p)) == -1)              /* record len */
445            badformat(buff, inm, BADLEN);
446        cksum = len;
447
448        switch (rectype) {
449            case 0x00:                  /* comment field, ignored */
450                goto write_it;
451
452            case 0x01:                          /* data record, 16 bit addr */
453                if ((addr = get2bytes(&p)) == -1L)
454                    badformat(buff, inm, BADADDR);
455                len -= 3;
456                goto doit;
457
458            case 0x02:                          /* ... 24 bit addr */
459                if ((addr = get3bytes(&p)) == -1L)
460                    badformat(buff, inm, BADADDR);
461                len -= 4;
462                goto doit;
463
464            case 0x03:                          /* ... 32 bit addr */
465                if ((addr = get4bytes(&p)) == -1L)
466                    badformat(buff, inm, BADADDR);
467                len -= 5;
468    doit:
469                cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
470
471                tb.dl_destaddr = (u32) addr;
472                while (len--) {
473                    if ((c = getbyte(&p)) == -1)
474                        badformat(buff, inm, BADDATA);
475                    cksum += c;
476                    filesum += c;
477                    tb.dl_buf[tb.dl_count++] = c;
478                }
479                break;
480
481            case 0x07:                  /* 32 bit end record */
482                if ((addr = get4bytes(&p)) == -1L)
483                    badformat(buff, inm, BADADDR);
484                goto end_rec;
485
486            case 0x08:                  /* 24 bit end record */
487                if ((addr = get3bytes(&p)) == -1L)
488                    badformat(buff, inm, BADADDR);
489                goto end_rec;
490
491            case 0x09:                  /* 16 bit end record */
492                if ((addr = get2bytes(&p)) == -1L)
493                    badformat(buff, inm, BADADDR);
494
495end_rec:
496                cksum += B0(addr) + B1(addr) + B2(addr) + B3(addr);
497                tb.dl_jumpaddr = addr;
498                break;
499
500            default:
501                error(0, "unknown Motorola-S record type: 0x%02x", rectype);
502                badformat(buff, inm, BADTYPE);
503                break;
504        }
505
506        /*
507         * Verify checksums are correct in file.
508         */
509
510        cksum = (~cksum) & 0xff;
511        if ((incksum = getbyte(&p)) == -1)
512            badformat(buff, inm, BADCSUM);
513        if (((u8) incksum) != cksum)
514            badformat(buff, inm, MISCSUM);
515
516write_it:
517        if (tb.dl_count)
518            write_record(&tb, ofp);
519    }
520    return 0;
521}
522
523int
524convert_TI_records(
525    FILE *ifp,
526    char *inm,
527    FILE *ofp,
528    char *onm)
529{
530    char buff[512];
531    char *p;
532    int c;
533    bool endrecord = FALSE;
534    bool eol;
535    buffer_rec tb;
536
537    while ( ! endrecord && (fgets(buff, sizeof(buff), ifp))) {
538        p = &buff[0];
539        fix_string_from_gets(p, sizeof(buff));
540
541        tb.dl_count = 0;
542
543        eol = FALSE;
544        while ( ! eol && ! endrecord) {
545            switch (*p++) {
546                case '9':
547                    if (tb.dl_count)
548                        write_record(&tb, ofp);
549                    tb.dl_destaddr = (u32) get2bytes(&p);
550                    break;
551
552                case 'B':
553                    c = getbyte(&p);
554                    assert( c != -1 );
555                    filesum += c;
556                    tb.dl_buf[tb.dl_count++] = c;
557
558                    c = getbyte(&p);
559                    assert( c != -1 );
560                    filesum += c;
561                    tb.dl_buf[tb.dl_count++] = c;
562                    break;
563
564                case 'F':
565                    eol = TRUE;
566                    break;
567
568                case ':':
569                    endrecord = TRUE;
570                    break;
571
572                default:
573                    badformat(p, inm, BADFMT);
574            }
575        }
576        if (tb.dl_count)
577            write_record(&tb, ofp);
578    }
579    return 0;
580}
581
582void
583write_record(buffer_rec *tb,
584             FILE *fp)
585{
586    if ( ! linear) {
587        if (tb->dl_destaddr < base)
588            error(ERR_FATAL, "record at address 0x%x precedes base of 0x%x",
589                     tb->dl_destaddr, base);
590        (void) fseek(fp, tb->dl_destaddr - base, 0);
591    }
592
593    (void) fwrite(tb->dl_buf, tb->dl_count, 1, fp);
594    tb->dl_destaddr += tb->dl_count;
595    tb->dl_count = 0;
596}
597
598int
599getnibble(char **p)
600{
601    register int val;
602
603    **p = toupper(**p);
604    switch (**p) {
605        case '0': case '1': case '2': case '3': case '4':
606        case '5': case '6': case '7': case '8': case '9':
607            val = **p - '0';
608            break;
609
610        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
611            val = 10 + (**p - 'A');
612            break;
613
614        default:
615            return(-1);
616    }
617    *p += 1;
618
619    return(val & 0x0f);
620}
621
622int
623getbyte(char **p)
624{
625    int n0, n1;
626
627    if ((n0 = getnibble(p)) == -1)
628        return(-1);
629    if ((n1 = getnibble(p)) == -1)
630        return(-1);
631
632    return(((n0 << 4) + n1) & 0xff);
633}
634
635long
636getNbytes(char **p,
637          int n)
638{
639    long t;
640    u32 val = 0;
641
642    while (n--) {
643        if ((t = getbyte(p)) == -1)
644            return(-1L);
645        val <<= 8;
646        val += (u32) t;
647    }
648
649    return(val);
650}
651
652void
653badformat(char *s,
654          char *fname,
655          char *msg)
656{
657    if ( *s != '\0' ) {
658      if (s[strlen(s)-1] == '\n')             /* get rid of newline */
659        s[strlen(s)-1] = '\0';
660    }
661    error(0, "line '%s'::\n\tfrom file '%s'; %s", s, fname, msg);
662    exit(1);
663}
664
665/*
666 * error(errn, arglist)
667 *      report an error to stderr using printf(3) conventions.
668 *      Any output is preceded by '<progname>: '
669 *
670 * Uses ERR_EXIT  bit to request exit(errn)
671 *      ERR_ABORT to request abort()
672 *      ERR_ERRNO to indicate use of errno instead of argument.
673 *
674 * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
675 *      associated error message is appended to the output.
676 */
677
678/*VARARGS*/
679
680void
681error(int error_flag, ...)
682{
683    va_list arglist;
684    register char *format;
685    int local_errno;
686
687    (void) fflush(stdout);          /* in case stdout/stderr same */
688
689    local_errno = error_flag & ~ERR_MASK;
690    if (error_flag & ERR_ERRNO)     /* use errno? */
691        local_errno = errno;
692
693    va_start(arglist, error_flag);
694    format = va_arg(arglist, char *);
695    (void) fprintf(stderr, "%s: ", progname);
696    (void) vfprintf(stderr, format, arglist);
697    va_end(arglist);
698
699    if (local_errno)
700      (void) fprintf(stderr, " (%s)\n", strerror(local_errno));
701    else
702      (void) fprintf(stderr, "\n");
703
704    (void) fflush(stderr);
705
706    if (error_flag & (ERR_FATAL | ERR_ABORT)) {
707        if (error_flag & ERR_FATAL) {
708            error(0, "fatal error, exiting");
709            exit(local_errno ? local_errno : 1);
710        } else {
711            error(0, "fatal error, aborting");
712            abort();
713        }
714    }
715}
716
717void  fix_string_from_gets(char *s, size_t max)
718{
719  size_t len;
720  assert( s );
721
722  if ( *s == '\0' )
723    return;
724
725  len = strnlen( s, max );
726
727  if ( s[len - 1] == '\n')                 /* get rid of newline */
728      s[len - 1] = '\0';
729
730  if ( s[len - 1] == '\r')                 /* get rid of any CR */
731      s[len - 1] = '\0';
732
733}
Note: See TracBrowser for help on using the repository browser.