From 0ae632070fde8d7cea6095303555c50c1692baf8 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Thu, 1 Dec 2022 20:21:33 +0000
Subject: [PATCH 1/8] Rewrite elf2b() in equivalent way absorbing elf_get_scn()

---
 src/fileio.c | 82 +++++++++++++++-------------------------------------
 1 file changed, 24 insertions(+), 58 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 79fccd5c..4eff1b92 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -708,41 +708,6 @@ int is_section_in_segment(Elf32_Shdr *sh, Elf32_Phdr *ph)
     return 1;
 }
 
-/*
- * Return the ELF section descriptor that corresponds to program
- * header `ph'.  The program header is expected to be of p_type
- * PT_LOAD, and to have a nonzero p_filesz.  (PT_LOAD sections with a
- * zero p_filesz are typically RAM sections that are not initialized
- * by file data, e.g. ".bss".)
- */
-static Elf_Scn *elf_get_scn(Elf *e, Elf32_Phdr *ph, Elf32_Shdr **shptr)
-{
-  Elf_Scn *s = NULL;
-
-  while ((s = elf_nextscn(e, s)) != NULL) {
-    Elf32_Shdr *sh;
-    size_t ndx = elf_ndxscn(s);
-    if ((sh = elf32_getshdr(s)) == NULL) {
-      pmsg_error("unable to read section #%u header: %s\n", (unsigned int)ndx, elf_errmsg(-1));
-      continue;
-    }
-    if ((sh->sh_flags & SHF_ALLOC) == 0 ||
-        sh->sh_type != SHT_PROGBITS)
-      /* we are only interested in PROGBITS, ALLOC sections */
-      continue;
-    if (sh->sh_size == 0)
-      /* we are not interested in empty sections */
-      continue;
-    if (is_section_in_segment(sh, ph)) {
-      /* yeah, we found it */
-      *shptr = sh;
-      return s;
-    }
-  }
-
-  pmsg_error("cannot find a matching section for program header entry @p_vaddr 0x%x\n", ph->p_vaddr);
-  return NULL;
-}
 
 static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
                           unsigned int *lowbound,
@@ -919,36 +884,37 @@ static int elf2b(const char *infile, FILE *inf,
    * PT_LOAD, and have a non-zero p_filesz.
    */
   for (i = 0; i < eh->e_phnum; i++) {
-    if (ph[i].p_type != PT_LOAD ||
-        ph[i].p_filesz == 0)
+    if (ph[i].p_type != PT_LOAD || ph[i].p_filesz == 0)
       continue;
 
     pmsg_notice2("considering PT_LOAD program header entry #%d:\n"
       "    p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", (int) i, ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz);
 
-    Elf32_Shdr *sh;
-    Elf_Scn *s = elf_get_scn(e, ph + i, &sh);
-    if (s == NULL)
-      continue;
+    Elf_Scn *scn = NULL;
+    while ((scn = elf_nextscn(e, scn)) != NULL) {
+      size_t ndx = elf_ndxscn(scn);
+      Elf32_Shdr *sh = elf32_getshdr(scn);
 
-    if ((sh->sh_flags & SHF_ALLOC) && sh->sh_size) {
-      const char *sname;
-
-      if (sndx != 0) {
-        sname = elf_strptr(e, sndx, sh->sh_name);
-      } else {
-        sname = "*unknown*";
+      if (sh == NULL) {
+        pmsg_error("unable to read section #%u header: %s\n", (unsigned int) ndx, elf_errmsg(-1));
+        continue;
       }
+      // Only interested in PROGBITS, ALLOC sections
+      if ((sh->sh_flags & SHF_ALLOC) == 0 || sh->sh_type != SHT_PROGBITS)
+        continue;
+      // Not interested in empty sections
+      if (sh->sh_size == 0)
+        continue;
+      // Section must belong to this segment
+      if (!is_section_in_segment(sh, ph+i))
+        continue;
 
-      unsigned int lma;
-      lma = ph[i].p_paddr + sh->sh_offset - ph[i].p_offset;
+      const char *sname = sndx? elf_strptr(e, sndx, sh->sh_name): "*unknown*";
+      unsigned int lma = ph[i].p_paddr + sh->sh_offset - ph[i].p_offset;
 
       pmsg_notice2("found section %s, LMA 0x%x, sh_size %u\n", sname, lma, sh->sh_size);
 
-      if (lma >= low &&
-          lma + sh->sh_size < high) {
-        /* OK */
-      } else {
+      if(!(lma >= low && lma + sh->sh_size < high)) {
         msg_notice2("    => skipping, inappropriate for %s memory region\n", mem->desc);
         continue;
       }
@@ -967,17 +933,16 @@ static int elf2b(const char *infile, FILE *inf,
       }
 
       Elf_Data *d = NULL;
-      while ((d = elf_getdata(s, d)) != NULL) {
+      while ((d = elf_getdata(scn, d)) != NULL) {
         msg_notice2("    Data block: d_buf %p, d_off 0x%x, d_size %ld\n",
-                        d->d_buf, (unsigned int)d->d_off, (long) d->d_size);
+          d->d_buf, (unsigned int)d->d_off, (long) d->d_size);
         if (mem->size == 1) {
           if (d->d_off != 0) {
             pmsg_error("unexpected data block at offset != 0\n");
           } else if (foff >= d->d_size) {
             pmsg_error("ELF file section does not contain byte at offset %d\n", foff);
           } else {
-            msg_notice2("    Extracting one byte from file offset %d\n",
-                            foff);
+            msg_notice2("    Extracting one byte from file offset %d\n", foff);
             mem->buf[0] = ((unsigned char *)d->d_buf)[foff];
             mem->tags[0] = TAG_ALLOCATED;
             rv = 1;
@@ -994,6 +959,7 @@ static int elf2b(const char *infile, FILE *inf,
           memset(mem->tags + idx, TAG_ALLOCATED, d->d_size);
         }
       }
+      break;                  // Stop after first section in program header
     }
   }
 done:

From 3b30e5d424fdcbd9f1b550c3f69359e9a462e673 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Thu, 1 Dec 2022 20:28:56 +0000
Subject: [PATCH 2/8] Fix elf2b() to consider all sections in segments

---
 src/fileio.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/fileio.c b/src/fileio.c
index 4eff1b92..33f258cb 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -959,7 +959,6 @@ static int elf2b(const char *infile, FILE *inf,
           memset(mem->tags + idx, TAG_ALLOCATED, d->d_size);
         }
       }
-      break;                  // Stop after first section in program header
     }
   }
 done:

From 2e98ee3a1c2e89d779e86caec7fb9aa7d00a3ebf Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Fri, 2 Dec 2022 18:28:19 +0000
Subject: [PATCH 3/8] Check elf section fits into memory and fail elf2b() on
 elf handling errors

---
 src/fileio.c | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 33f258cb..97e31683 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -772,7 +772,7 @@ static int elf2b(const char *infile, FILE *inf,
                  int bufsize, unsigned int fileoffset)
 {
   Elf *e;
-  int rv = -1;
+  int rv = 0, size = 0;
   unsigned int low, high, foff;
 
   if (elf_mem_limits(mem, p, &low, &high, &foff) != 0) {
@@ -897,6 +897,7 @@ static int elf2b(const char *infile, FILE *inf,
 
       if (sh == NULL) {
         pmsg_error("unable to read section #%u header: %s\n", (unsigned int) ndx, elf_errmsg(-1));
+        rv = -1;
         continue;
       }
       // Only interested in PROGBITS, ALLOC sections
@@ -927,8 +928,9 @@ static int elf2b(const char *infile, FILE *inf,
        * from it, using the "foff" offset obtained above.
        */
       if (mem->size != 1 && sh->sh_size > (unsigned) mem->size) {
-        pmsg_error("section %s does not fit into %s memory:\n"
-          "    0x%x + %u > %u\n", sname, mem->desc, lma, sh->sh_size, mem->size);
+        pmsg_error("section %s of size %u does not fit into %s of size %d\n",
+          sname, sh->sh_size, mem->desc, mem->size);
+        rv = -1;
         continue;
       }
 
@@ -939,31 +941,38 @@ static int elf2b(const char *infile, FILE *inf,
         if (mem->size == 1) {
           if (d->d_off != 0) {
             pmsg_error("unexpected data block at offset != 0\n");
+            rv = -1;
           } else if (foff >= d->d_size) {
             pmsg_error("ELF file section does not contain byte at offset %d\n", foff);
+            rv = -1;
           } else {
             msg_notice2("    Extracting one byte from file offset %d\n", foff);
             mem->buf[0] = ((unsigned char *)d->d_buf)[foff];
             mem->tags[0] = TAG_ALLOCATED;
-            rv = 1;
+            size = 1;
           }
         } else {
-          unsigned int idx;
+          int idx = lma-low + d->d_off;
+          int end = idx + d->d_size;
 
-          idx = lma - low + d->d_off;
-          if ((int)(idx + d->d_size) > rv)
-            rv = idx + d->d_size;
-          msg_debug("    Writing %ld bytes to mem offset 0x%x\n",
-            (long) d->d_size, idx);
-          memcpy(mem->buf + idx, d->d_buf, d->d_size);
-          memset(mem->tags + idx, TAG_ALLOCATED, d->d_size);
+          if(idx >= 0 && idx < mem->size && end >= 0 && end <= mem->size && end-idx >= 0) {
+            if (end > size)
+              size = end;
+            imsg_debug("writing %d bytes to mem offset 0x%x\n", end-idx, idx);
+            memcpy(mem->buf + idx, d->d_buf, end-idx);
+            memset(mem->tags + idx, TAG_ALLOCATED, end-idx);
+          } else {
+            pmsg_error("section %s [0x%04x, 0x%04x] does not fit into %s [0, 0x%04x]\n",
+              sname, idx, (int) (idx + d->d_size-1), mem->desc, mem->size-1);
+            rv = -1;
+          }
         }
       }
     }
   }
 done:
   (void)elf_end(e);
-  return rv;
+  return rv<0? rv: size;
 }
 #endif  /* HAVE_LIBELF */
 

From f688baabb770645002d6a3cdf64770662c83f058 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Fri, 2 Dec 2022 18:45:47 +0000
Subject: [PATCH 4/8] Improve error messaging

---
 src/fileio.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 97e31683..d9a1d1d0 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -887,8 +887,8 @@ static int elf2b(const char *infile, FILE *inf,
     if (ph[i].p_type != PT_LOAD || ph[i].p_filesz == 0)
       continue;
 
-    pmsg_notice2("considering PT_LOAD program header entry #%d:\n"
-      "    p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", (int) i, ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz);
+    pmsg_notice2("considering PT_LOAD program header entry #%d\n", (int) i);
+    imsg_notice2("p_vaddr 0x%x, p_paddr 0x%x, p_filesz %d\n", ph[i].p_vaddr, ph[i].p_paddr, ph[i].p_filesz);
 
     Elf_Scn *scn = NULL;
     while ((scn = elf_nextscn(e, scn)) != NULL) {
@@ -916,7 +916,7 @@ static int elf2b(const char *infile, FILE *inf,
       pmsg_notice2("found section %s, LMA 0x%x, sh_size %u\n", sname, lma, sh->sh_size);
 
       if(!(lma >= low && lma + sh->sh_size < high)) {
-        msg_notice2("    => skipping, inappropriate for %s memory region\n", mem->desc);
+        imsg_notice2("skipping %s (inappropriate for %s)\n", sname, mem->desc);
         continue;
       }
       /*
@@ -936,7 +936,7 @@ static int elf2b(const char *infile, FILE *inf,
 
       Elf_Data *d = NULL;
       while ((d = elf_getdata(scn, d)) != NULL) {
-        msg_notice2("    Data block: d_buf %p, d_off 0x%x, d_size %ld\n",
+        imsg_notice2("data block: d_buf %p, d_off 0x%x, d_size %ld\n",
           d->d_buf, (unsigned int)d->d_off, (long) d->d_size);
         if (mem->size == 1) {
           if (d->d_off != 0) {
@@ -946,7 +946,7 @@ static int elf2b(const char *infile, FILE *inf,
             pmsg_error("ELF file section does not contain byte at offset %d\n", foff);
             rv = -1;
           } else {
-            msg_notice2("    Extracting one byte from file offset %d\n", foff);
+            imsg_notice2("extracting one byte from file offset %d\n", foff);
             mem->buf[0] = ((unsigned char *)d->d_buf)[foff];
             mem->tags[0] = TAG_ALLOCATED;
             size = 1;

From 23dddef64badfa9078bc8fad5cdf3d91b29fd684 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Fri, 2 Dec 2022 19:03:06 +0000
Subject: [PATCH 5/8] Mark unused function parameters as such

---
 src/fileio.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index d9a1d1d0..24047e7a 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -118,10 +118,9 @@ char * fileio_fmtstr(FILEFMT format)
 }
 
 
-static int b2ihex(const unsigned char *inbuf, int bufsize,
-           int recsize, int startaddr,
-           const char *outfile, FILE *outf, FILEFMT ffmt)
-{
+static int b2ihex(const unsigned char *inbuf, int bufsize, int recsize,
+  int startaddr, const char *outfile_unused, FILE *outf, FILEFMT ffmt) {
+
   const unsigned char *buf;
   unsigned int nextaddr;
   int n, nbytes, n_64k;
@@ -397,10 +396,9 @@ static int ihex2b(const char *infile, FILE *inf,
   }
 }
 
-static int b2srec(const unsigned char *inbuf, int bufsize,
-           int recsize, int startaddr,
-           const char *outfile, FILE *outf)
-{
+static int b2srec(const unsigned char *inbuf, int bufsize, int recsize,
+  int startaddr, const char *outfile_unused, FILE *outf) {
+
   const unsigned char *buf;
   unsigned int nextaddr;
   int n, nbytes, addr_width;
@@ -767,10 +765,9 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
 }
 
 
-static int elf2b(const char *infile, FILE *inf,
-                 const AVRMEM *mem, const AVRPART *p,
-                 int bufsize, unsigned int fileoffset)
-{
+static int elf2b(const char *infile, FILE *inf, const AVRMEM *mem,
+  const AVRPART *p, int bufsize_unused, unsigned int fileoffset_unused) {
+
   Elf *e;
   int rv = 0, size = 0;
   unsigned int low, high, foff;
@@ -1045,9 +1042,9 @@ static int fileio_rbin(struct fioparms *fio,
 }
 
 
-static int fileio_imm(struct fioparms *fio,
-             const char *fname, FILE *f, const AVRMEM *mem, int size)
-{
+static int fileio_imm(struct fioparms *fio, const char *fname, FILE *f_unused,
+ const AVRMEM *mem, int size) {
+
   int rc = 0;
   char *e, *p, *filename;
   unsigned long b;

From 6b03d7dc5aa520329cc378d284598e8790b80fae Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Sat, 3 Dec 2022 13:37:44 +0000
Subject: [PATCH 6/8] Correct upper flash boundary for 8-bit AVR parts in
 elf_mem_limits()

---
 src/fileio.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 24047e7a..b2f29bf7 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -728,11 +728,11 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
         strcmp(mem->desc, "application") == 0 ||
         strcmp(mem->desc, "apptable") == 0) {
       *lowbound = 0;
-      *highbound = 0x7ffff;       /* max 8 MiB */
+      *highbound = 0x7Fffff;    // Max 8 MiB
       *fileoff = 0;
     } else if (strcmp(mem->desc, "eeprom") == 0) {
       *lowbound = 0x810000;
-      *highbound = 0x81ffff;      /* max 64 KiB */
+      *highbound = 0x81ffff;    // Max 64 KiB
       *fileoff = 0;
     } else if (strcmp(mem->desc, "lfuse") == 0) {
       *lowbound = 0x820000;

From db0258a7d8e6b2067f99d7127d7ce32d23c92846 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Sat, 10 Dec 2022 23:28:56 +0000
Subject: [PATCH 7/8] Add fuses, usersig, userrow, signature and data to
 elf_mem_limits()

---
 src/fileio.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index b2f29bf7..77cedbe3 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -730,11 +730,15 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
       *lowbound = 0;
       *highbound = 0x7Fffff;    // Max 8 MiB
       *fileoff = 0;
+    } else if (strcmp(mem->desc, "data") == 0) { // Volatile SRAM for XMEGA (not the .data section)
+      *lowbound = 0x802000;
+      *highbound = 0x80ffff;
+      *fileoff = 0;
     } else if (strcmp(mem->desc, "eeprom") == 0) {
       *lowbound = 0x810000;
       *highbound = 0x81ffff;    // Max 64 KiB
       *fileoff = 0;
-    } else if (strcmp(mem->desc, "lfuse") == 0) {
+    } else if (strcmp(mem->desc, "lfuse") == 0 || strcmp(mem->desc, "fuses") == 0) {
       *lowbound = 0x820000;
       *highbound = 0x82ffff;
       *fileoff = 0;
@@ -752,10 +756,18 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
       *lowbound = 0x820000;
       *highbound = 0x82ffff;
       *fileoff = mem->desc[4] - '0';
-    } else if (strncmp(mem->desc, "lock", 4) == 0) {
+    } else if (strncmp(mem->desc, "lock", 4) == 0) { // Lock or lockbits
       *lowbound = 0x830000;
       *highbound = 0x83ffff;
       *fileoff = 0;
+    } else if (strcmp(mem->desc, "signature") == 0) { // Read only
+      *lowbound = 0x840000;
+      *highbound = 0x84ffff;
+      *fileoff = 0;
+    } else if (strncmp(mem->desc, "user", 4) == 0) { // Usersig or userrow
+      *lowbound = 0x850000;
+      *highbound = 0x85ffff;
+      *fileoff = 0;
     } else {
       rv = -1;
     }

From e4f10a33ab1d1d32367b97065a4efe577a8d5218 Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Tue, 13 Dec 2022 23:59:58 +0000
Subject: [PATCH 8/8] Clarify comment

---
 src/fileio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/fileio.c b/src/fileio.c
index 77cedbe3..482bb3a6 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -730,7 +730,7 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
       *lowbound = 0;
       *highbound = 0x7Fffff;    // Max 8 MiB
       *fileoff = 0;
-    } else if (strcmp(mem->desc, "data") == 0) { // Volatile SRAM for XMEGA (not the .data section)
+    } else if (strcmp(mem->desc, "data") == 0) { // SRAM for XMEGAs
       *lowbound = 0x802000;
       *highbound = 0x80ffff;
       *fileoff = 0;