From 941b2cd4d0688311b0aea1dd1ef17fe3fff24b25 Mon Sep 17 00:00:00 2001
From: joerg_wunsch <joerg_wunsch@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Mon, 10 Oct 2011 13:42:08 +0000
Subject: [PATCH] bug #34518: loading intel hex files > 64k using record-type 4
 (Extended Linear Address Record)

Replace the change from r928 (handling of 0x8000000 offset in AVR32
files) by a completely different logic that no longer breaks hex files
for other devices starting with an offset; also apply a similar change
to S-record files, as well as when writing files.



git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1017 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog | 11 +++++++
 fileio.c  | 85 +++++++++++++++++++++++++++++++++++--------------------
 fileio.h  |  3 +-
 3 files changed, 67 insertions(+), 32 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3eccb524..87853bfc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-10-10  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #34518: loading intel hex files > 64k using record-type 4
+	(Extended Linear Address Record)
+	fileio.c: Replace the change from r928 (handling of 0x8000000
+	offset in AVR32 files) by a completely different logic that no
+	longer breaks hex files for other devices starting with an
+	offset; also apply a similar change to S-record files, as well
+	as when writing files.
+	fileio.c: (Ditto.)
+
 2011-09-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* avrftdi.c: Remove stray printf()s by fprintf(stderr)
diff --git a/fileio.c b/fileio.c
index ad523253..fa07a8f3 100644
--- a/fileio.c
+++ b/fileio.c
@@ -52,14 +52,14 @@ static int b2ihex(unsigned char * inbuf, int bufsize,
              char * outfile, FILE * outf);
 
 static int ihex2b(char * infile, FILE * inf,
-             AVRMEM * mem, int bufsize);
+             AVRMEM * mem, int bufsize, unsigned int fileoffset);
 
 static int b2srec(unsigned char * inbuf, int bufsize, 
            int recsize, int startaddr,
            char * outfile, FILE * outf);
 
 static int srec2b(char * infile, FILE * inf,
-             AVRMEM * mem, int bufsize);
+             AVRMEM * mem, int bufsize, unsigned int fileoffset);
 
 static int ihex_readrec(struct ihexrec * ihex, char * rec);
 
@@ -262,21 +262,20 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
  *
  * */
 static int ihex2b(char * infile, FILE * inf,
-             AVRMEM * mem, int bufsize)
+             AVRMEM * mem, int bufsize, unsigned int fileoffset)
 {
   char buffer [ MAX_LINE_LEN ];
-  unsigned int nextaddr, baseaddr, maxaddr, offsetaddr;
+  unsigned int nextaddr, baseaddr, maxaddr;
   int i;
   int lineno;
   int len;
   struct ihexrec ihex;
   int rc;
 
-  lineno      = 0;
-  baseaddr    = 0;
-  maxaddr     = 0;
-  offsetaddr  = 0;
-  nextaddr    = 0;
+  lineno   = 0;
+  baseaddr = 0;
+  maxaddr  = 0;
+  nextaddr = 0;
 
   while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
     lineno++;
@@ -301,23 +300,29 @@ static int ihex2b(char * infile, FILE * inf,
 
     switch (ihex.rectyp) {
       case 0: /* data record */
-        nextaddr = ihex.loadofs + baseaddr;
-        if ((nextaddr + ihex.reclen) > (bufsize+offsetaddr)) {
+        if (fileoffset != 0 && baseaddr < fileoffset) {
+          fprintf(stderr, 
+                  "%s: ERROR: address 0x%04x out of range (below fileoffset 0x%x) at line %d of %s\n",
+                  progname, baseaddr, fileoffset, lineno, infile);
+          return -1;
+        }
+        nextaddr = ihex.loadofs + baseaddr - fileoffset;
+        if (nextaddr + ihex.reclen > bufsize) {
           fprintf(stderr, 
                   "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
                   progname, nextaddr+ihex.reclen, lineno, infile);
           return -1;
         }
         for (i=0; i<ihex.reclen; i++) {
-          mem->buf[nextaddr+i-offsetaddr] = ihex.data[i];
-          mem->tags[nextaddr+i-offsetaddr] = TAG_ALLOCATED;
+          mem->buf[nextaddr+i] = ihex.data[i];
+          mem->tags[nextaddr+i] = TAG_ALLOCATED;
         }
         if (nextaddr+ihex.reclen > maxaddr)
           maxaddr = nextaddr+ihex.reclen;
         break;
 
       case 1: /* end of file record */
-        return maxaddr-offsetaddr;
+        return maxaddr;
         break;
 
       case 2: /* extended segment address record */
@@ -330,7 +335,6 @@ static int ihex2b(char * infile, FILE * inf,
 
       case 4: /* extended linear address record */
         baseaddr = (ihex.data[0] << 8 | ihex.data[1]) << 16;
-        if(nextaddr == 0) offsetaddr = baseaddr;	// if provided before any data, then remember it
         break;
 
       case 5: /* start linear address record */
@@ -353,7 +357,7 @@ static int ihex2b(char * infile, FILE * inf,
           "file \"%s\"\n",
           progname, infile);
 
-  return maxaddr-offsetaddr;
+  return maxaddr;
 }
 
 static int b2srec(unsigned char * inbuf, int bufsize, 
@@ -539,10 +543,10 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
 
 
 static int srec2b(char * infile, FILE * inf,
-           AVRMEM * mem, int bufsize)
+           AVRMEM * mem, int bufsize, unsigned int fileoffset)
 {
   char buffer [ MAX_LINE_LEN ];
-  unsigned int nextaddr, baseaddr, maxaddr;
+  unsigned int nextaddr, maxaddr;
   int i;
   int lineno;
   int len;
@@ -554,7 +558,6 @@ static int srec2b(char * infile, FILE * inf,
   char * msg = 0;
 
   lineno   = 0;
-  baseaddr = 0;
   maxaddr  = 0;
   reccount = 0;
 
@@ -588,17 +591,17 @@ static int srec2b(char * infile, FILE * inf,
 
       case 0x31: /* S1 - 16 bit address data record */
         datarec=1;
-        msg="%s: ERROR: address 0x%04x out of range at line %d of %s\n";    
+        msg="%s: ERROR: address 0x%04x out of range %sat line %d of %s\n";
         break;
 
       case 0x32: /* S2 - 24 bit address data record */
         datarec=1;
-        msg="%s: ERROR: address 0x%06x out of range at line %d of %s\n";
+        msg="%s: ERROR: address 0x%06x out of range %sat line %d of %s\n";
         break;
 
       case 0x33: /* S3 - 32 bit address data record */
         datarec=1;
-        msg="%s: ERROR: address 0x%08x out of range at line %d of %s\n";
+        msg="%s: ERROR: address 0x%08x out of range %sat line %d of %s\n";
         break;
 
       case 0x34: /* S4 - symbol record (LSI extension) */
@@ -634,9 +637,17 @@ static int srec2b(char * infile, FILE * inf,
     }
 
     if (datarec == 1) {
-      nextaddr = srec.loadofs + baseaddr;
+      nextaddr = srec.loadofs;
+      if (nextaddr < fileoffset) {
+        fprintf(stderr, msg, progname, nextaddr,
+                "(below fileoffset) ",
+                lineno, infile);
+        return -1;
+      }
+      nextaddr -= fileoffset;
       if (nextaddr + srec.reclen > bufsize) {
-        fprintf(stderr, msg, progname, nextaddr+srec.reclen, lineno, infile);
+        fprintf(stderr, msg, progname, nextaddr+srec.reclen, "",
+                lineno, infile);
         return -1;
       }
       for (i=0; i<srec.reclen; i++) {
@@ -786,14 +797,14 @@ static int fileio_ihex(struct fioparms * fio,
 
   switch (fio->op) {
     case FIO_WRITE:
-      rc = b2ihex(mem->buf, size, 32, 0, filename, f);
+      rc = b2ihex(mem->buf, size, 32, fio->fileoffset, filename, f);
       if (rc < 0) {
         return -1;
       }
       break;
 
     case FIO_READ:
-      rc = ihex2b(filename, f, mem, size);
+      rc = ihex2b(filename, f, mem, size, fio->fileoffset);
       if (rc < 0)
         return -1;
       break;
@@ -816,14 +827,14 @@ static int fileio_srec(struct fioparms * fio,
 
   switch (fio->op) {
     case FIO_WRITE:
-      rc = b2srec(mem->buf, size, 32, 0, filename, f);
+      rc = b2srec(mem->buf, size, 32, fio->fileoffset, filename, f);
       if (rc < 0) {
         return -1;
       }
       break;
 
     case FIO_READ:
-      rc = srec2b(filename, f, mem, size);
+      rc = srec2b(filename, f, mem, size, fio->fileoffset);
       if (rc < 0)
         return -1;
       break;
@@ -912,7 +923,8 @@ static int fileio_num(struct fioparms * fio,
 }
 
 
-int fileio_setparms(int op, struct fioparms * fp)
+int fileio_setparms(int op, struct fioparms * fp,
+                    struct avrpart * p, AVRMEM * m)
 {
   fp->op = op;
 
@@ -938,6 +950,19 @@ int fileio_setparms(int op, struct fioparms * fp)
       break;
   }
 
+  /*
+   * AVR32 devices maintain their load offset within the file itself,
+   * but AVRDUDE maintains all memory images 0-based.
+   */
+  if ((p->flags & AVRPART_AVR32) != 0)
+  {
+    fp->fileoffset = m->offset;
+  }
+  else
+  {
+    fp->fileoffset = 0;
+  }
+
   return 0;
 }
 
@@ -1032,7 +1057,7 @@ int fileio(int op, char * filename, FILEFMT format,
     return -1;
   }
 
-  rc = fileio_setparms(op, &fio);
+  rc = fileio_setparms(op, &fio, p, mem);
   if (rc < 0)
     return -1;
 
diff --git a/fileio.h b/fileio.h
index 2fe3f209..711dca5a 100644
--- a/fileio.h
+++ b/fileio.h
@@ -40,6 +40,7 @@ struct fioparms {
   char * iodesc;
   char * dir;
   char * rw;
+  unsigned int fileoffset;
 };
 
 enum {
@@ -53,8 +54,6 @@ extern "C" {
 
 char * fmtstr(FILEFMT format);
 
-int fileio_setparms(int op, struct fioparms * fp);
-
 int fileio(int op, char * filename, FILEFMT format,
            struct avrpart * p, char * memtype, int size);