]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Validate .debug_ranges
authorPetr Machata <pmachata@redhat.com>
Tue, 27 Jan 2009 22:14:37 +0000 (23:14 +0100)
committerPetr Machata <pmachata@redhat.com>
Tue, 27 Jan 2009 22:14:37 +0000 (23:14 +0100)
src/ChangeLog
src/dwarflint.c

index a30c83114dcf8fc1b385f170d456d9c0a3a7e455..7161957258aced01adc33fc04c6e472a43a7f348 100644 (file)
@@ -1,3 +1,8 @@
+2009-01-27  Petr Machata  <pmachata@redhat.com>
+
+       * dwarflint.c: Implement validation of .debug_ranges and
+       references from .debug_info to .debug_ranges.
+
 2009-01-27  Petr Machata  <pmachata@redhat.com>
 
        * dwarflint.c: Check that the base address selection entry
index dc71805198a33bb882c38d0b09909997880ba9a1..8bade4df7c2e8411ce8cd9b25ac81e984962fd5e 100644 (file)
@@ -190,7 +190,7 @@ accept_message (struct message_criteria *crit, enum message_category cat)
 }
 
 static struct message_criteria warning_criteria
-  = {mc_all & ~(mc_strings | mc_loc),
+  = {mc_all & ~(mc_strings | mc_loc | mc_ranges),
      mc_pubtypes};
 static struct message_criteria error_criteria
   = {mc_impact_4 | mc_error,
@@ -620,17 +620,21 @@ static struct cu *cu_find_cu (struct cu *cu_chain, uint64_t offset);
 static struct cu *check_debug_info_structural (struct read_ctx *ctx,
                                               struct abbrev_table *abbrev_chain,
                                               Elf_Data *strings,
-                                              Elf_Data *loc);
+                                              Elf_Data *loc,
+                                              Elf_Data *ranges);
 static bool check_cu_structural (struct read_ctx *ctx,
                                 struct cu *const cu,
                                 struct abbrev_table *abbrev_chain,
                                 Elf_Data *strings,
                                 Elf_Data *loc,
+                                Elf_Data *ranges,
                                 bool dwarf_64,
                                 struct ref_record *die_refs,
                                 struct addr_record *loc_addrs,
+                                struct addr_record *ranges_addrs,
                                 struct coverage *strings_coverage,
-                                struct coverage *loc_coverage);
+                                struct coverage *loc_coverage,
+                                struct coverage *ranges_coverage);
 static bool check_aranges_structural (struct read_ctx *ctx,
                                      struct cu *cu_chain);
 static bool check_pub_structural (struct read_ctx *ctx,
@@ -788,6 +792,7 @@ process_file (int fd __attribute__((unused)),
   Elf_Data *aranges_data = dwarf->sectiondata[IDX_debug_aranges];
   Elf_Data *pubnames_data = dwarf->sectiondata[IDX_debug_pubnames];
   Elf_Data *loc_data = dwarf->sectiondata[IDX_debug_loc];
+  Elf_Data *ranges_data = dwarf->sectiondata[IDX_debug_ranges];
 
   /* Obtaining pubtypes is a bit complicated, because GNU toolchain
      doesn't emit it, and libdw doesn't account for it.  */
@@ -841,7 +846,8 @@ process_file (int fd __attribute__((unused)),
        {
          read_ctx_init (&ctx, dwarf, info_data);
          cu_chain = check_debug_info_structural (&ctx, abbrev_chain,
-                                                 str_data, loc_data);
+                                                 str_data, loc_data,
+                                                 ranges_data);
        }
       else if (!tolerate_nodebug)
        /* Hard error, not a message.  We can't debug without this.  */
@@ -1209,37 +1215,6 @@ check_abbrev_location_form (uint64_t form)
     };
 }
 
-/* Check that given form is in fact valid in concrete CU.  Return 0 if
-   it's absolutely invalid, -1 if it's invalid in the given context, 1
-   if it's valid loclistptr, 2 if it's valid block.  */
-static int
-check_CU_location_form (uint64_t form, bool dwarf_64)
-{
-  switch (form)
-    {
-      /* loclistptr */
-    case DW_FORM_data4:
-      if (dwarf_64)
-       return -1;
-      return 1;
-
-    case DW_FORM_data8:
-      if (!dwarf_64)
-       return -1;
-      return 1;
-
-      /* block */
-    case DW_FORM_block1:
-    case DW_FORM_block2:
-    case DW_FORM_block4:
-    case DW_FORM_block:
-      return 2;
-
-    default:
-      return 0;
-    };
-}
-
 static bool
 is_location_attrib (uint64_t name)
 {
@@ -1436,7 +1411,7 @@ abbrev_table_load (struct read_ctx *ctx)
                            dwarf_form_string (attrib_form));
                };
            }
-         /* Similar for DW_AT_location.  */
+         /* Similar for DW_AT_location and friends.  */
          else if (is_location_attrib (attrib_name))
            {
              if (!check_abbrev_location_form (attrib_form))
@@ -1444,6 +1419,16 @@ abbrev_table_load (struct read_ctx *ctx)
                          ": location attribute with invalid form \"%s\".\n",
                          dwarf_form_string (attrib_form));
            }
+         /* Similar for DW_AT_ranges.  */
+         else if (attrib_name == DW_AT_ranges)
+           {
+             if (attrib_form != DW_FORM_data4
+                 && attrib_form != DW_FORM_data8
+                 && attrib_form != DW_FORM_indirect)
+               wr_error (&where,
+                         ": DW_AT_ranges with invalid form \"%s\".\n",
+                         dwarf_form_string (attrib_form));
+           }
 
          acur->name = attrib_name;
          acur->form = attrib_form;
@@ -1844,19 +1829,12 @@ wr_check_zero_padding (struct read_ctx *ctx,
   return true;
 }
 
-static bool
-check_x_location_expression (struct read_ctx *ctx,
-                            struct cu *cu,
-                            struct coverage *loc_coverage,
-                            struct addr_record *loc_addrs,
-                            uint64_t addr, bool addr_64,
-                            struct where *wh);
-
 static struct cu *
 check_debug_info_structural (struct read_ctx *ctx,
                             struct abbrev_table *abbrev_chain,
                             Elf_Data *strings,
-                            Elf_Data *loc)
+                            Elf_Data *loc,
+                            Elf_Data *ranges)
 {
   struct ref_record die_refs;
   memset (&die_refs, 0, sizeof (die_refs));
@@ -1874,7 +1852,7 @@ check_debug_info_structural (struct read_ctx *ctx,
 
   struct coverage loc_coverage_mem, *loc_coverage = NULL;
   struct addr_record loc_addrs_mem, *loc_addrs = NULL;
-  if (loc != NULL && check_category (mc_loc))
+  if (loc != NULL)
     {
       coverage_init (&loc_coverage_mem, loc->d_size);
       loc_coverage = &loc_coverage_mem;
@@ -1882,6 +1860,16 @@ check_debug_info_structural (struct read_ctx *ctx,
       loc_addrs = &loc_addrs_mem;
     }
 
+  struct coverage ranges_coverage_mem, *ranges_coverage = NULL;
+  struct addr_record ranges_addrs_mem, *ranges_addrs = NULL;
+  if (ranges != NULL)
+    {
+      coverage_init (&ranges_coverage_mem, ranges->d_size);
+      ranges_coverage = &ranges_coverage_mem;
+      memset (&ranges_addrs_mem, 0, sizeof (ranges_addrs_mem));
+      ranges_addrs = &ranges_addrs_mem;
+    }
+
   while (!read_ctx_eof (ctx))
     {
       const unsigned char *cu_begin = ctx->ptr;
@@ -1955,9 +1943,12 @@ check_debug_info_structural (struct read_ctx *ctx,
            }
          cu_ctx.ptr = ctx->ptr;
 
-         if (!check_cu_structural (&cu_ctx, cur, abbrev_chain, strings, loc,
-                                   dwarf_64, &die_refs, loc_addrs,
-                                   strings_coverage, loc_coverage))
+         if (!check_cu_structural (&cu_ctx, cur, abbrev_chain,
+                                   strings, loc, ranges,
+                                   dwarf_64, &die_refs,
+                                   loc_addrs, ranges_addrs,
+                                   strings_coverage,
+                                   loc_coverage, ranges_coverage))
            {
              success = false;
              break;
@@ -2017,6 +2008,15 @@ check_debug_info_structural (struct read_ctx *ctx,
       coverage_free (loc_coverage);
     }
 
+  if (ranges_coverage != NULL)
+    {
+      if (success)
+       coverage_find_holes (ranges_coverage, found_hole,
+                            &((struct hole_info)
+                              {sec_ranges, mc_ranges, ranges->d_buf}));
+      coverage_free (ranges_coverage);
+    }
+
   if (loc_addrs != NULL)
     addr_record_free (loc_addrs);
 
@@ -2094,14 +2094,16 @@ check_location_expression (struct read_ctx *ctx, struct where *wh, bool addr_64)
 }
 
 static bool
-check_x_location_expression (struct read_ctx *ctx,
-                            struct cu *cu,
-                            struct coverage *loc_coverage,
-                            struct addr_record *loc_addrs,
-                            uint64_t addr, bool addr_64,
-                            struct where *wh)
-{
-  if (loc_coverage == NULL)
+check_loc_or_range_ref (struct read_ctx *ctx,
+                       struct cu *cu,
+                       struct coverage *coverage,
+                       struct addr_record *addrs,
+                       uint64_t addr,
+                       bool addr_64,
+                       struct where *wh,
+                       bool contains_locations)
+{
+  if (coverage == NULL)
     return true;
 
   if (!read_ctx_skip (ctx, addr))
@@ -2112,9 +2114,9 @@ check_x_location_expression (struct read_ctx *ctx,
       return false;
     }
 
-  if (coverage_is_covered (loc_coverage, addr))
+  if (coverage_is_covered (coverage, addr))
     {
-      if (!addr_record_has_addr (loc_addrs, addr))
+      if (!addr_record_has_addr (addrs, addr))
        {
          /* XXX do it like everywhere else, using addr_records and
             ref_records..  */
@@ -2125,7 +2127,7 @@ check_x_location_expression (struct read_ctx *ctx,
       return true;
     }
   else
-    addr_record_add (loc_addrs, addr);
+    addr_record_add (addrs, addr);
 
   uint64_t escape = addr_64 ? (uint64_t)-1 : (uint64_t)(uint32_t)-1;
 
@@ -2147,7 +2149,7 @@ check_x_location_expression (struct read_ctx *ctx,
       /* begin address */
       uint64_t begin_addr;
       if (!overlap
-         && !coverage_pristine (loc_coverage,
+         && !coverage_pristine (coverage,
                                 read_ctx_get_offset (ctx),
                                 addr_64 ? 8 : 4))
        HAVE_OVERLAP;
@@ -2161,7 +2163,7 @@ check_x_location_expression (struct read_ctx *ctx,
       /* end address */
       uint64_t end_addr;
       if (!overlap
-         && !coverage_pristine (loc_coverage,
+         && !coverage_pristine (coverage,
                                 read_ctx_get_offset (ctx),
                                 addr_64 ? 8 : 4))
        HAVE_OVERLAP;
@@ -2176,39 +2178,42 @@ check_x_location_expression (struct read_ctx *ctx,
 
       if (!done && begin_addr != escape)
        {
-         /* location expression length */
-         uint16_t len;
-         if (!overlap
-             && !coverage_pristine (loc_coverage,
-                                    read_ctx_get_offset (ctx), 2))
-           HAVE_OVERLAP;
-
-         if (!read_ctx_read_2ubyte (ctx, &len))
+         if (contains_locations)
            {
-             wr_error (&where, ": can't read length of location expression.\n");
-             return false;
-           }
+             /* location expression length */
+             uint16_t len;
+             if (!overlap
+                 && !coverage_pristine (coverage,
+                                        read_ctx_get_offset (ctx), 2))
+               HAVE_OVERLAP;
+
+             if (!read_ctx_read_2ubyte (ctx, &len))
+               {
+                 wr_error (&where, ": can't read length of location expression.\n");
+                 return false;
+               }
 
-         /* location expression itself */
-         struct read_ctx expr_ctx;
-         if (!read_ctx_init_sub (&expr_ctx, ctx, ctx->ptr, ctx->ptr + len))
-           {
-           not_enough:
-             wr_error (&where, PRI_NOT_ENOUGH, "location expression");
-             return false;
-           }
+             /* location expression itself */
+             struct read_ctx expr_ctx;
+             if (!read_ctx_init_sub (&expr_ctx, ctx, ctx->ptr, ctx->ptr + len))
+               {
+               not_enough:
+                 wr_error (&where, PRI_NOT_ENOUGH, "location expression");
+                 return false;
+               }
 
-         uint64_t expr_start = read_ctx_get_offset (ctx);
-         check_location_expression (&expr_ctx, &where, addr_64);
-         uint64_t expr_end = read_ctx_get_offset (ctx);
-         if (!overlap
-             && !coverage_pristine (loc_coverage,
-                                    expr_start, expr_end - expr_start))
-           HAVE_OVERLAP;
-
-         if (!read_ctx_skip (ctx, len))
-           /* "can't happen" */
-           goto not_enough;
+             uint64_t expr_start = read_ctx_get_offset (ctx);
+             check_location_expression (&expr_ctx, &where, addr_64);
+             uint64_t expr_end = read_ctx_get_offset (ctx);
+             if (!overlap
+                 && !coverage_pristine (coverage,
+                                        expr_start, expr_end - expr_start))
+               HAVE_OVERLAP;
+
+             if (!read_ctx_skip (ctx, len))
+               /* "can't happen" */
+               goto not_enough;
+           }
        }
       else if (!done)
        {
@@ -2221,7 +2226,7 @@ check_x_location_expression (struct read_ctx *ctx,
        }
 #undef HAVE_OVERLAP
 
-      coverage_add (loc_coverage, where.addr1, read_ctx_get_offset (ctx) - 1);
+      coverage_add (coverage, where.addr1, read_ctx_get_offset (ctx) - 1);
       if (done)
        break;
     }
@@ -2243,12 +2248,15 @@ read_die_chain (struct read_ctx *ctx,
                struct abbrev_table *abbrevs,
                Elf_Data *strings,
                Elf_Data *loc,
+               Elf_Data *ranges,
                bool dwarf_64, bool addr_64,
                struct ref_record *die_refs,
                struct ref_record *die_loc_refs,
                struct addr_record *loc_addrs,
+               struct addr_record *ranges_addrs,
                struct coverage *strings_coverage,
-               struct coverage *loc_coverage)
+               struct coverage *loc_coverage,
+               struct coverage *ranges_coverage)
 {
   bool got_die = false;
   uint64_t sibling_addr = 0;
@@ -2377,31 +2385,56 @@ read_die_chain (struct read_ctx *ctx,
            }
 
          bool check_locptr = false;
-         bool locptr_64 = addr_64;
          if (is_location_attrib (it->name))
-           {
-             switch (check_CU_location_form (form, dwarf_64))
-               {
-               case 0: /* absolutely invalid */
-                 /* Only print error if it's indirect.  Otherwise we
-                    gave diagnostic during abbrev loading.  */
-                 if (indirect)
-                   wr_error (&where,
-                             ": location attribute with invalid (indirect) form \"%s\".\n",
-                             dwarf_form_string (form));
-                 break;
+           switch (form)
+             {
+             case DW_FORM_data8:
+               if (!dwarf_64)
+                 wr_error (&where,
+                           ": location attribute with form \"%s\" in 32-bit CU.\n",
+                           dwarf_form_string (form));
+               /* fall-through */
+             case DW_FORM_data4:
+               check_locptr = true;
+               /* fall-through */
+             case DW_FORM_block1:
+             case DW_FORM_block2:
+             case DW_FORM_block4:
+             case DW_FORM_block:
+               break;
 
-               case -1: /* locptr invalid in this context */
+             default:
+               /* Only print error if it's indirect.  Otherwise we
+                  gave diagnostic during abbrev loading.  */
+               if (indirect)
                  wr_error (&where,
-                           ": location attribute with form \"%s\" in %d-bit CU.\n",
-                           dwarf_form_string (form), (dwarf_64 ? 64 : 32));
-                 locptr_64 = !locptr_64;
+                           ": location attribute with invalid (indirect) form \"%s\".\n",
+                           dwarf_form_string (form));
+             };
 
-                 /* fall-through */
-               case 1: /* locptr */
-                 check_locptr = true;
-               };
-           }
+         bool check_rangeptr = false;
+         if (it->name == DW_AT_ranges)
+           switch (form)
+             {
+             case DW_FORM_data8:
+               if (!dwarf_64)
+                 wr_error (&where,
+                           ": DW_AT_ranges with form DW_FORM_data8 in 32-bit CU.\n");
+               /* fall-through */
+             case DW_FORM_data4:
+               check_rangeptr = true;
+               break;
+
+             default:
+               /* Only print error if it's indirect.  Otherwise we
+                  gave diagnostic during abbrev loading.  */
+               if (indirect)
+                 wr_error (&where,
+                           ": DW_AT_ranges with invalid (indirect) form \"%s\".\n",
+                           dwarf_form_string (form));
+             };
+
+         assert (!(check_locptr && check_rangeptr));
 
          switch (form)
            {
@@ -2516,13 +2549,19 @@ read_die_chain (struct read_ctx *ctx,
 
                if (it->name == DW_AT_sibling)
                  sibling_addr = value;
-               else if (check_locptr)
+               else if (check_locptr || check_rangeptr)
                  {
+                   Elf_Data *d = check_locptr ? loc : ranges;
+                   struct coverage *cov
+                     = check_locptr ? loc_coverage : ranges_coverage;
+                   struct addr_record *rec
+                     = check_locptr ? loc_addrs : ranges_addrs;
+
                    struct read_ctx sub_ctx;
-                   read_ctx_init (&sub_ctx, ctx->dbg, loc);
-                   check_x_location_expression (&sub_ctx, cu, loc_coverage,
-                                                loc_addrs, value, locptr_64,
-                                                &where);
+                   read_ctx_init (&sub_ctx, ctx->dbg, d);
+                   check_loc_or_range_ref (&sub_ctx, cu, cov,
+                                           rec, value, addr_64,
+                                           &where, check_locptr);
                  }
                else if (it->form == DW_FORM_ref4)
                  record_ref (value, &where, true);
@@ -2538,13 +2577,19 @@ read_die_chain (struct read_ctx *ctx,
 
                if (it->name == DW_AT_sibling)
                  sibling_addr = value;
-               else if (check_locptr)
+               else if (check_locptr || check_rangeptr)
                  {
+                   Elf_Data *d = check_locptr ? loc : ranges;
+                   struct coverage *cov
+                     = check_locptr ? loc_coverage : ranges_coverage;
+                   struct addr_record *rec
+                     = check_locptr ? loc_addrs : ranges_addrs;
+
                    struct read_ctx sub_ctx;
-                   read_ctx_init (&sub_ctx, ctx->dbg, loc);
-                   check_x_location_expression (&sub_ctx, cu, loc_coverage,
-                                                loc_addrs, value, locptr_64,
-                                                &where);
+                   read_ctx_init (&sub_ctx, ctx->dbg, d);
+                   check_loc_or_range_ref (&sub_ctx, cu, cov,
+                                           rec, value, addr_64,
+                                           &where, check_locptr);
                  }
                else if (it->form == DW_FORM_ref8)
                  record_ref (value, &where, true);
@@ -2618,10 +2663,13 @@ read_die_chain (struct read_ctx *ctx,
 
       if (abbrev->has_children)
        {
-         int st = read_die_chain (ctx, cu, abbrevs, strings, loc,
+         int st = read_die_chain (ctx, cu, abbrevs, strings,
+                                  loc, ranges,
                                   dwarf_64, addr_64,
-                                  die_refs, die_loc_refs, loc_addrs,
-                                  strings_coverage, loc_coverage);
+                                  die_refs, die_loc_refs,
+                                  loc_addrs, ranges_addrs,
+                                  strings_coverage,
+                                  loc_coverage, ranges_coverage);
          if (st == -1)
            return -1;
          else if (st == 0)
@@ -2673,11 +2721,14 @@ check_cu_structural (struct read_ctx *ctx,
                     struct abbrev_table *abbrev_chain,
                     Elf_Data *strings,
                     Elf_Data *loc,
+                    Elf_Data *ranges,
                     bool dwarf_64,
                     struct ref_record *die_refs,
                     struct addr_record *loc_addrs,
+                    struct addr_record *ranges_addrs,
                     struct coverage *strings_coverage,
-                    struct coverage *loc_coverage)
+                    struct coverage *loc_coverage,
+                    struct coverage *ranges_coverage)
 {
   uint16_t version;
   uint64_t abbrev_offset;
@@ -2726,11 +2777,12 @@ check_cu_structural (struct read_ctx *ctx,
   memset (&die_loc_refs, 0, sizeof (die_loc_refs));
 
   bool retval = true;
-  if (read_die_chain (ctx, cu, abbrevs, strings, loc,
+  if (read_die_chain (ctx, cu, abbrevs, strings, loc, ranges,
                      dwarf_64, address_size == 8,
                      die_refs, &die_loc_refs,
-                     loc_addrs, strings_coverage,
-                     loc_coverage) >= 0)
+                     loc_addrs, ranges_addrs,
+                     strings_coverage,
+                     loc_coverage, ranges_coverage) >= 0)
     {
       for (size_t i = 0; i < abbrevs->size; ++i)
        if (!abbrevs->abbr[i].used)