source: rtems/c/build-tools/unhex.c @ 9fbba98

4.104.114.84.95
Last change on this file since 9fbba98 was 254b4450, checked in by Joel Sherrill <joel.sherrill@…>, on 04/01/97 at 23:07:52

This set of changes is the build of what was required to convert to
GNU autoconf. This is the first large step in allowing an RTEMS
user to perform a one-tree build (per crossgcc FAQ) including RTEMS
in the build process. With this change RTEMS is configured in
built in the same style as the GNU tools, yet retains the basic
structure of its traditional Makefiles (ala Tony Bennett).
Jiri Gaisler (jgais@…) deserves (and received)
a big thank you for doing this.

There are still issues to be resolved but as of this commit, all target
which can be built on a linux host have been using a modified version
of the source Jiri submitted. This source was merged and most targets
built in the tree before this commit.

There are some issues which remain to be resolved but they are primarily
related to host OS dependencies, script issues, the use of gawk
for hack_specs, and the dependence on gcc snapshots. These will
be resolved.

  • 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#ifdef HAVE_STRTOUL
92#define stol(p) strtoul(p, (char **) NULL, 0)
93#else
94#define stol(p) strtol(p, (char **) NULL, 0)
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.