source: rtems/tools/build/unhex.c @ 8f71a36

4.104.114.84.95
Last change on this file since 8f71a36 was 8f71a36, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/20/04 at 07:09:31

Remove stray white spaces.

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