source: rtems/c/build-tools/unhex.c @ b1b5a7cb

4.104.114.84.95
Last change on this file since b1b5a7cb was 52a0641, checked in by Joel Sherrill <joel.sherrill@…>, on 06/03/96 at 15:47:45

added ifdef for sunos 4.x since it does not have strtoul.

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