]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Separate loading of CU header from validation of CU body
authorPetr Machata <pmachata@redhat.com>
Fri, 20 Nov 2009 19:33:51 +0000 (20:33 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:13 +0000 (14:55 +0200)
* A temporary solution, single-file only

src/dwarflint/check_debug_info.cc
src/dwarflint/low.c
src/dwarflint/low.h
src/dwarflint/reloc.cc
src/dwarflint/reloc.h

index 41f41f50c2d57bfa5d87c52fe620354d3a21b41e..2870d7444e1ef6e4a191c2a64c139d856ace9263 100644 (file)
@@ -39,6 +39,7 @@
 #include "low.h"
 #include "checks-low.hh"
 #include "pri.hh"
+#include "config.h"
 
 namespace
 {
@@ -48,6 +49,24 @@ namespace
     return message_accept (&warning_criteria, cat);
   }
 
+  bool
+  check_die_references (struct cu *cu,
+                       struct ref_record *die_refs)
+  {
+    bool retval = true;
+    for (size_t i = 0; i < die_refs->size; ++i)
+      {
+       struct ref *ref = die_refs->refs + i;
+       if (!addr_record_has_addr (&cu->die_addrs, ref->addr))
+         {
+           wr_error (&ref->who,
+                     ": unresolved reference to " PRI_DIE ".\n", ref->addr);
+           retval = false;
+         }
+      }
+    return retval;
+  }
+
   bool
   check_global_die_references (struct cu *cu_chain)
   {
@@ -87,7 +106,8 @@ namespace
 
   std::vector <cu_head>
   read_info_headers (struct elf_file *file,
-                    struct sec *sec)
+                    struct sec *sec,
+                    struct relocation_data *reloc)
   {
     struct read_ctx ctx;
     read_ctx_init (&ctx, sec->data, file->other_byte_order);
@@ -95,6 +115,8 @@ namespace
     std::vector <cu_head> ret;
     while (!read_ctx_eof (&ctx))
       {
+       std::cout << "head " << read_ctx_get_offset (&ctx)
+                 << ' ' << pri::hex (read_ctx_get_offset (&ctx)) << std::endl;
        const unsigned char *cu_begin = ctx.ptr;
        struct where where = WHERE (sec_info, NULL);
        where_reset_1 (&where, read_ctx_get_offset (&ctx));
@@ -110,7 +132,11 @@ namespace
            && check_zero_padding (&ctx, cat (mc_info, mc_header), &where))
          break;
 
-       /* CU length.  */
+       /* CU length.  In DWARF 2, (uint32_t)-1 is simply a CU of that
+          length.  In DWARF 3+ that's an escape for 64bit length.
+          Unfortunately to read CU version, we have to get through
+          this field.  So we just assume that (uint32_t)-1 is an
+          escape in all cases.  */
        uint32_t size32;
        if (!read_ctx_read_4ubyte (&ctx, &size32))
          {
@@ -121,31 +147,72 @@ namespace
            && check_zero_padding (&ctx, cat (mc_info, mc_header), &where))
          break;
 
-       if (!read_size_extra (&ctx, size32, &head.size,
+       Dwarf_Off cu_size;
+       if (!read_size_extra (&ctx, size32, &cu_size,
                              &head.offset_size, &where))
          throw check_base::failed ();
 
-       if (!read_ctx_need_data (&ctx, head.size))
+       if (!read_ctx_need_data (&ctx, cu_size))
          {
            wr_error (where)
              << "section doesn't have enough data to read CU of size "
-             << head.size << '.' << std::endl;
+             << cu_size << '.' << std::endl;
            throw check_base::failed ();
          }
 
-       /* version + debug_abbrev_offset + address_size */
-       Dwarf_Off cu_head_size = 2 + head.offset_size + 1;
-       if (head.size < cu_head_size)
+       /* CU size captures the size from the end of the length field
+          to the end of the CU.  */
+       const unsigned char *cu_end = ctx.ptr + cu_size;
+
+       /* Version.  */
+       uint16_t version;
+       if (!read_ctx_read_2ubyte (&ctx, &version))
          {
-           wr_error (where)
-             << "claimed length of " << head.size
-             << " doesn't even cover CU head." << std::endl;
+           wr_error (head.where) << "can't read version." << std::endl;
+           throw check_base::failed ();
+         }
+       if (get_dwarf_version (version) == NULL)
+         {
+           wr_error (head.where) << "unsupported CU version "
+                                 << version << '.' << std::endl;
            throw check_base::failed ();
          }
+       if (version == 2 && head.offset_size == 8) // xxx?
+         /* Keep going.  It's a standard violation, but we may still
+            be able to read the unit under consideration and do
+            high-level checks.  */
+         wr_error (head.where) << "invalid 64-bit unit in DWARF 2 format.\n";
+       head.version = version;
+
+       /* Abbrev offset.  */
+       uint64_t ctx_offset = read_ctx_get_offset (&ctx) + head.offset;
+       if (!read_ctx_read_offset (&ctx, head.offset_size == 8,
+                                  &head.abbrev_offset))
+         {
+           wr_error (head.where) << "can't read abbrev offset." << std::endl;
+           throw check_base::failed ();
+         }
+
+       struct relocation *rel
+         = relocation_next (reloc, ctx_offset, &head.where, skip_ok);
+       if (rel != NULL)
+         {
+           relocate_one (file, reloc, rel, head.offset_size,
+                         &head.abbrev_offset, &head.where, sec_abbrev, NULL);
+           rel->invalid = true; // mark as invalid so it's skipped
+                                // next time we pass by this
+         }
+       else if (file->ehdr.e_type == ET_REL)
+         wr_message (head.where, cat (mc_impact_2, mc_info, mc_reloc))
+           << pri::lacks_relocation ("abbrev offset") << std::endl;
+
+       /* Address size.  */
+       if (!read_address_size (file, &ctx, &head.address_size, &head.where))
+         throw check_base::failed ();
 
-       const unsigned char *cu_end = ctx.ptr + head.size;
-       head.head_size = ctx.ptr - cu_begin; // Length of the head itself.
-       head.total_size = cu_end - cu_begin; // Length including the length field.
+       head.head_size = ctx.ptr - cu_begin; // Length of the headers itself.
+       head.total_size = cu_end - cu_begin; // Length including headers field.
+       head.size = head.total_size - head.head_size;
 
        if (!read_ctx_skip (&ctx, head.size))
          {
@@ -159,6 +226,59 @@ namespace
     return ret;
   }
 
+  bool
+  check_cu_structural (struct elf_file *file,
+                      struct read_ctx *ctx,
+                      struct cu *const cu,
+                      struct abbrev_table *abbrev_chain,
+                      Elf_Data *strings,
+                      struct coverage *strings_coverage,
+                      struct relocation_data *reloc,
+                      struct cu_coverage *cu_coverage)
+  {
+    if (dump_die_offsets)
+      fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
+    bool retval = true;
+
+    dwarf_version_h ver = get_dwarf_version (cu->head->version);
+    assert (ver != NULL);
+
+    /* Look up Abbrev table for this CU.  */
+    struct abbrev_table *abbrevs = abbrev_chain;
+    for (; abbrevs != NULL; abbrevs = abbrevs->next)
+      if (abbrevs->offset == cu->head->abbrev_offset)
+       break;
+
+    if (abbrevs == NULL)
+      {
+       wr_error (&cu->head->where,
+                 ": couldn't find abbrev section with offset %" PRId64 ".\n",
+                 cu->head->abbrev_offset);
+       return false;
+      }
+
+    abbrevs->used = true;
+
+    /* Read DIEs.  */
+    struct ref_record local_die_refs;
+    WIPE (local_die_refs);
+
+    cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset;
+    if (read_die_chain (ver, file, ctx, cu, abbrevs, strings,
+                       &local_die_refs, strings_coverage,
+                       (reloc != NULL && reloc->size > 0) ? reloc : NULL,
+                       cu_coverage) < 0)
+      {
+       abbrevs->skip_check = true;
+       retval = false;
+      }
+    else if (!check_die_references (cu, &local_die_refs))
+      retval = false;
+
+    ref_record_free (&local_die_refs);
+    return retval;
+  }
+
   struct cu *
   check_info_structural (struct elf_file *file,
                         struct sec *sec,
@@ -180,14 +300,18 @@ namespace
       }
 
     struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
+    // xxx temporary static xxx
+    static std::vector <cu_head> cu_headers = read_info_headers (file, sec, reloc);
+    if (reloc != NULL)
+      relocation_reset (reloc);
 
-    std::vector <cu_head> cu_headers = read_info_headers (file, sec);
     struct read_ctx ctx;
     read_ctx_init (&ctx, sec->data, file->other_byte_order);
     for (std::vector <cu_head>::const_iterator it = cu_headers.begin ();
         it != cu_headers.end (); ++it)
       {
        cu_head const &head = *it;
+       std::cout << "read " << pri::hex (head.offset) << std::endl;
        where const &where = head.where;
        struct cu *cur = (cu *)xcalloc (1, sizeof (*cur));
        cur->head = &head;
index 3e3dbc68814a8ca45165119924b740b20ba0198a..b20358725d25ea0496cbcefc775412f33b322fe5 100644 (file)
@@ -119,13 +119,13 @@ checked_read_sleb128 (struct read_ctx *ctx, int64_t *ret,
    type-casted int64_t.  WHAT and WHERE describe error message and
    context for LEB128 loading.  */
 static bool
-read_ctx_read_form (struct read_ctx *ctx, struct cu *cu, uint8_t form,
+read_ctx_read_form (struct read_ctx *ctx, int address_size, uint8_t form,
                    uint64_t *valuep, struct where *where, const char *what)
 {
   switch (form)
     {
     case DW_FORM_addr:
-      return read_ctx_read_offset (ctx, cu->address_size == 8, valuep);
+      return read_ctx_read_offset (ctx, address_size == 8, valuep);
     case DW_FORM_udata:
       return checked_read_uleb128 (ctx, valuep, where, what);
     case DW_FORM_sdata:
@@ -479,25 +479,6 @@ cu_find_cu (struct cu *cu_chain, uint64_t offset)
   return NULL;
 }
 
-
-static bool
-check_die_references (struct cu *cu,
-                     struct ref_record *die_refs)
-{
-  bool retval = true;
-  for (size_t i = 0; i < die_refs->size; ++i)
-    {
-      struct ref *ref = die_refs->refs + i;
-      if (!addr_record_has_addr (&cu->die_addrs, ref->addr))
-       {
-         wr_error (&ref->who,
-                   ": unresolved reference to " PRI_DIE ".\n", ref->addr);
-         retval = false;
-       }
-    }
-  return retval;
-}
-
 bool
 read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep,
                 int *offset_sizep, struct where *wh)
@@ -708,7 +689,7 @@ check_range_relocations (enum message_category cat,
        terminating zero die.
     +1 in case some dies were actually loaded
  */
-static int
+int
 read_die_chain (dwarf_version_h ver,
                struct elf_file *file,
                struct read_ctx *ctx,
@@ -909,7 +890,7 @@ read_die_chain (dwarf_version_h ver,
          /* Callback for rangeptr values.  */
          void check_rangeptr (uint64_t value, struct where *who)
          {
-           if ((value % cu->address_size) != 0)
+           if ((value % cu->head->address_size) != 0)
              wr_message (mc_ranges | mc_impact_2, who,
                          ": rangeptr value %#" PRIx64
                          " not aligned to CU address size.\n", value);
@@ -1071,9 +1052,9 @@ read_die_chain (dwarf_version_h ver,
              value_check_cb = check_die_ref_global;
              width = cu->head->offset_size;
 
-             if (cu->version == 2)
+             if (cu->head->version == 2)
            case DW_FORM_addr:
-               width = cu->address_size;
+               width = cu->head->address_size;
 
              if (!read_ctx_read_offset (ctx, width == 8, &value))
                goto cant_read;
@@ -1297,10 +1278,10 @@ read_die_chain (dwarf_version_h ver,
   return got_die ? 1 : 0;
 }
 
-static bool
-read_address_size (struct elf_file *file,
+bool
+read_address_size (bool elf_64,
                   struct read_ctx *ctx,
-                  uint8_t *address_sizep,
+                  int *address_sizep,
                   struct where const *where)
 {
   uint8_t address_size;
@@ -1317,111 +1298,18 @@ read_address_size (struct elf_file *file,
       wr_error (where,
                ": invalid address size: %d (only 4 or 8 allowed).\n",
                address_size);
-      address_size = file->addr_64 ? 8 : 4;
+      address_size = elf_64 ? 8 : 4;
     }
-  else if ((address_size == 8) != file->addr_64)
+  else if ((address_size == 8) != elf_64)
     /* Keep going, we may still be able to parse it.  */
     wr_error (where,
              ": CU reports address size of %d in %d-bit ELF.\n",
-             address_size, file->addr_64 ? 64 : 32);
+             address_size, elf_64 ? 64 : 32);
 
   *address_sizep = address_size;
   return true;
 }
 
-bool
-check_cu_structural (struct elf_file *file,
-                    struct read_ctx *ctx,
-                    struct cu *const cu,
-                    struct abbrev_table *abbrev_chain,
-                    Elf_Data *strings,
-                    struct coverage *strings_coverage,
-                    struct relocation_data *reloc,
-                    struct cu_coverage *cu_coverage)
-{
-  if (dump_die_offsets)
-    fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
-  bool retval = true;
-
-  /* Version.  */
-  uint16_t version;
-  if (!read_ctx_read_2ubyte (ctx, &version))
-    {
-      wr_error (&cu->head->where, ": can't read version.\n");
-      return false;
-    }
-  dwarf_version_h ver = get_dwarf_version (version);
-  if (ver == NULL)
-    return false;
-  if (version == 2 && cu->head->offset_size == 8) // xxx?
-    /* Keep going.  It's a standard violation, but we may still be
-       able to read the unit under consideration and do high-level
-       checks.  */
-    wr_error (&cu->head->where, ": invalid 64-bit unit in DWARF 2 format.\n");
-  cu->version = version;
-
-  /* Abbrev offset.  */
-  uint64_t abbrev_offset;
-  uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->head->offset;
-  if (!read_ctx_read_offset (ctx, cu->head->offset_size == 8, &abbrev_offset))
-    {
-      wr_error (&cu->head->where, ": can't read abbrev offset.\n");
-      return false;
-    }
-
-  struct relocation *rel
-    = relocation_next (reloc, ctx_offset, &cu->head->where, skip_mismatched);
-  if (rel != NULL)
-    relocate_one (file, reloc, rel, cu->head->offset_size,
-                 &abbrev_offset, &cu->head->where, sec_abbrev, NULL);
-  else if (file->ehdr.e_type == ET_REL)
-    wr_message (mc_impact_2 | mc_info | mc_reloc, &cu->head->where,
-               PRI_LACK_RELOCATION, "abbrev offset");
-
-  /* Address size.  */
-  {
-    uint8_t address_size;
-    if (!read_address_size (file, ctx, &address_size, &cu->head->where))
-      return false;
-    cu->address_size = address_size;
-  }
-
-  /* Look up Abbrev table for this CU.  */
-  struct abbrev_table *abbrevs = abbrev_chain;
-  for (; abbrevs != NULL; abbrevs = abbrevs->next)
-    if (abbrevs->offset == abbrev_offset)
-      break;
-
-  if (abbrevs == NULL)
-    {
-      wr_error (&cu->head->where,
-               ": couldn't find abbrev section with offset %" PRId64 ".\n",
-               abbrev_offset);
-      return false;
-    }
-
-  abbrevs->used = true;
-
-  /* Read DIEs.  */
-  struct ref_record local_die_refs;
-  WIPE (local_die_refs);
-
-  cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset;
-  if (read_die_chain (ver, file, ctx, cu, abbrevs, strings,
-                     &local_die_refs, strings_coverage,
-                     (reloc != NULL && reloc->size > 0) ? reloc : NULL,
-                     cu_coverage) < 0)
-    {
-      abbrevs->skip_check = true;
-      retval = false;
-    }
-  else if (!check_die_references (cu, &local_die_refs))
-    retval = false;
-
-  ref_record_free (&local_die_refs);
-  return retval;
-}
-
 static struct coverage_map *
 coverage_map_alloc_XA (struct elf_file *elf, bool allow_overlap)
 {
@@ -1607,7 +1495,7 @@ check_aranges_structural (struct elf_file *file,
        }
 
       /* Address size.  */
-      uint8_t address_size;
+      int address_size;
       if (!read_address_size (file, &sub_ctx, &address_size, &where))
        {
          retval = false;
@@ -1983,7 +1871,7 @@ check_location_expression (struct elf_file *file,
          {                                                             \
            uint64_t _off = read_ctx_get_offset (&ctx) + init_off;      \
            uint64_t *_ptr = (PTR);                                     \
-           if (!read_ctx_read_form (&ctx, cu, (OP),                    \
+           if (!read_ctx_read_form (&ctx, cu->head->address_size, (OP), \
                                     _ptr, &where, STR " operand"))     \
              {                                                         \
                wr_error (&where, ": opcode \"%s\""                     \
@@ -1996,7 +1884,7 @@ check_location_expression (struct elf_file *file,
            if ((_rel = relocation_next (reloc, _off,                   \
                                         &where, skip_mismatched)))     \
              relocate_one (file, reloc, _rel,                          \
-                           cu->address_size, _ptr, &where,             \
+                           cu->head->address_size, _ptr, &where,               \
                            reloc_target_loc (opcode), NULL);           \
          }                                                             \
       } while (0)
@@ -2033,13 +1921,13 @@ check_location_expression (struct elf_file *file,
 
        case DW_OP_const8u:
        case DW_OP_const8s:
-         if (cu->address_size == 4)
+         if (cu->head->address_size == 4)
            wr_error (&where, ": %s on 32-bit machine.\n",
                      dwarf_locexpr_opcode_string (opcode));
          break;
 
        default:
-         if (cu->address_size == 4
+         if (cu->head->address_size == 4
              && (opcode == DW_OP_constu
                  || opcode == DW_OP_consts
                  || opcode == DW_OP_deref_size
@@ -2106,7 +1994,7 @@ check_loc_or_range_ref (struct elf_file *file,
       retval = false;
     }
 
-  uint64_t escape = cu->address_size == 8
+  uint64_t escape = cu->head->address_size == 8
     ? (uint64_t)-1 : (uint64_t)(uint32_t)-1;
 
   bool overlap = false;
@@ -2129,10 +2017,10 @@ check_loc_or_range_ref (struct elf_file *file,
       GElf_Sym begin_symbol_mem, *begin_symbol = &begin_symbol_mem;
       bool begin_relocated = false;
       if (!overlap
-         && coverage_is_overlap (coverage, begin_off, cu->address_size))
+         && coverage_is_overlap (coverage, begin_off, cu->head->address_size))
        HAVE_OVERLAP;
 
-      if (!read_ctx_read_offset (&ctx, cu->address_size == 8, &begin_addr))
+      if (!read_ctx_read_offset (&ctx, cu->head->address_size == 8, &begin_addr))
        {
          wr_error (&where, ": can't read address range beginning.\n");
          return false;
@@ -2143,7 +2031,7 @@ check_loc_or_range_ref (struct elf_file *file,
                                  &where, skip_mismatched)))
        {
          begin_relocated = true;
-         relocate_one (file, &sec->rel, rel, cu->address_size,
+         relocate_one (file, &sec->rel, rel, cu->head->address_size,
                        &begin_addr, &where, rel_value, &begin_symbol);
        }
 
@@ -2153,10 +2041,10 @@ check_loc_or_range_ref (struct elf_file *file,
       GElf_Sym end_symbol_mem, *end_symbol = &end_symbol_mem;
       bool end_relocated = false;
       if (!overlap
-         && coverage_is_overlap (coverage, end_off, cu->address_size))
+         && coverage_is_overlap (coverage, end_off, cu->head->address_size))
        HAVE_OVERLAP;
 
-      if (!read_ctx_read_offset (&ctx, cu->address_size == 8, &end_addr))
+      if (!read_ctx_read_offset (&ctx, cu->head->address_size == 8, &end_addr))
        {
          wr_error (&where, ": can't read address range ending.\n");
          return false;
@@ -2166,7 +2054,7 @@ check_loc_or_range_ref (struct elf_file *file,
                                  &where, skip_mismatched)))
        {
          end_relocated = true;
-         relocate_one (file, &sec->rel, rel, cu->address_size,
+         relocate_one (file, &sec->rel, rel, cu->head->address_size,
                        &end_addr, &where, rel_value, &end_symbol);
          if (begin_addr != escape)
            {
@@ -2375,7 +2263,7 @@ check_loc_or_range_structural (struct elf_file *file,
       coverage_find_holes (&coverage, 0, ctx.data->d_size, found_hole,
                           &((struct hole_info)
                             {sec->id, cat, ctx.data->d_buf,
-                             cu_chain->address_size}));
+                             cu_chain->head->address_size}));
 
       if (coverage_map)
        coverage_map_find_holes (coverage_map, &coverage_map_found_hole,
index 795f34260e7f8769ebd32a7b89d42ea81f3fc58c..d6308c1c8d3b5df7104f1a9f9ce540cf73dd2101 100644 (file)
@@ -111,6 +111,10 @@ extern "C"
   extern bool check_zero_padding (struct read_ctx *ctx,
                                  enum message_category category,
                                  struct where const *wh);
+  extern bool read_address_size (bool elf_64,
+                                struct read_ctx *ctx,
+                                int *address_sizep,
+                                struct where const *where);
 
   struct section_coverage
   {
@@ -142,14 +146,16 @@ extern "C"
 
   // xxx low-level check entry points, will go away
   struct cu;
-  extern bool check_cu_structural (struct elf_file *file,
-                                  struct read_ctx *ctx,
-                                  struct cu *const cu,
-                                  struct abbrev_table *abbrev_chain,
-                                  Elf_Data *strings,
-                                  struct coverage *strings_coverage,
-                                  struct relocation_data *reloc,
-                                  struct cu_coverage *cu_coverage);
+  extern int read_die_chain (dwarf_version_h ver,
+                            struct elf_file *file,
+                            struct read_ctx *ctx,
+                            struct cu *cu,
+                            struct abbrev_table *abbrevs,
+                            Elf_Data *strings,
+                            struct ref_record *local_die_refs,
+                            struct coverage *strings_coverage,
+                            struct relocation_data *reloc,
+                            struct cu_coverage *cu_coverage);
   extern bool check_loc_or_range_structural (struct elf_file *file,
                                             struct sec *sec,
                                             struct cu *cu_chain,
@@ -231,6 +237,8 @@ extern "C"
     int offset_size;             // Offset size in this CU.
     struct where where;           // Where was this section defined.
     Dwarf_Off abbrev_offset;      // Abbreviation section that this CU uses.
+    int version;                  // CU version
+    int address_size;             // Address size in bytes on the target machine.
   };
 
   struct cu
@@ -245,8 +253,6 @@ extern "C"
     struct ref_record loc_refs;   // references into .debug_loc from this CU.
     struct ref_record range_refs; // references into .debug_ranges from this CU.
     struct ref_record line_refs;  // references into .debug_line from this CU.
-    int address_size;             // Address size in bytes on the target machine.
-    int version;                  // CU version
     bool has_arange;              // Whether we saw arange section pointing to this CU.
     bool has_pubnames;            // Likewise for pubnames.
     bool has_pubtypes;            // Likewise for pubtypes.
index c3ea6e2ccbe7287f12dfb7edd70c9e9386d331a2..c49a150ce4c9e8258b0b5759e5f11e2e3f58b562 100644 (file)
@@ -67,6 +67,13 @@ relocation_skip (struct relocation_data *reloc, uint64_t offset,
     relocation_next (reloc, offset - 1, where, st);
 }
 
+void
+relocation_reset (struct relocation_data *reloc)
+{
+  if (reloc != NULL)
+    reloc->index = 0;
+}
+
 /* Skip all the remaining relocations.  */
 void
 relocation_skip_rest (struct relocation_data *reloc,
index d3a90748a3bc0e5aa5155b2f29db7498f0937c61..ae5f8292fd87c0bff63b4ff7bca48c37028df617 100644 (file)
@@ -76,6 +76,8 @@ extern "C"
                                      struct where const *where,
                                      enum skip_type st);
 
+  void relocation_reset (struct relocation_data *reloc);
+
   void relocation_skip (struct relocation_data *reloc, uint64_t offset,
                        struct where const *where, enum skip_type st);