]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Lowlevel doesn't depend on libdw
authorPetr Machata <pmachata@redhat.com>
Sun, 19 Jul 2009 15:44:55 +0000 (17:44 +0200)
committerPetr Machata <pmachata@redhat.com>
Sun, 19 Jul 2009 15:44:55 +0000 (17:44 +0200)
* When we don't depend on libdw to provide us with Dwarf descriptor, we can
  validate even fragmental files.  Since on low level dwarflint does all
  the data processing itself, libdw is not really used anyway.

* High level obviously still does use libdw

src/Makefile.am
src/dwarflint-hl.cc
src/dwarflint-readctx.c [new file with mode: 0644]
src/dwarflint-readctx.h [new file with mode: 0644]
src/dwarflint.c
src/dwarflint.h

index 79748d1035cb376a94cc7067e6991707a12a7b45..9fe64d3ae924192425222c6e8a235f59f55cf13b 100644 (file)
@@ -84,7 +84,8 @@ dwarfcmp_SOURCES = dwarfcmp.cc
 
 dwarflint_SOURCES = dwarflint.c dwarflint.h dwarflint-hl.cc \
                    dwarflint-expected-at.cc dwarflint-expected.hh \
-                   dwarfstrings.c dwarflint-coverage.c dwarflint-coverage.h
+                   dwarfstrings.c dwarflint-coverage.c dwarflint-coverage.h \
+                   dwarflint-readctx.c dwarflint-readctx.h
 
 readelf_SOURCES = readelf.c dwarfstrings.c
 
index 7fa6ecdb1e3450459cc64b7b9d02765e2c082f12..c4c471775e680569048a9adcea649f05370d3849 100644 (file)
@@ -55,18 +55,25 @@ namespace
 
 struct hl_ctx
 {
+  Dwarf *dwarf;
   elfutils::dwarf dw;
 
-  hl_ctx (Dwarf *dwarf)
-    : dw (dwarf)
+  hl_ctx (Elf *elf)
+    : dwarf (dwarf_begin_elf (elf, DWARF_C_READ, NULL))
+    , dw (dwarf)
   {
   }
+
+  ~hl_ctx ()
+  {
+    dwarf_end (dwarf);
+  }
 };
 
 hl_ctx *
-hl_ctx_new (Dwarf *dwarf)
+hl_ctx_new (Elf *elf)
 {
-  return new hl_ctx (dwarf);
+  return new hl_ctx (elf);
 }
 
 void
diff --git a/src/dwarflint-readctx.c b/src/dwarflint-readctx.c
new file mode 100644 (file)
index 0000000..2a99254
--- /dev/null
@@ -0,0 +1,317 @@
+/* Pedantic checking of DWARF files.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+   Written by Petr Machata <pmachata@redhat.com>, 2009.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "dwarflint-readctx.h"
+#include "dwarflint.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <byteswap.h>
+
+/* read_Xubyte_* is basically cut'n'paste from memory-access.h.  */
+union unaligned
+  {
+    void *p;
+    uint16_t u2;
+    uint32_t u4;
+    uint64_t u8;
+    int16_t s2;
+    int32_t s4;
+    int64_t s8;
+  } __attribute__ ((packed));
+
+static uint16_t
+read_2ubyte_unaligned (struct elf_file *file, const void *p)
+{
+  const union unaligned *up = p;
+  if (file->other_byte_order)
+    return bswap_16 (up->u2);
+  return up->u2;
+}
+
+/* Prefix with dwarflint_ for export, so that it doesn't get confused
+   with functions and macros in memory-access.h.  */
+uint32_t
+dwarflint_read_4ubyte_unaligned (struct elf_file *file, const void *p)
+{
+  const union unaligned *up = p;
+  if (file->other_byte_order)
+    return bswap_32 (up->u4);
+  return up->u4;
+}
+
+uint64_t
+dwarflint_read_8ubyte_unaligned (struct elf_file *file, const void *p)
+{
+  const union unaligned *up = p;
+  if (file->other_byte_order)
+    return bswap_64 (up->u8);
+  return up->u8;
+}
+
+
+#define read_2ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr);                        \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                    \
+     t_; })
+
+#define read_4ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint32_t t_ = dwarflint_read_4ubyte_unaligned (Dbg, Addr);                      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                    \
+     t_; })
+
+#define read_8ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint64_t t_ = dwarflint_read_8ubyte_unaligned (Dbg, Addr);                      \
+     Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                    \
+     t_; })
+
+
+
+void
+read_ctx_init (struct read_ctx *ctx, struct elf_file *file, Elf_Data *data)
+{
+  if (data == NULL)
+    abort ();
+
+  ctx->file = file;
+  ctx->data = data;
+  ctx->begin = data->d_buf;
+  ctx->end = data->d_buf + data->d_size;
+  ctx->ptr = data->d_buf;
+}
+
+bool
+read_ctx_init_sub (struct read_ctx *ctx, struct read_ctx *parent,
+                  const unsigned char *begin, const unsigned char *end)
+{
+  if (parent == NULL)
+    abort ();
+
+  if (begin < parent->begin
+      || end > parent->end)
+    return false;
+
+  ctx->file = parent->file;
+  ctx->data = parent->data;
+  ctx->begin = begin;
+  ctx->end = end;
+  ctx->ptr = begin;
+  return true;
+}
+
+uint64_t
+read_ctx_get_offset (struct read_ctx *ctx)
+{
+  assert (ctx->ptr >= ctx->begin);
+  return (uint64_t)(ctx->ptr - ctx->begin);
+}
+
+bool
+read_ctx_need_data (struct read_ctx *ctx, size_t length)
+{
+  const unsigned char *ptr = ctx->ptr + length;
+  return ptr <= ctx->end && (length == 0 || ptr > ctx->ptr);
+}
+
+bool
+read_ctx_read_ubyte (struct read_ctx *ctx, unsigned char *ret)
+{
+  if (!read_ctx_need_data (ctx, 1))
+    return false;
+  if (ret != NULL)
+    *ret = *ctx->ptr;
+  ctx->ptr++;
+  return true;
+}
+
+int
+read_ctx_read_uleb128 (struct read_ctx *ctx, uint64_t *ret)
+{
+  uint64_t result = 0;
+  int shift = 0;
+  int size = 8 * sizeof (result);
+  bool zero_tail = false;
+
+  while (1)
+    {
+      uint8_t byte;
+      if (!read_ctx_read_ubyte (ctx, &byte))
+       return -1;
+
+      uint8_t payload = byte & 0x7f;
+      zero_tail = payload == 0 && shift > 0;
+      result |= (uint64_t)payload << shift;
+      shift += 7;
+      if (shift > size && byte != 0x1)
+       return -1;
+      if ((byte & 0x80) == 0)
+       break;
+    }
+
+  if (ret != NULL)
+    *ret = result;
+  return zero_tail ? 1 : 0;
+}
+
+int
+read_ctx_read_sleb128 (struct read_ctx *ctx, int64_t *ret)
+{
+  int64_t result = 0;
+  int shift = 0;
+  int size = 8 * sizeof (result);
+  bool zero_tail = false;
+  bool sign = false;
+
+  while (1)
+    {
+      uint8_t byte;
+      if (!read_ctx_read_ubyte (ctx, &byte))
+       return -1;
+
+      uint8_t payload = byte & 0x7f;
+      zero_tail = shift > 0 && ((payload == 0x7f && sign)
+                               || (payload == 0 && !sign));
+      sign = (byte & 0x40) != 0; /* Set sign for rest of loop & next round.  */
+      result |= (int64_t)payload << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+       {
+         if (shift < size && sign)
+           result |= -((int64_t)1 << shift);
+         break;
+       }
+      if (shift > size)
+       return -1;
+    }
+
+  if (ret != NULL)
+    *ret = result;
+  return zero_tail ? 1 : 0;
+}
+
+bool
+read_ctx_read_2ubyte (struct read_ctx *ctx, uint16_t *ret)
+{
+  if (!read_ctx_need_data (ctx, 2))
+    return false;
+  uint16_t val = read_2ubyte_unaligned_inc (ctx->file, ctx->ptr);
+  if (ret != NULL)
+    *ret = val;
+  return true;
+}
+
+bool
+read_ctx_read_4ubyte (struct read_ctx *ctx, uint32_t *ret)
+{
+  if (!read_ctx_need_data (ctx, 4))
+    return false;
+  uint32_t val = read_4ubyte_unaligned_inc (ctx->file, ctx->ptr);
+  if (ret != NULL)
+    *ret = val;
+  return true;
+}
+
+bool
+read_ctx_read_8ubyte (struct read_ctx *ctx, uint64_t *ret)
+{
+  if (!read_ctx_need_data (ctx, 8))
+    return false;
+  uint64_t val = read_8ubyte_unaligned_inc (ctx->file, ctx->ptr);
+  if (ret != NULL)
+    *ret = val;
+  return true;
+}
+
+bool
+read_ctx_read_offset (struct read_ctx *ctx, bool dwarf64, uint64_t *ret)
+{
+  if (dwarf64)
+    return read_ctx_read_8ubyte (ctx, ret);
+
+  uint32_t v;
+  if (!read_ctx_read_4ubyte (ctx, &v))
+    return false;
+
+  if (ret != NULL)
+    *ret = (uint64_t)v;
+  return true;
+}
+
+bool
+read_ctx_read_var (struct read_ctx *ctx, int width, uint64_t *ret)
+{
+  switch (width)
+    {
+    case 4:
+    case 8:
+      return read_ctx_read_offset (ctx, width == 8, ret);
+    case 2:
+      {
+       uint16_t val;
+       if (!read_ctx_read_2ubyte (ctx, &val))
+         return false;
+       *ret = val;
+       return true;
+      }
+    case 1:
+      {
+       uint8_t val;
+       if (!read_ctx_read_ubyte (ctx, &val))
+         return false;
+       *ret = val;
+       return true;
+      }
+    default:
+      return false;
+    };
+}
+
+const char *
+read_ctx_read_str (struct read_ctx *ctx)
+{
+  const char *ret = (const char *)ctx->ptr;
+  uint8_t byte;
+  do
+    if (!read_ctx_read_ubyte (ctx, &byte))
+      return NULL;
+  while (byte != 0);
+  return ret;
+}
+
+bool
+read_ctx_skip (struct read_ctx *ctx, uint64_t len)
+{
+  if (!read_ctx_need_data (ctx, len))
+    return false;
+  ctx->ptr += len;
+  return true;
+}
+
+bool
+read_ctx_eof (struct read_ctx *ctx)
+{
+  return !read_ctx_need_data (ctx, 1);
+}
diff --git a/src/dwarflint-readctx.h b/src/dwarflint-readctx.h
new file mode 100644 (file)
index 0000000..4adcdf5
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef dwarflint_readctx_h
+#define dwarflint_readctx_h
+
+#include <stdbool.h>
+#include "../libelf/libelf.h"
+
+/* Functions and data structures related to bounds-checked
+   reading.  */
+
+struct read_ctx
+{
+  struct elf_file *file;
+  Elf_Data *data;
+  const unsigned char *ptr;
+  const unsigned char *begin;
+  const unsigned char *end;
+};
+
+uint32_t dwarflint_read_4ubyte_unaligned (struct elf_file *file,
+                                         const void *p);
+uint64_t dwarflint_read_8ubyte_unaligned (struct elf_file *file,
+                                         const void *p);
+
+
+void read_ctx_init (struct read_ctx *ctx,
+                          struct elf_file *file,
+                          Elf_Data *data);
+bool read_ctx_init_sub (struct read_ctx *ctx,
+                       struct read_ctx *parent,
+                       const unsigned char *begin,
+                       const unsigned char *end);
+uint64_t read_ctx_get_offset (struct read_ctx *ctx);
+bool read_ctx_need_data (struct read_ctx *ctx, size_t length);
+bool read_ctx_read_ubyte (struct read_ctx *ctx, unsigned char *ret);
+int read_ctx_read_uleb128 (struct read_ctx *ctx, uint64_t *ret);
+int read_ctx_read_sleb128 (struct read_ctx *ctx, int64_t *ret);
+bool read_ctx_read_2ubyte (struct read_ctx *ctx, uint16_t *ret);
+bool read_ctx_read_4ubyte (struct read_ctx *ctx, uint32_t *ret);
+bool read_ctx_read_8ubyte (struct read_ctx *ctx, uint64_t *ret);
+bool read_ctx_read_offset (struct read_ctx *ctx, bool dwarf64,
+                                 uint64_t *ret);
+bool read_ctx_read_var (struct read_ctx *ctx, int width, uint64_t *ret);
+const char *read_ctx_read_str (struct read_ctx *ctx);
+bool read_ctx_skip (struct read_ctx *ctx, uint64_t len);
+bool read_ctx_eof (struct read_ctx *ctx);
+
+#endif
index 6ddc61c7745740faff467f5188fbca7530242021..292385517244fd2e9af409d3edec84572e9842f3 100644 (file)
 #include <unistd.h>
 
 #include "../libdw/dwarf.h"
-#include "../libdw/libdwP.h"
 #include "../libdw/known-dwarf.h"
 #include "../libebl/libebl.h"
 #include "dwarfstrings.h"
 #include "dwarflint.h"
+#include "dwarflint-readctx.h"
 
 /* Bug report address.  */
 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
@@ -103,7 +103,7 @@ static struct argp argp =
 /* If true, we accept silently files without debuginfo.  */
 static bool tolerate_nodebug = false;
 
-static void process_file (Dwarf *dwarf, const char *fname, bool only_one);
+static void process_file (Elf *elf, const char *fname, bool only_one);
 
 struct message_term
 {
@@ -593,28 +593,15 @@ main (int argc, char *argv[])
          if (layout_rel_file (elf))
            goto invalid_elf;
 
-         Dwarf *dwarf = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
-         if (dwarf == NULL)
-           {
-             if (!tolerate_nodebug)
-               wr_error (NULL,
-                         gettext ("cannot generate Dwarf descriptor: %s\n"),
-                         dwarf_errmsg (-1));
-           }
-         else
-           {
-             process_file (dwarf, argv[remaining], only_one);
-
-             if (dwarf_end (dwarf) != 0)
-               wr_error (NULL,
-                         gettext ("error while closing Dwarf descriptor: %s\n"),
-                         dwarf_errmsg (-1));
-           }
+         process_file (elf, argv[remaining], only_one);
 
-         if (elf_end (elf) != 0)
+         elf_errno (); /* Clear errno.  */
+         elf_end (elf);
+         int err = elf_errno ();
+         if (err != 0)
            wr_error (NULL,
                      gettext ("error while closing Elf descriptor: %s\n"),
-                     elf_errmsg (-1));
+                     elf_errmsg (err));
 
          if (prev_error_count == error_count && !be_quiet)
            puts (gettext ("No errors"));
@@ -685,81 +672,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
 #define PRI_NOT_ENOUGH ": not enough data for %s.\n"
 #define PRI_LACK_RELOCATION ": %s seems to lack a relocation.\n"
 
-struct relocation
-{
-  uint64_t offset;
-  uint64_t addend;
-  int symndx;
-  int type;
-  bool invalid;                /* Whether this one relocation should be
-                          ignored.  Necessary so that we don't
-                          double-report invalid & missing
-                          relocation.  */
-};
-
-struct relocation_data
-{
-  struct elf_file *file;
-  Elf_Data *symdata;   /* Symbol table associated with this
-                          relocation section.  */
-  size_t type;         /* SHT_REL or SHT_RELA.  */
-
-  struct relocation *rel;      /* Array of relocations.  May be NULL
-                                  if there are no associated
-                                  relocation data.  */
-  size_t size;
-  size_t alloc;
-  size_t index;                /* Current index. */
-};
-
-struct section_data
-{
-  struct elf_file *file;
-  size_t secndx;       /* Index into file->sec.  */
-  Elf_Data *data;
-  struct relocation_data rel;
-};
-
-static struct sec *
-data_get_sec (struct section_data *data)
-{
-  return data->file->sec + data->secndx;
-}
-
-/* Functions and data structures related to bounds-checked
-   reading.  */
-
-struct read_ctx
-{
-  Dwarf *dbg;
-  Elf_Data *data;
-  const unsigned char *ptr;
-  const unsigned char *begin;
-  const unsigned char *end;
-};
-
-
-static void read_ctx_init (struct read_ctx *ctx, Dwarf *dbg,
-                          Elf_Data *data);
-static bool read_ctx_init_sub (struct read_ctx *ctx,
-                              struct read_ctx *parent,
-                              const unsigned char *begin,
-                              const unsigned char *end);
-static uint64_t read_ctx_get_offset (struct read_ctx *ctx);
-static bool read_ctx_need_data (struct read_ctx *ctx, size_t length);
-static bool read_ctx_read_ubyte (struct read_ctx *ctx, unsigned char *ret);
-static int read_ctx_read_uleb128 (struct read_ctx *ctx, uint64_t *ret);
-static int read_ctx_read_sleb128 (struct read_ctx *ctx, int64_t *ret);
-static bool read_ctx_read_2ubyte (struct read_ctx *ctx, uint16_t *ret);
-static bool read_ctx_read_4ubyte (struct read_ctx *ctx, uint32_t *ret);
-static bool read_ctx_read_8ubyte (struct read_ctx *ctx, uint64_t *ret);
-static bool read_ctx_read_offset (struct read_ctx *ctx, bool dwarf64,
-                                 uint64_t *ret);
-static bool read_ctx_read_var (struct read_ctx *ctx, int width, uint64_t *ret);
-static const char *read_ctx_read_str (struct read_ctx *ctx);
-static bool read_ctx_skip (struct read_ctx *ctx, uint64_t len);
-static bool read_ctx_eof (struct read_ctx *ctx);
-
 
 /* Functions and data structures related to raw (i.e. unassisted by
    libdw) Dwarf abbreviation handling.  */
@@ -882,34 +794,41 @@ struct cu_coverage
 
 /* Functions for checking of structural integrity.  */
 
-static struct cu * check_info_structural (struct section_data *data,
+static struct cu * check_info_structural (struct elf_file *file,
+                                         struct sec *sec,
                                          struct abbrev_table *abbrev_chain,
                                          Elf_Data *strings,
                                          struct cu_coverage *cu_coverage);
 
-static bool check_aranges_structural (struct section_data *data,
+static bool check_aranges_structural (struct elf_file *file,
+                                     struct sec *sec,
                                      struct cu *cu_chain,
                                      struct coverage *coverage);
 
-static bool check_pub_structural (struct section_data *data,
+static bool check_pub_structural (struct elf_file *file,
+                                 struct sec *sec,
                                  struct cu *cu_chain);
 
-static bool check_location_expression (struct read_ctx *ctx,
+static bool check_location_expression (struct elf_file *file,
+                                      struct read_ctx *ctx,
                                       uint64_t init_off,
                                       struct relocation_data *reloc,
                                       size_t length,
                                       struct where *wh,
                                       bool addr_64);
 
-static bool check_loc_or_range_structural (struct section_data *data,
+static bool check_loc_or_range_structural (struct elf_file *file,
+                                          struct sec *sec,
                                           struct cu *cu_chain,
                                           struct cu_coverage *cu_coverage);
 
-static bool read_rel (struct section_data *secdata,
+static bool read_rel (struct elf_file *file,
+                     struct sec *sec,
                      Elf_Data *reldata,
                      bool elf_64);
 
-static bool check_line_structural (struct section_data *data,
+static bool check_line_structural (struct elf_file *file,
+                                  struct sec *sec,
                                   struct cu *cu_chain);
 
 const char *
@@ -1085,8 +1004,6 @@ where_reset_3 (struct where *wh, uint64_t addr)
   wh->addr3 = addr;
 }
 
-#define WHERE_SECDATA(DATA, PARENT) (WHERE (data_get_sec (DATA)->id, PARENT))
-
 static bool
 address_aligned (uint64_t addr, uint64_t align)
 {
@@ -1099,60 +1016,35 @@ necessary_alignment (uint64_t start, uint64_t length, uint64_t align)
   return address_aligned (start + length, align) && length < align;
 }
 
-static void
-process_file (Dwarf *dwarf, const char *fname, bool only_one)
+static bool
+elf_file_init (struct elf_file *file, Elf *elf)
 {
-  if (!only_one)
-    printf ("\n%s:\n", fname);
+  WIPE (*file);
 
-  struct elf_file file;
-  WIPE (file);
-
-  file.dwarf = dwarf;
-  file.ebl = ebl_openbackend (dwarf->elf);
-  if (file.ebl == NULL)
-    goto invalid_elf;
-  if (gelf_getehdr (dwarf->elf, &file.ehdr) == NULL)
-    goto invalid_elf;
-  file.addr_64 = file.ehdr.e_ident[EI_CLASS] == ELFCLASS64;
-
-#define DEF_SECDATA(VAR, SEC)                                  \
-  struct section_data VAR = {&file, (size_t)-1, NULL,          \
-                            {&file, NULL, SHT_NULL, NULL, 0, 0, 0}}
-
-  DEF_SECDATA (abbrev_data, sec_abbrev);
-  DEF_SECDATA (aranges_data, sec_aranges);
-  DEF_SECDATA (info_data, sec_info);
-  DEF_SECDATA (line_data, sec_line);
-  DEF_SECDATA (loc_data, sec_loc);
-  DEF_SECDATA (pubnames_data, sec_pubnames);
-  DEF_SECDATA (pubtypes_data, sec_pubtypes);
-  DEF_SECDATA (ranges_data, sec_ranges);
-  DEF_SECDATA (str_data, sec_str);
-
-#undef DEF_SECDATA
+  file->elf = elf;
+  file->ebl = ebl_openbackend (elf);
+
+  if (file->ebl == NULL
+      || gelf_getehdr (elf, &file->ehdr) == NULL)
+    return false;
+
+  file->addr_64 = file->ehdr.e_ident[EI_CLASS] == ELFCLASS64;
 
   struct secinfo
   {
     const char *name;
-    struct section_data *dataptr;
-    Elf_Data *reldata;
-    enum section_id sec;
+    enum section_id id;        /* Section type.  */
+    Elf_Data *reldata;  /* Relocation data if any found.  */
+    size_t reltype;    /* SHT_REL or SHT_RELA.  We need this
+                          temporary store to be able to resolve
+                          relocation section appearing before
+                          relocated section.  */
+    size_t secndx;     /* Index into file->sec or 0 if not yet loaded.  */
   };
   struct secinfo secinfo[] = {
-#define DEF_SECINFO(SEC) {".debug_" #SEC, &SEC##_data, NULL, sec_##SEC}
-#define DEF_NOINFO(SEC)  {".debug_" #SEC, NULL, NULL, sec_##SEC}
-    DEF_SECINFO (abbrev),
-    DEF_SECINFO (aranges),
-    DEF_SECINFO (info),
-    DEF_SECINFO (line),
-    DEF_SECINFO (loc),
-    DEF_SECINFO (pubnames),
-    DEF_SECINFO (pubtypes),
-    DEF_SECINFO (ranges),
-    DEF_SECINFO (str),
-#undef DEF_NOINFO
-#undef DEF_SECINFO
+#define SEC(n) {".debug_" #n, sec_##n, NULL, 0, 0},
+    DEBUGINFO_SECTIONS
+#undef SEC
   };
 
   Elf_Scn *reloc_symtab = NULL;
@@ -1165,41 +1057,30 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
     return NULL;
   }
 
-  struct section_data *find_secdata (const char *secname)
-  {
-    struct secinfo *info = find_secentry (secname);
-    if (info != NULL)
-      return info->dataptr;
-    else
-      return NULL;
-  }
-
   /* Now find all necessary debuginfo sections and associated
      relocation sections.  */
 
-  Elf_Scn *scn = NULL;
-
   /* Section 0 is special, skip it.  */
-  REALLOC (&file, sec);
-  file.sec[file.size++].id = sec_invalid;
+  REALLOC (file, sec);
+  file->sec[file->size++].id = sec_invalid;
 
-  while ((scn = elf_nextscn (dwarf->elf, scn)) != NULL)
+  bool check_rel = true;
+
+  for (Elf_Scn *scn = NULL; (scn = elf_nextscn (elf, scn)); )
     {
-      REALLOC (&file, sec);
-      size_t curndx = file.size++;
-      struct sec *cursec = file.sec + curndx;
+      REALLOC (file, sec);
+      size_t curndx = file->size++;
+      struct sec *cursec = file->sec + curndx;
 
       GElf_Shdr *shdr = gelf_getshdr (scn, &cursec->shdr);
       if (shdr == NULL)
        {
        invalid_elf:
-         /* A "can't happen".  libdw already managed to parse the Elf
-            file when constructing the Dwarf object.  */
          wr_error (NULL, "Broken ELF.\n");
-         goto skip_rel;
+         return false;
        }
 
-      const char *scnname = elf_strptr (dwarf->elf, file.ehdr.e_shstrndx,
+      const char *scnname = elf_strptr (elf, file->ehdr.e_shstrndx,
                                        shdr->sh_name);
       if (scnname == NULL)
        goto invalid_elf;
@@ -1210,28 +1091,34 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
                  scnname, shdr->sh_addr, shdr->sh_addralign);
 
       struct secinfo *secentry = find_secentry (scnname);
-      struct section_data *secdata = secentry != NULL ? secentry->dataptr : NULL;
       cursec->scn = scn;
-      cursec->id = secentry != NULL ? secentry->sec : sec_invalid;
+      cursec->id = secentry != NULL ? secentry->id : sec_invalid;
       cursec->name = scnname;
+      cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0};
 
-      if (secdata != NULL)
+      /* Dwarf section.  */
+      if (secentry != NULL)
        {
-         if (secdata->secndx == (size_t)-1)
+         if (unlikely (secentry->secndx != 0))
+           wr_error (NULL, "Multiple occurrences of section %s.\n", scnname);
+         else
            {
-             secdata->data = elf_getdata (scn, NULL);
-             if (secdata->data == NULL || secdata->data->d_buf == NULL)
-               wr_error (NULL, "Data-less section %s.\n", scnname);
-             secdata->secndx = curndx;
+             /* Haven't seen a section of that name yet.  */
+             cursec->data = elf_getdata (scn, NULL);
+             if (cursec->data == NULL || cursec->data->d_buf == NULL)
+               {
+                 wr_error (NULL, "Data-less section %s.\n", scnname);
+                 cursec->data = NULL;
+               }
+             secentry->secndx = curndx;
            }
-         else
-           wr_error (NULL, "Multiple occurrences of section %s.\n", scnname);
        }
+      /* Relocation section.  */
       else if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL)
        {
          /* Get data of section that this REL(A) section relocates.  */
-         Elf_Scn *relocated_scn = elf_getscn (dwarf->elf, shdr->sh_info);
-         Elf_Scn *symtab_scn = elf_getscn (dwarf->elf, shdr->sh_link);
+         Elf_Scn *relocated_scn = elf_getscn (elf, shdr->sh_info);
+         Elf_Scn *symtab_scn = elf_getscn (elf, shdr->sh_link);
          if (relocated_scn == NULL || symtab_scn == NULL)
            goto invalid_elf;
 
@@ -1242,13 +1129,13 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
            goto invalid_elf;
 
          const char *relocated_scnname
-           = elf_strptr (dwarf->elf, file.ehdr.e_shstrndx,
+           = elf_strptr (elf, file->ehdr.e_shstrndx,
                          relocated_shdr->sh_name);
 
          struct secinfo *relocated
            = find_secentry (relocated_scnname);
 
-         if (relocated != NULL && relocated->dataptr != NULL)
+         if (relocated != NULL)
            {
              if (relocated->reldata != NULL)
                wr_error (NULL,
@@ -1258,10 +1145,15 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
              else
                {
                  relocated->reldata = elf_getdata (scn, NULL);
-                 if (relocated->reldata == NULL)
-                   wr_error (NULL,
-                             "Data-less relocation section %s.\n", scnname);
-                 relocated->dataptr->rel.type = shdr->sh_type;
+                 if (unlikely (relocated->reldata == NULL
+                               || relocated->reldata->d_buf == NULL))
+                   {
+                     wr_error (NULL,
+                               "Data-less relocation section %s.\n", scnname);
+                     relocated->reldata = NULL;
+                   }
+                 else
+                   relocated->reltype = shdr->sh_type;
                }
 
              if (reloc_symtab == NULL)
@@ -1273,49 +1165,67 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
        }
     }
 
-  Elf_Data *reloc_symdata = NULL;
-  if (reloc_symtab != NULL)
+  for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i)
+    if (secinfo[i].secndx != 0)
+      file->debugsec[secinfo[i].id] = file->sec + secinfo[i].secndx;
+
+  if (check_rel)
     {
-      reloc_symdata = elf_getdata (reloc_symtab, NULL);
-      if (reloc_symdata == NULL)
+      Elf_Data *reloc_symdata = NULL;
+      if (reloc_symtab != NULL)
        {
-         wr_error (NULL,
-                   "Couldn't obtain symtab data.\n");
-         /* But carry on, we can check a lot of stuff even without
-            symbol table.  */
+         reloc_symdata = elf_getdata (reloc_symtab, NULL);
+         if (reloc_symdata == NULL)
+           /* Not a show stopper, we can check a lot of stuff even
+              without a symbol table.  */
+             wr_error (NULL,
+                       "Couldn't obtain symtab data.\n");
        }
-    }
 
-  /* Check relocation sections that we've got.  */
-  for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i)
-    {
-      struct secinfo *cur = secinfo + i;
-      if (cur->dataptr != NULL
-         && cur->reldata != NULL)
+      /* Check relocation sections that we've got.  */
+      for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i)
        {
-         if (cur->dataptr->data == NULL)
-           wr_error (&WHERE_SECDATA (secinfo[i].dataptr, NULL),
-                     ": this data-less section has a relocation section.\n");
-         else if (read_rel (cur->dataptr, cur->reldata, file.addr_64))
-           cur->dataptr->rel.symdata = reloc_symdata;
+         struct secinfo *cur = secinfo + i;
+         if (cur->secndx != 0 && cur->reldata != NULL)
+           {
+             struct sec *sec = file->sec + cur->secndx;
+             sec->rel.type = cur->reltype;
+             if (sec->data == NULL)
+               wr_error (&WHERE (sec->id, NULL),
+                         ": this data-less section has a relocation section.\n");
+             else if (read_rel (file, sec, cur->reldata, file->addr_64))
+               sec->rel.symdata = reloc_symdata;
+           }
        }
+
+      if (find_secentry (".debug_str")->reldata != NULL)
+       wr_message (mc_impact_2 | mc_elf, &WHERE (sec_str, NULL),
+                   ": there's a relocation section associated with this section.\n");
     }
 
-  if (str_data.rel.size > 0)
-    wr_message (mc_impact_2 | mc_elf, &WHERE (sec_str, NULL),
-               ": there's a relocation section associated with this section.\n");
+  return true;
+}
+
+static void
+process_file (Elf *elf, const char *fname, bool only_one)
+{
+  if (!only_one)
+    printf ("\n%s:\n", fname);
+
+  struct elf_file file;
+  if (!elf_file_init (&file, elf))
+    return;
 
- skip_rel:;
   struct abbrev_table *abbrev_chain = NULL;
   struct cu *cu_chain = NULL;
   struct read_ctx ctx;
-  struct hl_ctx *hlctx = hl_ctx_new (dwarf);
+  struct hl_ctx *hlctx = hl_ctx_new (elf);
+
+#define SEC(sec) (file.debugsec[sec_##sec])
 
-  /* If we got Dwarf pointer, .debug_abbrev and .debug_info are
-     present inside the file.  But let's be paranoid.  */
-  if (likely (abbrev_data.data != NULL))
+  if (likely (SEC(abbrev) != NULL))
     {
-      read_ctx_init (&ctx, dwarf, abbrev_data.data);
+      read_ctx_init (&ctx, &file, SEC(abbrev)->data);
       abbrev_chain = abbrev_table_load (&ctx);
     }
   else if (!tolerate_nodebug)
@@ -1325,11 +1235,11 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
   struct cu_coverage *cu_coverage = NULL;
   if (abbrev_chain != NULL)
     {
-      if (info_data.data != NULL)
+      if (SEC(info) != NULL)
        {
          cu_coverage = calloc (1, sizeof (struct cu_coverage));
-         cu_chain = check_info_structural (&info_data, abbrev_chain,
-                                           str_data.data, cu_coverage);
+         cu_chain = check_info_structural (&file, SEC(info), abbrev_chain,
+                                           SEC(str)->data, cu_coverage);
          if (cu_chain != NULL && do_high_level)
            check_expected_trees (hlctx);
        }
@@ -1339,43 +1249,44 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
     }
 
   bool ranges_sound;
-  if (ranges_data.data != NULL && cu_chain != NULL)
-    ranges_sound
-      = check_loc_or_range_structural (&ranges_data, cu_chain, cu_coverage);
+  if (SEC(ranges) != NULL && cu_chain != NULL)
+    ranges_sound = check_loc_or_range_structural (&file, SEC(ranges),
+                                                 cu_chain, cu_coverage);
   else
     ranges_sound = false;
 
-  if (loc_data.data != NULL && cu_chain != NULL)
-    check_loc_or_range_structural (&loc_data, cu_chain, NULL);
+  if (SEC(loc) != NULL && cu_chain != NULL)
+    check_loc_or_range_structural (&file, SEC(loc), cu_chain, NULL);
 
-  if (aranges_data.data != NULL)
+  if (SEC(aranges) != NULL)
     {
-      read_ctx_init (&ctx, dwarf, aranges_data.data);
+      read_ctx_init (&ctx, &file, SEC(aranges)->data);
 
       /* If ranges were needed and not loaded, don't pass them down
         for CU/aranges coverage analysis. */
       struct coverage *cov
-       = cu_coverage->need_ranges ? NULL : &cu_coverage->cov;
+       = (cu_coverage != NULL
+          && cu_coverage->need_ranges) ? NULL : &cu_coverage->cov;
 
-      if (check_aranges_structural (&aranges_data, cu_chain, cov)
+      if (check_aranges_structural (&file, SEC(aranges), cu_chain, cov)
          && ranges_sound && do_high_level && !be_tolerant && !be_gnu)
        check_matching_ranges (hlctx);
     }
 
-  if (pubnames_data.data != NULL)
-    check_pub_structural (&pubnames_data, cu_chain);
+  if (SEC(pubnames) != NULL)
+    check_pub_structural (&file, SEC(pubnames), cu_chain);
   else
     wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf,
                &WHERE (sec_pubnames, NULL), ": data not found.\n");
 
-  if (pubtypes_data.data != NULL)
-    check_pub_structural (&pubtypes_data, cu_chain);
+  if (SEC(pubtypes) != NULL)
+    check_pub_structural (&file, SEC(pubtypes), cu_chain);
   else
     wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_pubtypes,
                &WHERE (sec_pubtypes, NULL), ": data not found.\n");
 
-  if (line_data.data != NULL)
-    check_line_structural (&line_data, cu_chain);
+  if (SEC(line) != NULL)
+    check_line_structural (&file, SEC(line), cu_chain);
   else
     wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_loc,
                &WHERE (sec_line, NULL), ": data not found.\n");
@@ -1386,92 +1297,8 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
     ebl_closebackend (file.ebl);
   free (file.sec);
   hl_ctx_delete (hlctx);
-}
-
-static void
-read_ctx_init (struct read_ctx *ctx, Dwarf *dbg, Elf_Data *data)
-{
-  if (data == NULL)
-    abort ();
-
-  ctx->dbg = dbg;
-  ctx->data = data;
-  ctx->begin = data->d_buf;
-  ctx->end = data->d_buf + data->d_size;
-  ctx->ptr = data->d_buf;
-}
-
-static bool
-read_ctx_init_sub (struct read_ctx *ctx, struct read_ctx *parent,
-                  const unsigned char *begin, const unsigned char *end)
-{
-  if (parent == NULL)
-    abort ();
-
-  if (begin < parent->begin
-      || end > parent->end)
-    return false;
-
-  ctx->dbg = parent->dbg;
-  ctx->data = parent->data;
-  ctx->begin = begin;
-  ctx->end = end;
-  ctx->ptr = begin;
-  return true;
-}
-
-static uint64_t
-read_ctx_get_offset (struct read_ctx *ctx)
-{
-  assert (ctx->ptr >= ctx->begin);
-  return (uint64_t)(ctx->ptr - ctx->begin);
-}
-
-static bool
-read_ctx_need_data (struct read_ctx *ctx, size_t length)
-{
-  const unsigned char *ptr = ctx->ptr + length;
-  return ptr <= ctx->end && (length == 0 || ptr > ctx->ptr);
-}
-
-static bool
-read_ctx_read_ubyte (struct read_ctx *ctx, unsigned char *ret)
-{
-  if (!read_ctx_need_data (ctx, 1))
-    return false;
-  if (ret != NULL)
-    *ret = *ctx->ptr;
-  ctx->ptr++;
-  return true;
-}
-
-static int
-read_ctx_read_uleb128 (struct read_ctx *ctx, uint64_t *ret)
-{
-  uint64_t result = 0;
-  int shift = 0;
-  int size = 8 * sizeof (result);
-  bool zero_tail = false;
-
-  while (1)
-    {
-      uint8_t byte;
-      if (!read_ctx_read_ubyte (ctx, &byte))
-       return -1;
-
-      uint8_t payload = byte & 0x7f;
-      zero_tail = payload == 0 && shift > 0;
-      result |= (uint64_t)payload << shift;
-      shift += 7;
-      if (shift > size && byte != 0x1)
-       return -1;
-      if ((byte & 0x80) == 0)
-       break;
-    }
 
-  if (ret != NULL)
-    *ret = result;
-  return zero_tail ? 1 : 0;
+#undef SEC
 }
 
 static bool
@@ -1491,42 +1318,6 @@ checked_read_uleb128 (struct read_ctx *ctx, uint64_t *ret,
   return st >= 0;
 }
 
-static int
-read_ctx_read_sleb128 (struct read_ctx *ctx, int64_t *ret)
-{
-  int64_t result = 0;
-  int shift = 0;
-  int size = 8 * sizeof (result);
-  bool zero_tail = false;
-  bool sign = false;
-
-  while (1)
-    {
-      uint8_t byte;
-      if (!read_ctx_read_ubyte (ctx, &byte))
-       return -1;
-
-      uint8_t payload = byte & 0x7f;
-      zero_tail = shift > 0 && ((payload == 0x7f && sign)
-                               || (payload == 0 && !sign));
-      sign = (byte & 0x40) != 0; /* Set sign for rest of loop & next round.  */
-      result |= (int64_t)payload << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-       {
-         if (shift < size && sign)
-           result |= -((int64_t)1 << shift);
-         break;
-       }
-      if (shift > size)
-       return -1;
-    }
-
-  if (ret != NULL)
-    *ret = result;
-  return zero_tail ? 1 : 0;
-}
-
 static bool
 checked_read_sleb128 (struct read_ctx *ctx, int64_t *ret,
                      struct where *where, const char *what)
@@ -1545,83 +1336,6 @@ checked_read_sleb128 (struct read_ctx *ctx, int64_t *ret,
   return st >= 0;
 }
 
-static bool
-read_ctx_read_2ubyte (struct read_ctx *ctx, uint16_t *ret)
-{
-  if (!read_ctx_need_data (ctx, 2))
-    return false;
-  uint16_t val = read_2ubyte_unaligned_inc (ctx->dbg, ctx->ptr);
-  if (ret != NULL)
-    *ret = val;
-  return true;
-}
-
-static bool
-read_ctx_read_4ubyte (struct read_ctx *ctx, uint32_t *ret)
-{
-  if (!read_ctx_need_data (ctx, 4))
-    return false;
-  uint32_t val = read_4ubyte_unaligned_inc (ctx->dbg, ctx->ptr);
-  if (ret != NULL)
-    *ret = val;
-  return true;
-}
-
-static bool
-read_ctx_read_8ubyte (struct read_ctx *ctx, uint64_t *ret)
-{
-  if (!read_ctx_need_data (ctx, 8))
-    return false;
-  uint64_t val = read_8ubyte_unaligned_inc (ctx->dbg, ctx->ptr);
-  if (ret != NULL)
-    *ret = val;
-  return true;
-}
-
-static bool
-read_ctx_read_offset (struct read_ctx *ctx, bool dwarf64, uint64_t *ret)
-{
-  if (dwarf64)
-    return read_ctx_read_8ubyte (ctx, ret);
-
-  uint32_t v;
-  if (!read_ctx_read_4ubyte (ctx, &v))
-    return false;
-
-  if (ret != NULL)
-    *ret = (uint64_t)v;
-  return true;
-}
-
-static bool
-read_ctx_read_var (struct read_ctx *ctx, int width, uint64_t *ret)
-{
-  switch (width)
-    {
-    case 4:
-    case 8:
-      return read_ctx_read_offset (ctx, width == 8, ret);
-    case 2:
-      {
-       uint16_t val;
-       if (!read_ctx_read_2ubyte (ctx, &val))
-         return false;
-       *ret = val;
-       return true;
-      }
-    case 1:
-      {
-       uint8_t val;
-       if (!read_ctx_read_ubyte (ctx, &val))
-         return false;
-       *ret = val;
-       return true;
-      }
-    default:
-      return false;
-    };
-}
-
 /* The value passed back in uint64_t VALUEP may actually be
    type-casted int64_t.  WHAT and WHERE describe error message and
    context for LEB128 loading.  */
@@ -1671,33 +1385,6 @@ read_ctx_read_form (struct read_ctx *ctx, bool addr_64, uint8_t form,
   return false;
 }
 
-static const char *
-read_ctx_read_str (struct read_ctx *ctx)
-{
-  const char *ret = (const char *)ctx->ptr;
-  uint8_t byte;
-  do
-    if (!read_ctx_read_ubyte (ctx, &byte))
-      return NULL;
-  while (byte != 0);
-  return ret;
-}
-
-static bool
-read_ctx_skip (struct read_ctx *ctx, uint64_t len)
-{
-  if (!read_ctx_need_data (ctx, len))
-    return false;
-  ctx->ptr += len;
-  return true;
-}
-
-static bool
-read_ctx_eof (struct read_ctx *ctx)
-{
-  return !read_ctx_need_data (ctx, 1);
-}
-
 static bool
 attrib_form_valid (uint64_t form)
 {
@@ -2181,13 +1868,6 @@ coverage_map_found_hole (uint64_t begin, uint64_t end,
   const char *scnname = sco->sec->name;
 
   struct sec *sec = sco->sec;
-  Elf_Data *data = elf_getdata (sec->scn, NULL);
-  if (data == NULL)
-    {
-      wr_error (&where, ": couldn't read the data of section %s.\n", scnname);
-      return false;
-    }
-
   GElf_Xword align = sec->shdr.sh_addralign;
 
   /* We don't expect some sections to be covered.  But if they
@@ -2207,11 +1887,11 @@ coverage_map_found_hole (uint64_t begin, uint64_t end,
      get stripped debuginfo file, the data may not be available.  In
      that case don't report the hole, if it seems to be alignment
      padding.  */
-  if (data->d_buf != NULL)
+  if (sco->sec->data->d_buf != NULL)
     {
       bool zeroes = true;
       for (uint64_t j = begin; j < end; ++j)
-       if (((char *)data->d_buf)[j] != 0)
+       if (((char *)sco->sec->data->d_buf)[j] != 0)
          {
            zeroes = false;
            break;
@@ -2610,10 +2290,10 @@ relocation_skip (struct relocation_data *reloc, uint64_t offset,
 
 /* Skip all the remaining relocations.  */
 static void
-relocation_skip_rest (struct section_data *data)
+relocation_skip_rest (struct sec *sec)
 {
-  if (data->rel.rel != NULL)
-    relocation_next (&data->rel, (uint64_t)-1, &WHERE_SECDATA (data, NULL),
+  if (sec->rel.rel != NULL)
+    relocation_next (&sec->rel, (uint64_t)-1, &WHERE (sec->id, NULL),
                     skip_mismatched);
 }
 
@@ -2622,7 +2302,9 @@ relocation_skip_rest (struct section_data *data)
    which case we failed or didn't get around to obtain the symbol from
    symbol table, or non-NULL, in which case the symbol was initialized.  */
 static void
-relocate_one (struct relocation_data *reloc, struct relocation *rel,
+relocate_one (struct elf_file *file,
+             struct relocation_data *reloc,
+             struct relocation *rel,
              unsigned width, uint64_t *value, struct where *where,
              enum section_id offset_into, GElf_Sym **symptr)
 {
@@ -2650,7 +2332,7 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
       return;
     }
 
-  Elf_Type type = ebl_reloc_simple_type (reloc->file->ebl, rel->type);
+  Elf_Type type = ebl_reloc_simple_type (file->ebl, rel->type);
 
   unsigned rel_width;
   switch (type)
@@ -2684,7 +2366,7 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
              ": %d-byte relocation relocates %d-byte datum.\n",
              rel_width, width);
 
-  /* Tolerate that we might have failed to obtain a symbol table.  */
+  /* Tolerate that we might have failed to obtain the symbol table.  */
   if (reloc->symdata != NULL)
     {
       symbol = gelf_getsym (reloc->symdata, rel->symndx, symbol);
@@ -2707,11 +2389,11 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
         don't update symbol table doing that.  So instead of looking
         at symbol value, look at section address.  */
       uint64_t sym_value = symbol->st_value;
-      if (reloc->file->ehdr.e_type == ET_REL
+      if (file->ehdr.e_type == ET_REL
          && ELF64_ST_TYPE (symbol->st_info) == STT_SECTION)
        {
          assert (sym_value == 0);
-         sym_value = reloc->file->sec[section_index].shdr.sh_addr;
+         sym_value = file->sec[section_index].shdr.sh_addr;
        }
 
       /* It's target value, not section offset.  */
@@ -2728,33 +2410,23 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
                    && (section_index == SHN_UNDEF
                        || section_index == SHN_COMMON))))
            {
-             Elf_Scn *scn;
-             GElf_Shdr shdr_mem, *shdr;
              if (offset_into != rel_address && section_index == SHN_UNDEF)
                wr_error (&reloc_where,
                            ": relocation of an address is formed against SHN_UNDEF symbol"
                            " (symtab index %d).\n", rel->symndx);
-             else if ((scn = elf_getscn (reloc->file->dwarf->elf,
-                                         section_index)) == NULL)
-               wr_error (&reloc_where,
-                         ": couldn't obtain associated section #%" PRId64 ".\n",
-                         section_index);
-             else if ((shdr = gelf_getshdr (scn, &shdr_mem)) == NULL)
-               wr_error (&reloc_where,
-                         ": couldn't obtain header of associated section #%" PRId64 ".\n",
-                         section_index);
              else
                {
+                 GElf_Shdr *shdr = &file->sec[section_index].shdr;
                  if ((shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC)
                    wr_message (mc_reloc | mc_impact_3, &reloc_where,
                                ": associated section %s isn't SHF_ALLOC.\n",
-                               reloc->file->sec[section_index].name);
+                               file->sec[section_index].name);
                  if (offset_into == rel_exec
                      && (shdr->sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
                    /* This may still be kosher, but it's suspicious.  */
                    wr_message (mc_reloc | mc_impact_2, &reloc_where,
                                ": relocation against %s is suspicious, expected executable section.\n",
-                               reloc->file->sec[section_index].name);
+                               file->sec[section_index].name);
                }
            }
        }
@@ -2763,15 +2435,15 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
          enum section_id id;
          /* If symtab[symndx].st_shndx does not match the expected
             debug section's index, complain.  */
-         if (section_index >= reloc->file->size)
+         if (section_index >= file->size)
            wr_error (&reloc_where,
                      ": invalid associated section #%" PRId64 ".\n",
                      section_index);
-         else if ((id = reloc->file->sec[section_index].id) != offset_into)
+         else if ((id = file->sec[section_index].id) != offset_into)
            {
              char *wh1 = id != sec_invalid
                ? strdup (where_fmt (&WHERE (id, NULL), NULL))
-               : (char *)reloc->file->sec[section_index].name;
+               : (char *)file->sec[section_index].name;
              char *wh2 = strdup (where_fmt (&WHERE (offset_into, NULL), NULL));
              wr_error (&reloc_where,
                        ": relocation references section %s, but %s was expected.\n",
@@ -2784,7 +2456,7 @@ relocate_one (struct relocation_data *reloc, struct relocation *rel,
 
       /* Only do the actual relocation if we have ET_REL files.  For
         non-ET_REL files, only do the above checking.  */
-      if (reloc->file->ehdr.e_type == ET_REL)
+      if (file->ehdr.e_type == ET_REL)
        {
          *value = rel->addend + sym_value;
          if (rel_width == 4)
@@ -2954,7 +2626,8 @@ check_range_relocations (enum message_category cat,
     +1 in case some dies were actually loaded
  */
 static int
-read_die_chain (struct read_ctx *ctx,
+read_die_chain (struct elf_file *file,
+               struct read_ctx *ctx,
                struct cu *cu,
                struct abbrev_table *abbrevs,
                Elf_Data *strings,
@@ -2962,7 +2635,6 @@ read_die_chain (struct read_ctx *ctx,
                struct ref_record *local_die_refs,
                struct coverage *strings_coverage,
                struct relocation_data *reloc,
-               struct elf_file *file,
                struct cu_coverage *cu_coverage)
 {
   bool got_die = false;
@@ -3218,7 +2890,7 @@ read_die_chain (struct read_ctx *ctx,
 
                if ((rel = relocation_next (reloc, ctx_offset,
                                            &where, skip_mismatched)))
-                 relocate_one (reloc, rel, dwarf_64 ? 8 : 4,
+                 relocate_one (file, reloc, rel, dwarf_64 ? 8 : 4,
                                &addr, &where, sec_str, NULL);
                else if (type_is_rel)
                  wr_message (mc_impact_2 | mc_die_other | mc_reloc | mc_strings,
@@ -3278,8 +2950,8 @@ read_die_chain (struct read_ctx *ctx,
                if ((rel = relocation_next (reloc, ctx_offset,
                                            &where, skip_mismatched)))
                  {
-                   relocate_one (reloc, rel, addr_64 ? 8 : 4, &addr, &where,
-                                 reloc_target (form, it), symbolp);
+                   relocate_one (file, reloc, rel, addr_64 ? 8 : 4, &addr,
+                                 &where, reloc_target (form, it), symbolp);
                    if (relocatedp != NULL)
                      *relocatedp = true;
                  }
@@ -3373,7 +3045,7 @@ read_die_chain (struct read_ctx *ctx,
                  {
                    if ((rel = relocation_next (reloc, ctx_offset,
                                                &where, skip_mismatched)))
-                     relocate_one (reloc, rel, 4, &value, &where,
+                     relocate_one (file, reloc, rel, 4, &value, &where,
                                    reloc_target (form, it), NULL);
                    else if (type_is_rel && check_ptr != check_nothing)
                      wr_message (mc_impact_2 | mc_die_other | mc_reloc
@@ -3403,7 +3075,7 @@ read_die_chain (struct read_ctx *ctx,
                  {
                    if ((rel = relocation_next (reloc, ctx_offset,
                                                &where, skip_mismatched)))
-                     relocate_one (reloc, rel, 8, &value, &where,
+                     relocate_one (file, reloc, rel, 8, &value, &where,
                                    reloc_target (form, it), NULL);
                    else if (type_is_rel && check_ptr != check_nothing)
                      wr_message (mc_impact_2 | mc_die_other | mc_reloc
@@ -3460,7 +3132,7 @@ read_die_chain (struct read_ctx *ctx,
                if (is_location_attrib (it->name))
                  {
                    uint64_t expr_start = cu->offset + read_ctx_get_offset (ctx);
-                   if (!check_location_expression (ctx, expr_start,
+                   if (!check_location_expression (file, ctx, expr_start,
                                                    reloc, length,
                                                    &where, addr_64))
                      return -1;
@@ -3503,10 +3175,10 @@ read_die_chain (struct read_ctx *ctx,
 
       if (abbrev->has_children)
        {
-         int st = read_die_chain (ctx, cu, abbrevs, strings,
+         int st = read_die_chain (file, ctx, cu, abbrevs, strings,
                                   dwarf_64, addr_64,
                                   local_die_refs,
-                                  strings_coverage, reloc, file,
+                                  strings_coverage, reloc,
                                   cu_coverage);
          if (st == -1)
            return -1;
@@ -3526,14 +3198,14 @@ read_die_chain (struct read_ctx *ctx,
 }
 
 static bool
-check_cu_structural (struct read_ctx *ctx,
+check_cu_structural (struct elf_file *file,
+                    struct read_ctx *ctx,
                     struct cu *const cu,
                     struct abbrev_table *abbrev_chain,
                     Elf_Data *strings,
                     bool dwarf_64,
                     struct coverage *strings_coverage,
                     struct relocation_data *reloc,
-                    struct elf_file *file,
                     struct cu_coverage *cu_coverage)
 {
   uint8_t address_size;
@@ -3566,7 +3238,7 @@ check_cu_structural (struct read_ctx *ctx,
   struct relocation *rel
     = relocation_next (reloc, ctx_offset, &cu->where, skip_mismatched);
   if (rel != NULL)
-    relocate_one (reloc, rel, dwarf_64 ? 8 : 4,
+    relocate_one (file, reloc, rel, dwarf_64 ? 8 : 4,
                  &abbrev_offset, &cu->where, sec_abbrev, NULL);
   else if (file->ehdr.e_type == ET_REL)
     wr_message (mc_impact_2 | mc_info | mc_reloc, &cu->where,
@@ -3604,11 +3276,11 @@ check_cu_structural (struct read_ctx *ctx,
   WIPE (local_die_refs);
 
   cu->cudie_offset = read_ctx_get_offset (ctx) + cu->offset;
-  if (read_die_chain (ctx, cu, abbrevs, strings,
+  if (read_die_chain (file, ctx, cu, abbrevs, strings,
                      dwarf_64, address_size == 8,
                      &local_die_refs, strings_coverage,
                      (reloc != NULL && reloc->size > 0) ? reloc : NULL,
-                     file, cu_coverage) >= 0)
+                     cu_coverage) >= 0)
     {
       for (size_t i = 0; i < abbrevs->size; ++i)
        if (!abbrevs->abbr[i].used)
@@ -3627,13 +3299,14 @@ check_cu_structural (struct read_ctx *ctx,
 }
 
 static struct cu *
-check_info_structural (struct section_data *data,
+check_info_structural (struct elf_file *file,
+                      struct sec *sec,
                       struct abbrev_table *abbrev_chain,
                       Elf_Data *strings,
                       struct cu_coverage *cu_coverage)
 {
   struct read_ctx ctx;
-  read_ctx_init (&ctx, data->file->dwarf, data->data);
+  read_ctx_init (&ctx, file, sec->data);
 
   struct ref_record die_refs;
   WIPE (die_refs);
@@ -3649,7 +3322,7 @@ check_info_structural (struct section_data *data,
       strings_coverage = &strings_coverage_mem;
     }
 
-  struct relocation_data *reloc = data->rel.size > 0 ? &data->rel : NULL;
+  struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
   while (!read_ctx_eof (&ctx))
     {
       const unsigned char *cu_begin = ctx.ptr;
@@ -3725,9 +3398,9 @@ check_info_structural (struct section_data *data,
            }
          cu_ctx.ptr = ctx.ptr;
 
-         if (!check_cu_structural (&cu_ctx, cur, abbrev_chain,
+         if (!check_cu_structural (file, &cu_ctx, cur, abbrev_chain,
                                    strings, dwarf_64,
-                                   strings_coverage, reloc, data->file,
+                                   strings_coverage, reloc,
                                    cu_coverage))
            {
              success = false;
@@ -3753,7 +3426,7 @@ check_info_structural (struct section_data *data,
                    ": CU lengths don't exactly match Elf_Data contents.");
       else
        /* Did we consume all the relocations?  */
-       relocation_skip_rest (data);
+       relocation_skip_rest (sec);
     }
 
 
@@ -3889,11 +3562,13 @@ compare_coverage (struct elf_file *file,
    low_pc/high_pc pairs, or via DW_AT_ranges references).  If
    non-NULL, analysis of arange coverage is done against that set. */
 static bool
-check_aranges_structural (struct section_data *data, struct cu *cu_chain,
+check_aranges_structural (struct elf_file *file,
+                         struct sec *sec,
+                         struct cu *cu_chain,
                          struct coverage *coverage)
 {
   struct read_ctx ctx;
-  read_ctx_init (&ctx, data->file->dwarf, data->data);
+  read_ctx_init (&ctx, file, sec->data);
 
   bool retval = true;
 
@@ -3969,11 +3644,11 @@ check_aranges_structural (struct section_data *data, struct cu *cu_chain,
        }
 
       struct relocation *rel;
-      if ((rel = relocation_next (&data->rel, ctx_offset,
+      if ((rel = relocation_next (&sec->rel, ctx_offset,
                                  &where, skip_mismatched)))
-       relocate_one (&data->rel, rel, dwarf_64 ? 8 : 4,
+       relocate_one (file, &sec->rel, rel, dwarf_64 ? 8 : 4,
                      &cu_offset, &where, sec_info, NULL);
-      else if (data->file->ehdr.e_type == ET_REL)
+      else if (file->ehdr.e_type == ET_REL)
        wr_message (mc_impact_2 | mc_aranges | mc_reloc | mc_header, &where,
                    PRI_LACK_RELOCATION, "debug info offset");
 
@@ -4052,7 +3727,8 @@ check_aranges_structural (struct section_data *data, struct cu *cu_chain,
              if (!read_ctx_read_ubyte (&sub_ctx, &c))
                {
                  wr_error (&where,
-                           ": section ends after the header, but before the first entry.\n");
+                           ": section ends after the header, "
+                           "but before the first entry.\n");
                  retval = false;
                  goto next;
                }
@@ -4087,15 +3763,14 @@ check_aranges_structural (struct section_data *data, struct cu *cu_chain,
              goto next;
            }
 
-         if ((rel = relocation_next (&data->rel, ctx_offset,
+         if ((rel = relocation_next (&sec->rel, ctx_offset,
                                      &where, skip_mismatched)))
            {
              address_relocated = true;
-             relocate_one (&data->rel, rel, address_size,
+             relocate_one (file, &sec->rel, rel, address_size,
                            &address, &where, rel_address, NULL);
            }
-         else if (data->file->ehdr.e_type == ET_REL
-                  && address != 0)
+         else if (file->ehdr.e_type == ET_REL && address != 0)
            wr_message (mc_impact_2 | mc_aranges | mc_reloc, &where,
                        PRI_LACK_RELOCATION, "address field");
 
@@ -4139,25 +3814,27 @@ check_aranges_structural (struct section_data *data, struct cu *cu_chain,
     }
 
   if (aranges_coverage != NULL)
-    compare_coverage (data->file, coverage, aranges_coverage,
-                     sec_aranges, "aranges");
-
-  coverage_free (aranges_coverage);
+    {
+      compare_coverage (file, coverage, aranges_coverage,
+                       sec_aranges, "aranges");
+      coverage_free (aranges_coverage);
+    }
 
   return retval;
 }
 
 static bool
-check_pub_structural (struct section_data *data,
+check_pub_structural (struct elf_file *file,
+                     struct sec *sec,
                      struct cu *cu_chain)
 {
   struct read_ctx ctx;
-  read_ctx_init (&ctx, data->file->dwarf, data->data);
+  read_ctx_init (&ctx, file, sec->data);
   bool retval = true;
 
   while (!read_ctx_eof (&ctx))
     {
-      struct where where = WHERE_SECDATA (data, NULL);
+      struct where where = WHERE (sec->id, NULL);
       where_reset_1 (&where, read_ctx_get_offset (&ctx));
       const unsigned char *set_begin = ctx.ptr;
 
@@ -4208,22 +3885,21 @@ check_pub_structural (struct section_data *data,
        }
 
       struct relocation *rel;
-      if ((rel = relocation_next (&data->rel, ctx_offset,
+      if ((rel = relocation_next (&sec->rel, ctx_offset,
                                  &where, skip_mismatched)))
-       relocate_one (&data->rel, rel, dwarf_64 ? 8 : 4,
+       relocate_one (file, &sec->rel, rel, dwarf_64 ? 8 : 4,
                      &cu_offset, &where, sec_info, NULL);
-      else if (data->file->ehdr.e_type == ET_REL)
+      else if (file->ehdr.e_type == ET_REL)
        wr_message (mc_impact_2 | mc_pubtables | mc_reloc | mc_header, &where,
                    PRI_LACK_RELOCATION, "debug info offset");
 
       struct cu *cu = NULL;
-      enum section_id sec = data_get_sec (data)->id;
       if (cu_chain != NULL && (cu = cu_find_cu (cu_chain, cu_offset)) == NULL)
        wr_error (&where, ": unresolved reference to " PRI_CU ".\n", cu_offset);
       if (cu != NULL)
        {
          where.ref = &cu->where;
-         bool *has = sec == sec_pubnames
+         bool *has = sec->id == sec_pubnames
                        ? &cu->has_pubnames : &cu->has_pubtypes;
          if (*has)
            wr_message (mc_impact_2 | mc_pubtables | mc_header, &where,
@@ -4287,10 +3963,10 @@ check_pub_structural (struct section_data *data,
 
       if (sub_ctx.ptr != sub_ctx.end
          && !check_zero_padding (&sub_ctx, mc_pubtables,
-                                 &WHERE (sec, NULL)))
+                                 &WHERE (sec->id, NULL)))
        {
          wr_message_padding_n0 (mc_pubtables | mc_error,
-                                &WHERE (sec, NULL),
+                                &WHERE (sec->id, NULL),
                                 read_ctx_get_offset (&sub_ctx),
                                 read_ctx_get_offset (&sub_ctx) + size);
          retval = false;
@@ -4302,7 +3978,7 @@ check_pub_structural (struct section_data *data,
     }
 
   if (retval)
-    relocation_skip_rest (data);
+    relocation_skip_rest (sec);
 
   return retval;
 }
@@ -4331,7 +4007,8 @@ get_location_opcode_operands (uint8_t opcode, uint8_t *op1, uint8_t *op2)
 }
 
 static bool
-check_location_expression (struct read_ctx *parent_ctx,
+check_location_expression (struct elf_file *file,
+                          struct read_ctx *parent_ctx,
                           uint64_t init_off,
                           struct relocation_data *reloc,
                           size_t length,
@@ -4392,7 +4069,7 @@ check_location_expression (struct read_ctx *parent_ctx,
            struct relocation *_rel;                                    \
            if ((_rel = relocation_next (reloc, _off,                   \
                                         &where, skip_mismatched)))     \
-             relocate_one (reloc, _rel,                                \
+             relocate_one (file, reloc, _rel,                          \
                            addr_64 ? 8 : 4, _ptr, &where,              \
                            reloc_target_loc (opcode), NULL);           \
          }                                                             \
@@ -4465,9 +4142,10 @@ check_location_expression (struct read_ctx *parent_ctx,
 }
 
 static bool
-check_loc_or_range_ref (const struct read_ctx *parent_ctx,
+check_loc_or_range_ref (struct elf_file *file,
+                       const struct read_ctx *parent_ctx,
                        struct cu *cu,
-                       struct section_data *data,
+                       struct sec *sec,
                        struct coverage *coverage,
                        struct coverage_map *coverage_map,
                        struct cu_coverage *cu_coverage,
@@ -4477,15 +4155,14 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
                        enum message_category cat)
 {
   char buf[128]; // messages
-  enum section_id sec = data_get_sec (data)->id;
 
-  assert (sec == sec_loc || sec == sec_ranges);
+  assert (sec->id == sec_loc || sec->id == sec_ranges);
   assert (cat == mc_loc || cat == mc_ranges);
-  assert ((sec == sec_loc) == (cat == mc_loc));
+  assert ((sec->id == sec_loc) == (cat == mc_loc));
   assert (coverage != NULL);
 
   struct read_ctx ctx;
-  read_ctx_init (&ctx, parent_ctx->dbg, parent_ctx->data);
+  read_ctx_init (&ctx, parent_ctx->file, parent_ctx->data);
   if (!read_ctx_skip (&ctx, addr))
     {
       wr_error (wh, ": invalid reference outside the section "
@@ -4495,7 +4172,7 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
     }
 
   bool retval = true;
-  bool contains_locations = sec == sec_loc;
+  bool contains_locations = sec->id == sec_loc;
 
   if (coverage_is_covered (coverage, addr, 1))
     {
@@ -4510,7 +4187,7 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
   uint64_t base = cu->low_pc;
   while (!read_ctx_eof (&ctx))
     {
-      struct where where = WHERE (sec, wh);
+      struct where where = WHERE (sec->id, wh);
       where_reset_1 (&where, read_ctx_get_offset (&ctx));
 
 #define HAVE_OVERLAP                                           \
@@ -4536,11 +4213,11 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
        }
 
       struct relocation *rel;
-      if ((rel = relocation_next (&data->rel, begin_off,
+      if ((rel = relocation_next (&sec->rel, begin_off,
                                  &where, skip_mismatched)))
        {
          begin_relocated = true;
-         relocate_one (&data->rel, rel, addr_64 ? 8 : 4,
+         relocate_one (file, &sec->rel, rel, addr_64 ? 8 : 4,
                        &begin_addr, &where, rel_value, &begin_symbol);
        }
 
@@ -4559,11 +4236,11 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
          return false;
        }
 
-      if ((rel = relocation_next (&data->rel, end_off,
+      if ((rel = relocation_next (&sec->rel, end_off,
                                  &where, skip_mismatched)))
        {
          end_relocated = true;
-         relocate_one (&data->rel, rel, addr_64 ? 8 : 4,
+         relocate_one (file, &sec->rel, rel, addr_64 ? 8 : 4,
                        &end_addr, &where, rel_value, &end_symbol);
          if (begin_addr != escape)
            {
@@ -4571,8 +4248,7 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
                wr_message (cat | mc_impact_2 | mc_reloc, &where,
                            ": end of address range is relocated, but the beginning wasn't.\n");
              else
-               check_range_relocations (cat, &where,
-                                        data->file,
+               check_range_relocations (cat, &where, file,
                                         begin_symbol, end_symbol,
                                         "begin and end address");
            }
@@ -4633,8 +4309,8 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
 
              /* location expression itself */
              uint64_t expr_start = read_ctx_get_offset (&ctx);
-             if (!check_location_expression (&ctx, expr_start, &data->rel,
-                                             len, &where, addr_64))
+             if (!check_location_expression (file, &ctx, expr_start,
+                                             &sec->rel, len, &where, addr_64))
                return false;
              uint64_t expr_end = read_ctx_get_offset (&ctx);
              if (!overlap
@@ -4670,26 +4346,27 @@ check_loc_or_range_ref (const struct read_ctx *parent_ctx,
 }
 
 static bool
-check_loc_or_range_structural (struct section_data *data,
+check_loc_or_range_structural (struct elf_file *file,
+                              struct sec *sec,
                               struct cu *cu_chain,
                               struct cu_coverage *cu_coverage)
 {
-  enum section_id sec = data_get_sec (data)->id;
-  assert (sec == sec_loc || sec == sec_ranges);
+  assert (sec->id == sec_loc || sec->id == sec_ranges);
   assert (cu_chain != NULL);
 
   struct read_ctx ctx;
-  read_ctx_init (&ctx, data->file->dwarf, data->data);
+  read_ctx_init (&ctx, file, sec->data);
 
   bool retval = true;
 
   /* For .debug_ranges, we optionally do ranges vs. ELF sections
      coverage analysis.  */
   struct coverage_map *coverage_map = NULL;
-  if (do_range_coverage && sec == sec_ranges
-      && (coverage_map = coverage_map_alloc_XA (data->file, sec == sec_loc)) == NULL)
+  if (do_range_coverage && sec->id == sec_ranges
+      && (coverage_map
+           = coverage_map_alloc_XA (file, sec->id == sec_loc)) == NULL)
     {
-      wr_error (&WHERE (sec, NULL),
+      wr_error (&WHERE (sec->id, NULL),
                ": couldn't read ELF, skipping coverage analysis.\n");
       retval = false;
     }
@@ -4698,7 +4375,7 @@ check_loc_or_range_structural (struct section_data *data,
   struct coverage coverage;
   WIPE (coverage);
 
-  enum message_category cat = sec == sec_loc ? mc_loc : mc_ranges;
+  enum message_category cat = sec->id == sec_loc ? mc_loc : mc_ranges;
 
   /* Relocation checking in the followings assumes that all the
      references are organized in monotonously increasing order.  That
@@ -4708,7 +4385,7 @@ check_loc_or_range_structural (struct section_data *data,
   for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next)
     {
       struct ref_record *rec
-       = sec == sec_loc ? &cu->loc_refs : &cu->range_refs;
+       = sec->id == sec_loc ? &cu->loc_refs : &cu->range_refs;
       size += rec->size;
     }
   struct ref_cu
@@ -4721,7 +4398,7 @@ check_loc_or_range_structural (struct section_data *data,
   for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next)
     {
       struct ref_record *rec
-       = sec == sec_loc ? &cu->loc_refs : &cu->range_refs;
+       = sec->id == sec_loc ? &cu->loc_refs : &cu->range_refs;
       for (size_t i = 0; i < rec->size; ++i)
        *refptr++ = ((struct ref_cu){.ref = rec->refs[i], .cu = cu});
     }
@@ -4747,16 +4424,16 @@ check_loc_or_range_structural (struct section_data *data,
        {
          if (off == last_off)
            continue;
-         relocation_skip (&data->rel, off,
-                          &WHERE (sec, NULL), skip_unref);
+         relocation_skip (&sec->rel, off,
+                          &WHERE (sec->id, NULL), skip_unref);
        }
 
       /* XXX We pass cu_coverage down for all ranges.  That means all
         ranges get recorded, not only those belonging to CUs.
         Perhaps that's undesirable.  */
-      if (!check_loc_or_range_ref (&ctx, refs[i].cu, data,
+      if (!check_loc_or_range_ref (file, &ctx, refs[i].cu, sec,
                                   &coverage, coverage_map,
-                                  sec == sec_ranges ? cu_coverage : NULL,
+                                  sec->id == sec_ranges ? cu_coverage : NULL,
                                   off, refs[i].cu->address_size == 8,
                                   &refs[i].ref.who, cat))
        retval = false;
@@ -4765,20 +4442,20 @@ check_loc_or_range_structural (struct section_data *data,
 
   if (retval)
     {
-      relocation_skip_rest (data);
+      relocation_skip_rest (sec);
 
       /* We check that all CUs have the same address size when building
         the CU chain.  So just take the address size of the first CU in
         chain.  */
       coverage_find_holes (&coverage, 0, ctx.data->d_size, found_hole,
                           &((struct hole_info)
-                            {sec, cat, cu_chain->address_size,
+                            {sec->id, cat, cu_chain->address_size,
                              ctx.data->d_buf}));
 
       if (coverage_map)
        coverage_map_find_holes (coverage_map, &coverage_map_found_hole,
                                 &(struct coverage_map_hole_info)
-                                {{sec, cat, 0, NULL},
+                                {{sec->id, cat, 0, NULL},
                                   coverage_map->elf});
     }
 
@@ -4813,14 +4490,17 @@ get_rel_or_rela (Elf_Data *data, int ndx,
 }
 
 static bool
-read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
+read_rel (struct elf_file *file,
+         struct sec *sec,
+         Elf_Data *reldata,
+         bool elf_64)
 {
-  assert (secdata->rel.type == SHT_REL
-         || secdata->rel.type == SHT_RELA);
-  bool is_rela = secdata->rel.type == SHT_RELA;
+  assert (sec->rel.type == SHT_REL
+         || sec->rel.type == SHT_RELA);
+  bool is_rela = sec->rel.type == SHT_RELA;
 
   struct read_ctx ctx;
-  read_ctx_init (&ctx, secdata->file->dwarf, secdata->data);
+  read_ctx_init (&ctx, file, sec->data);
 
   size_t entrysize
     = elf_64
@@ -4828,7 +4508,7 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
     : (is_rela ? sizeof (Elf32_Rela) : sizeof (Elf32_Rel));
   size_t count = reldata->d_size / entrysize;
 
-  struct where parent = WHERE_SECDATA (secdata, NULL);
+  struct where parent = WHERE (sec->id, NULL);
   struct where where = WHERE (is_rela ? sec_rela : sec_rel, NULL);
   where.ref = &parent;
 
@@ -4836,12 +4516,12 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
     {
       where_reset_1 (&where, i);
 
-      REALLOC (&secdata->rel, rel);
-      struct relocation *cur = secdata->rel.rel + secdata->rel.size++;
+      REALLOC (&sec->rel, rel);
+      struct relocation *cur = sec->rel.rel + sec->rel.size++;
       WIPE (*cur);
 
       GElf_Rela rela_mem, *rela
-       = get_rel_or_rela (reldata, i, &rela_mem, secdata->rel.type);
+       = get_rel_or_rela (reldata, i, &rela_mem, sec->rel.type);
       if (rela == NULL)
        {
          wr_error (&where, ": couldn't read relocation.\n");
@@ -4864,7 +4544,7 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
 
       where_reset_2 (&where, cur->offset);
 
-      Elf_Type type = ebl_reloc_simple_type (secdata->file->ebl, cur->type);
+      Elf_Type type = ebl_reloc_simple_type (file->ebl, cur->type);
       int width;
 
       switch (type)
@@ -4887,8 +4567,8 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
          {
            char buf[64];
            wr_error (&where, ": 8 or 16-bit relocation type %s.\n",
-                     ebl_reloc_type_name (secdata->file->ebl,
-                                          cur->type, buf, sizeof (buf)));
+                     ebl_reloc_type_name (file->ebl, cur->type,
+                                          buf, sizeof (buf)));
            goto skip;
          }
 
@@ -4897,13 +4577,13 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
            char buf[64];
            wr_error (&where, ": invalid relocation %d (%s).\n",
                      cur->type,
-                     ebl_reloc_type_name (secdata->file->ebl,
-                                          cur->type, buf, sizeof (buf)));
+                     ebl_reloc_type_name (file->ebl, cur->type,
+                                          buf, sizeof (buf)));
            goto skip;
          }
        };
 
-      if (cur->offset + width >= secdata->data->d_size)
+      if (cur->offset + width >= sec->data->d_size)
        {
          wr_error (&where,
                    ": relocation doesn't fall into relocated section.\n");
@@ -4912,13 +4592,13 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
 
       uint64_t value;
       if (width == 4)
-       value = read_4ubyte_unaligned (secdata->file->dwarf,
-                                      secdata->data->d_buf + cur->offset);
+       value = dwarflint_read_4ubyte_unaligned
+         (file, sec->data->d_buf + cur->offset);
       else
        {
          assert (width == 8);
-         value = read_8ubyte_unaligned (secdata->file->dwarf,
-                                        secdata->data->d_buf + cur->offset);
+         value = dwarflint_read_8ubyte_unaligned
+           (file, sec->data->d_buf + cur->offset);
        }
 
       if (is_rela)
@@ -4941,17 +4621,18 @@ read_rel (struct section_data *secdata, Elf_Data *reldata, bool elf_64)
       - ((struct relocation *)b)->offset;
   }
 
-  qsort (secdata->rel.rel, secdata->rel.size,
-        sizeof (*secdata->rel.rel), &compare);
+  qsort (sec->rel.rel, sec->rel.size,
+        sizeof (*sec->rel.rel), &compare);
   return true;
 }
 
 static bool
-check_line_structural (struct section_data *data,
+check_line_structural (struct elf_file *file,
+                      struct sec *sec,
                       struct cu *cu_chain)
 {
   struct read_ctx ctx;
-  read_ctx_init (&ctx, data->file->dwarf, data->data);
+  read_ctx_init (&ctx, file, sec->data);
   bool retval = true;
 
   struct addr_record line_tables;
@@ -4959,7 +4640,7 @@ check_line_structural (struct section_data *data,
 
   while (!read_ctx_eof (&ctx))
     {
-      struct where where = WHERE_SECDATA (data, NULL);
+      struct where where = WHERE (sec->id, NULL);
       uint64_t set_offset = read_ctx_get_offset (&ctx);
       where_reset_1 (&where, set_offset);
       addr_record_add (&line_tables, set_offset);
@@ -5253,18 +4934,20 @@ check_line_structural (struct section_data *data,
                    {
                      uint64_t ctx_offset = read_ctx_get_offset (&sub_ctx);
                      uint64_t addr;
-                     if (!read_ctx_read_offset (&sub_ctx, data->file->addr_64, &addr))
+                     if (!read_ctx_read_offset (&sub_ctx,
+                                                file->addr_64, &addr))
                        {
                          wr_error (&where, ": can't read operand of DW_LNE_set_address.\n");
                          goto skip;
                        }
 
                      struct relocation *rel;
-                     if ((rel = relocation_next (&data->rel, ctx_offset,
+                     if ((rel = relocation_next (&sec->rel, ctx_offset,
                                                  &where, skip_mismatched)))
-                       relocate_one (&data->rel, rel, data->file->addr_64 ? 8 : 4,
+                       relocate_one (file, &sec->rel, rel,
+                                     file->addr_64 ? 8 : 4,
                                      &addr, &where, rel_address, NULL);
-                     else if (data->file->ehdr.e_type == ET_REL)
+                     else if (file->ehdr.e_type == ET_REL)
                        wr_message (mc_impact_2 | mc_line | mc_reloc, &where,
                                    PRI_LACK_RELOCATION, "DW_LNE_set_address");
                      break;
@@ -5436,7 +5119,7 @@ check_line_structural (struct section_data *data,
 
   if (retval)
     {
-      relocation_skip_rest (data);
+      relocation_skip_rest (sec);
 
       for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next)
        for (size_t i = 0; i < cu->line_refs.size; ++i)
index d31055a1e7af866a33b2e5c8ac9f3fabc04528a8..9ecc4f71d5f9d8e5874bd6438651b51061259d19 100644 (file)
@@ -16,7 +16,7 @@ extern "C"
   struct hl_ctx;
 
   /* Check that .debug_aranges and .debug_ranges match.  */
-  extern struct hl_ctx *hl_ctx_new (Dwarf *dwarf);
+  extern struct hl_ctx *hl_ctx_new (Elf *elf);
   extern void hl_ctx_delete (struct hl_ctx *hlctx);
   extern bool check_matching_ranges (struct hl_ctx *hlctx);
   extern bool check_expected_trees (struct hl_ctx *hlctx);
@@ -24,31 +24,40 @@ extern "C"
 
   /* Functions and data structures describing location in Dwarf.  */
 
-  enum section_id
+#define DEBUGINFO_SECTIONS \
+  SEC (info)              \
+  SEC (abbrev)            \
+  SEC (aranges)                   \
+  SEC (pubnames)          \
+  SEC (pubtypes)          \
+  SEC (str)               \
+  SEC (line)              \
+  SEC (loc)               \
+  SEC (mac)               \
+  SEC (ranges)
+
+    enum section_id
   {
     sec_invalid = 0,
+
+    /* Debuginfo sections:  */
+#define SEC(n) sec_##n,
+    DEBUGINFO_SECTIONS
+    count_debuginfo_sections,
+#undef SEC
+
+    /* Non-debuginfo sections:  */
+    sec_rel = count_debuginfo_sections,
+    sec_rela,
+
+    /* Non-sections:  */
+    sec_locexpr,       /* Not a section, but a portion of file that
+                          contains a location expression.  */
     rel_value,         /* For relocations, this denotes that the
                           relocation is applied to taget value, not a
                           section offset.  */
     rel_address,       /* Same as above, but for addresses.  */
     rel_exec,          /* Some as above, but we expect EXEC bit.  */
-
-    /* Debuginfo sections:  */
-    sec_info,
-    sec_abbrev,
-    sec_aranges,
-    sec_pubnames,
-    sec_pubtypes,
-    sec_str,
-    sec_line,
-    sec_loc,
-    sec_mac,
-    sec_ranges,
-    sec_locexpr,       /* Not a section, but a portion of file that
-                          contains a location expression.  */
-    /* Non-debuginfo sections:  */
-    sec_rel,
-    sec_rela,
   };
 
   enum where_formatting
@@ -156,24 +165,59 @@ extern "C"
 
   extern char *range_fmt (char *buf, size_t buf_size, uint64_t start, uint64_t end);
 
+  struct relocation
+  {
+    uint64_t offset;
+    uint64_t addend;
+    int symndx;
+    int type;
+    bool invalid;              /* Whether this one relocation should be
+                                  ignored.  Necessary so that we don't
+                                  double-report invalid & missing
+                                  relocation.  */
+  };
+
+  struct relocation_data
+  {
+    Elf_Data *symdata;         /* Symbol table associated with this
+                                  relocation section.  */
+    size_t type;               /* SHT_REL or SHT_RELA.  */
+
+    struct relocation *rel;    /* Array of relocations.  May be NULL
+                                  if there are no associated
+                                  relocation data.  */
+    size_t size;
+    size_t alloc;
+    size_t index;              /* Current index. */
+  };
+
   struct sec
   {
     Elf_Scn *scn;
     GElf_Shdr shdr;
     enum section_id id;
     const char *name;
+
+    Elf_Data *data;    /* May be NULL if data in this section are
+                          missing or not substantial.  */
+    struct relocation_data rel;
   };
 
   struct elf_file
   {
-    Dwarf *dwarf;
+    Elf *elf;
     Ebl *ebl;
-    GElf_Ehdr ehdr;    /* Header of dwarf->elf.  */
-    bool addr_64;
+    GElf_Ehdr ehdr;    /* Header of underlying Elf.  */
+    bool addr_64;      /* True if it's 64-bit Elf.  */
+    bool other_byte_order; /* True if the file has a byte order
+                             different from the host.  */
 
     struct sec *sec;   /* Array of sections.  */
     size_t size;
     size_t alloc;
+
+    /* Pointers into SEC above.  Maps section_id to section.  */
+    struct sec *debugsec[count_debuginfo_sections];
   };
 
   struct section_coverage