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

4.104.114.84.95
Last change on this file since fe65110 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

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