source: rtems/c/build-tools/unhex.c @ 8cf88427

4.104.114.84.95
Last change on this file since 8cf88427 was c64e4ed4, checked in by Joel Sherrill <joel.sherrill@…>, on 01/15/96 at 21:50:28

updates from Tony Bennett for PA and UNIX ports

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