public inbox for dwz@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Handle DW_FORM_implicit_const
@ 2021-01-17 22:24 Mark Wielaard
  2021-01-18  8:12 ` Jakub Jelinek
  0 siblings, 1 reply; 2+ messages in thread
From: Mark Wielaard @ 2021-01-17 22:24 UTC (permalink / raw)
  To: dwz; +Cc: Mark Wielaard

This handles DW_FORM_implicit_const. This form keeps the actual data
value in the abbrev. This makes things tricky because we have to decide
where to keep (a reference to) the value and when to update the value
if necessary.

To not bloat each abbrev_attr struct we add an int64 *values to the
abbrev_tag struct which points to an array of values at the end. We
only allocate values up to the highest implicit_const form (if any)
when we know those upfront. In compute_abbrevs and recompute_abbrevs
we have to allocate a maximum number of values (just like we have to
allocate the maximum number of attributes). But when cloning those
we reduce the number of values (and attributes) to the minimum needed.
To keep the values field up to date always call pool_clone_abbrev
when copying an abbrev.

When a DW_AT_decl_file or DW_AT_call_file attribute references a
file number using DW_FORM_implicit_const we need to be careful when
updating the value for a new file table. The abbrev can be used by
more than one DIE, but the value only needs to be updated once. We
use the fact that file references are positive, but an implicit_const
is signed. When updating we negate the new file number and don't update
a negative file number. Negative file numbers are made positive again when
calculating the new abbrev sizes in compute_abbrevs.

	* dwz.c (write_sleb128): New macro.
	(struct abbrev_tag): Add values pointer field.
	(pool_clone_abbrev): New function.
	(abbrev_eq2): Handle DW_FORM_implicit_const by also comparing
	the value.
	(compute_abbrev_hash): Likewise.
	(read_abbrev): Read DW_FORM_implicit_const. Keep track of
	highest_implicit_value_ndx. Allocate values.
	(get_AT): Return pointer to value for DW_FORM_implicit_const.
	(get_AT_int): Return value of DW_FORM_implicit_const.
	(checksum_die): Get value for DW_AT_decl_file or DW_AT_call_file
	from DW_FORM_implicit_const, skip for others.
	(checksum_ref_die): Likewise.
	(die_eq_1): Likewise.
	(mark_refs): Handle DW_FORM_implicit_const.
	(read_debug_info): Handle DW_FORM_implicit_const, set cu_lang
	for compile/partial units.
	(size_of_sleb128): New function.
	(build_abbrevs_for_die): Handle DW_FORM_implicit_const value.
	Use pool_clone_abbrev.
	(abbrev_cmp): Also compare DW_FORM_implicit_const values.
	(compute_abbrevs): Use pool_clone_abbrev. Switch any negative
	file implicit_const values back before calculating size.
	(write_abbrev): Also write DW_FORM_implicit_const value.
	(write_die): Handle DW_FORM_implicit_const, but don't change
	form/value for DW_AT_decl_file and DW_AT_call_file.
	(recompute_abbrevs): Alloc space for max_nattr values, set
	abbrev_tag values field.
---
 dwz.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 215 insertions(+), 55 deletions(-)

diff --git a/dwz.c b/dwz.c
index f8f2910..b3cf346 100644
--- a/dwz.c
+++ b/dwz.c
@@ -399,6 +399,25 @@ typedef struct
     }					\
   while (0)
 
+#define write_sleb128(ptr, val)					\
+  do								\
+    {								\
+      int64_t valv = (val);					\
+      bool more;						\
+      do							\
+	{							\
+	  unsigned char c = valv & 0x7f;			\
+	  valv >>= 7;						\
+	  more = ((valv != 0 || (c & 0x40) != 0)                \
+		  && (valv != -1 || (c & 0x40) == 0));          \
+	  if (more)						\
+	    c |= 0x80;						\
+	  *ptr++ = c;						\
+	}							\
+      while (more);						\
+    }								\
+  while (0)
+
 /* Macro to skip a uleb128 or sleb128 number and update ptr to the end of the
    number.  */
 #define skip_leb128(ptr) \
@@ -898,6 +917,8 @@ struct abbrev_tag
   bool children;
   /* True if any typed DWARF opcodes refer to this.  */
   bool op_type_referenced;
+  /* The values of DW_FORM_implicit_const attribute forms.  */
+  int64_t *values;
   /* Attribute/form pairs.  */
   struct abbrev_attr attr[0];
 };
@@ -1204,6 +1225,34 @@ pool_destroy (void)
   (struct name *) pool_alloc_1 (offsetof (struct align_##name, s), size)
 #endif
 
+static struct abbrev_tag *
+pool_clone_abbrev (struct abbrev_tag *t)
+{
+  struct abbrev_tag *newt;
+  size_t newt_size;
+  unsigned nvalue = 0;
+  if (t->values != NULL)
+    {
+      unsigned i;
+      for (i = 0; i < t->nattr; i++)
+	if (t->attr[i].form == DW_FORM_implicit_const)
+	  nvalue = i + 1;
+    }
+  newt_size = (sizeof (*newt)
+	       + t->nattr * sizeof (struct abbrev_attr)
+	       + nvalue * sizeof (int64_t));
+  newt = pool_alloc (abbrev_tag, newt_size);
+  memcpy (newt, t, newt_size - (nvalue * sizeof (int64_t)));
+  if (nvalue == 0)
+    newt->values = NULL;
+  else
+    {
+      newt->values = (int64_t *) &newt->attr[newt->nattr];
+      memcpy (newt->values, t->values, nvalue * sizeof (int64_t));
+    }
+  return newt;
+}
+
 /* Hash function in first abbrev hash table as well as cu->cu_new_abbrev
    htab.  */
 static hashval_t
@@ -1239,7 +1288,9 @@ abbrev_eq2 (const void *p, const void *q)
     return 0;
   for (i = 0; i < t1->nattr; i++)
     if (t1->attr[i].attr != t2->attr[i].attr
-	|| t1->attr[i].form != t2->attr[i].form)
+	|| t1->attr[i].form != t2->attr[i].form
+	|| (t1->attr[i].form == DW_FORM_implicit_const
+	    && t1->values[i] != t2->values[i]))
       return 0;
   return 1;
 }
@@ -1257,6 +1308,8 @@ compute_abbrev_hash (struct abbrev_tag *t)
     {
       t->hash = iterative_hash_object (t->attr[i].attr, t->hash);
       t->hash = iterative_hash_object (t->attr[i].form, t->hash);
+      if (t->attr[i].form == DW_FORM_implicit_const)
+	t->hash = iterative_hash_object (t->values[i], t->hash);
     }
 }
 
@@ -1278,6 +1331,7 @@ read_abbrev (DSO *dso, unsigned char *ptr)
 
   while ((attr = read_uleb128 (ptr)) != 0)
     {
+      int highest_implicit_value_ndx = -1;
       unsigned int nattr = 0;
       unsigned char *p = ptr;
 
@@ -1287,7 +1341,12 @@ read_abbrev (DSO *dso, unsigned char *ptr)
 	{
 	  nattr++;
 	  form = read_uleb128 (p);
-	  if (form == 2
+	  if (form == DW_FORM_implicit_const)
+	    {
+	      skip_leb128 (p);
+	      highest_implicit_value_ndx = nattr - 1;
+	    }
+	  else if (form == 2
 	      || (form > DW_FORM_flag_present
 		  && !(form == DW_FORM_ref_sig8
 		       || form == DW_FORM_data16
@@ -1308,19 +1367,25 @@ read_abbrev (DSO *dso, unsigned char *ptr)
 	}
 
       t = pool_alloc (abbrev_tag,
-		      sizeof (*t) + nattr * sizeof (struct abbrev_attr));
+		      sizeof (*t) + nattr * sizeof (struct abbrev_attr)
+		      + sizeof (int64_t) * (highest_implicit_value_ndx + 1));
       t->entry = attr;
       t->hash = attr;
-      t->nattr = 0;
+      t->nattr = nattr;
       t->nusers = 0;
       t->tag = read_uleb128 (ptr);
       t->children = *ptr++ == DW_CHILDREN_yes;
       t->op_type_referenced = false;
+      t->values = (highest_implicit_value_ndx >= 0
+		   ? (int64_t *) &t->attr[nattr] : NULL);
+      nattr = 0;
       while ((attr = read_uleb128 (ptr)) != 0)
 	{
 	  form = read_uleb128 (ptr);
-	  t->attr[t->nattr].attr = attr;
-	  t->attr[t->nattr++].form = form;
+	  if (form == DW_FORM_implicit_const)
+	    t->values[nattr] = read_sleb128 (ptr);
+	  t->attr[nattr].attr = attr;
+	  t->attr[nattr++].form = form;
 	}
       skip_leb128 (ptr);
       if (t->nattr > max_nattr)
@@ -2164,6 +2229,8 @@ get_AT (dw_die_ref die, enum dwarf_attribute at, enum dwarf_form *formp)
       if (t->attr[i].attr == at)
 	{
 	  *formp = form;
+	  if (form == DW_FORM_implicit_const)
+	    return (unsigned char *) &t->values[i];
 	  return ptr;
 	}
 
@@ -2212,6 +2279,8 @@ get_AT_int (dw_die_ref die, enum dwarf_attribute at, bool *present,
     case DW_FORM_ref_udata:
     case DW_FORM_udata:
       return read_uleb128 (ptr);
+    case DW_FORM_implicit_const:
+      return *(uint64_t *)ptr; /* See get_AT.  */
     default:
       *present = false;
       return 0;
@@ -3371,6 +3440,8 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	    case DW_FORM_data8: value = read_64 (ptr); handled = true; break;
 	    case DW_FORM_udata:
 	      value = read_uleb128 (ptr); handled = true; break;
+	    case DW_FORM_implicit_const:
+	      value = t->values[i]; handled = true; break;
 	    default:
 	      error (0, 0, "%s: Unhandled %s for %s",
 		     dso->filename, get_DW_FORM_str (form),
@@ -3505,6 +3576,7 @@ checksum_die (DSO *dso, dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die)
 	  ptr += ptr_size;
 	  break;
 	case DW_FORM_flag_present:
+	case DW_FORM_implicit_const:
 	  break;
 	case DW_FORM_flag:
 	case DW_FORM_data1:
@@ -3937,6 +4009,7 @@ checksum_ref_die (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die,
 	      ptr += ptr_size;
 	      break;
 	    case DW_FORM_flag_present:
+	    case DW_FORM_implicit_const:
 	      break;
 	    case DW_FORM_flag:
 	    case DW_FORM_data1:
@@ -4629,6 +4702,7 @@ die_eq_1 (dw_cu_ref cu1, dw_cu_ref cu2,
 	    case DW_FORM_data4: value1 = read_32 (ptr1); break;
 	    case DW_FORM_data8: value1 = read_64 (ptr1); break;
 	    case DW_FORM_udata: value1 = read_uleb128 (ptr1); break;
+	    case DW_FORM_implicit_const: value1 = t1->values[i]; break;
 	    default: abort ();
 	    }
 	  switch (form2)
@@ -4638,6 +4712,7 @@ die_eq_1 (dw_cu_ref cu1, dw_cu_ref cu2,
 	    case DW_FORM_data4: value2 = read_32 (ptr2); break;
 	    case DW_FORM_data8: value2 = read_64 (ptr2); break;
 	    case DW_FORM_udata: value2 = read_uleb128 (ptr2); break;
+	    case DW_FORM_implicit_const: value2 = t2->values[j]; break;
 	    default: abort ();
 	    }
 	  if (ignore_locus)
@@ -4758,6 +4833,7 @@ die_eq_1 (dw_cu_ref cu1, dw_cu_ref cu2,
 	  ptr2 += ptr_size;
 	  break;
 	case DW_FORM_flag_present:
+	case DW_FORM_implicit_const:
 	  break;
 	case DW_FORM_flag:
 	case DW_FORM_data1:
@@ -5850,6 +5926,7 @@ mark_refs (dw_cu_ref cu, dw_die_ref top_die, dw_die_ref die, int mode)
 	      ptr += ptr_size;
 	      break;
 	    case DW_FORM_flag_present:
+	    case DW_FORM_implicit_const:
 	      break;
 	    case DW_FORM_flag:
 	    case DW_FORM_data1:
@@ -6803,6 +6880,13 @@ read_debug_info (DSO *dso, int kind, unsigned int *die_count)
 		  break;
 		case DW_FORM_flag_present:
 		  break;
+		case DW_FORM_implicit_const:
+		  if (lang_p
+		      && (die->die_tag == DW_TAG_compile_unit
+			  || die->die_tag == DW_TAG_partial_unit)
+		      && t->attr[i].attr == DW_AT_language)
+		    cu->lang = t->values[i];
+		  break;
 		case DW_FORM_data1:
 		  if (lang_p
 		      && (die->die_tag == DW_TAG_compile_unit
@@ -9495,6 +9579,24 @@ size_of_uleb128 (uint64_t val)
   return size;
 }
 
+/* Return number of bytes needed to encode VAL using
+   sleb128.  */
+static unsigned int
+size_of_sleb128 (int64_t val)
+{
+  unsigned int size = 0;
+  unsigned char c;
+  do
+    {
+      c = val & 0x7f;
+      val >>= 7;
+      size++;
+    }
+  while ((val != 0 || (c & 0x40) != 0)
+	 && (val != -1 || (c & 0x40) == 0));
+  return size;
+}
+
 /* Hash table mapping original file IDs to new ids.  */
 static htab_t line_htab;
 /* Current new maximum file ID.  */
@@ -10319,6 +10421,8 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	    {
 	      t->attr[i].attr = reft->attr[i].attr;
 	      t->attr[i].form = reft->attr[i].form;
+	      if (t->attr[i].form == DW_FORM_implicit_const)
+		t->values[i] = reft->values[i];
 	    }
 	  t->nattr = reft->nattr;
 	}
@@ -10331,7 +10435,7 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	      uint32_t form = reft->attr[i].form;
 	      size_t len = 0;
 	      dw_die_ref refd;
-	      uint64_t value;
+	      uint64_t value = 0;
 	      unsigned char *orig_ptr = ptr;
 
 	      while (form == DW_FORM_indirect)
@@ -10348,30 +10452,40 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		    case DW_FORM_data4: value = read_32 (ptr); break;
 		    case DW_FORM_data8: value = read_64 (ptr); break;
 		    case DW_FORM_udata: value = read_uleb128 (ptr); break;
+		    case DW_FORM_implicit_const: break;
 		    default:
 		      error (0, 0, "Unhandled %s for %s",
 			     get_DW_FORM_str (form),
 			     get_DW_AT_str (reft->attr[i].attr));
 		      return 1;
 		    }
-		  value = line_htab_lookup (refcu, value);
-		  if (value <= 0xff)
+		  /* Note that the value is only used for calculating the
+		     DIE size and possibly change form. Doesn't change the
+		     implicit_const from or value.  */
+		  if (form != DW_FORM_implicit_const)
 		    {
-		      form = DW_FORM_data1;
-		      die->die_size++;
-		    }
-		  else if (value <= 0xffff)
-		    {
-		      form = DW_FORM_data2;
-		      die->die_size += 2;
-		    }
-		  else
-		    {
-		      form = DW_FORM_data4;
-		      die->die_size += 4;
+		      value = line_htab_lookup (refcu, value);
+		      if (value <= 0xff)
+			{
+			  form = DW_FORM_data1;
+			  die->die_size++;
+			}
+		      else if (value <= 0xffff)
+			{
+			  form = DW_FORM_data2;
+			  die->die_size += 2;
+			}
+		      else
+			{
+			  form = DW_FORM_data4;
+			  die->die_size += 4;
+			}
 		    }
 		  t->attr[j].attr = reft->attr[i].attr;
-		  t->attr[j++].form = form;
+		  t->attr[j].form = form;
+		  if (form == DW_FORM_implicit_const)
+		    t->values[j] = reft->values[i];
+		  j++;
 		  continue;
 		}
 
@@ -10475,6 +10589,7 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 		    }
 		  break;
 		case DW_FORM_flag_present:
+		case DW_FORM_implicit_const:
 		  break;
 		case DW_FORM_flag:
 		case DW_FORM_data1:
@@ -10657,7 +10772,10 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
 	      if (form == DW_FORM_block1)
 		ptr += len;
 	      t->attr[j].attr = reft->attr[i].attr;
-	      t->attr[j++].form = reft->attr[i].form;
+	      t->attr[j].form = reft->attr[i].form;
+	      if (reft->attr[i].form == DW_FORM_implicit_const)
+		t->values[j] = reft->values[i];
+	      j++;
 	      die->die_size += ptr - orig_ptr;
 	    }
 	  t->nattr = j;
@@ -10785,11 +10903,7 @@ build_abbrevs_for_die (htab_t h, dw_cu_ref cu, dw_die_ref die,
     }
   else
     {
-      struct abbrev_tag *newt
-	= pool_alloc (abbrev_tag,
-		      sizeof (*newt) + t->nattr * sizeof (struct abbrev_attr));
-      memcpy (newt, t,
-	      sizeof (*newt) + t->nattr * sizeof (struct abbrev_attr));
+      struct abbrev_tag *newt = pool_clone_abbrev (t);
       *slot = newt;
       die->u.p2.die_new_abbrev = newt;
     }
@@ -10882,6 +10996,13 @@ abbrev_cmp (const void *p, const void *q)
 	return -1;
       if (t1->attr[i].form > t2->attr[i].form)
 	return 1;
+      if (t1->attr[i].form == DW_FORM_implicit_const)
+	{
+	  if (t1->values[i] < t2->values[i])
+	    return -1;
+	  if (t1->values[i] > t2->values[i])
+	    return 1;
+	}
     }
   return 0;
 }
@@ -11070,7 +11191,9 @@ compute_abbrevs (DSO *dso)
   t = (struct abbrev_tag *)
       obstack_alloc (&ob2,
 		     sizeof (*t)
-		     + (max_nattr + 4) * sizeof (struct abbrev_attr));
+		     + (max_nattr + 4) * sizeof (struct abbrev_attr)
+		     + (max_nattr + 4) * sizeof (int64_t));
+  t->values = (int64_t *) &t->attr[max_nattr + 4];
   for (cu = first_cu, ncus = 0; cu; cu = cu->cu_next)
     {
       unsigned int intracu, ndies = 0, tagsize = 0, nchildren = 0;
@@ -11327,13 +11450,7 @@ compute_abbrevs (DSO *dso)
 		    {
 		      struct abbrev_tag *newt;
 		      arr[k]->entry = ++entry;
-		      newt = pool_alloc (abbrev_tag,
-					 sizeof (*newt)
-					 + arr[k]->nattr
-					   * sizeof (struct abbrev_attr));
-		      memcpy (newt, arr[k],
-			      sizeof (*newt)
-			      + arr[k]->nattr * sizeof (struct abbrev_attr));
+		      newt = pool_clone_abbrev (arr[k]);
 		      *slot = newt;
 		    }
 		}
@@ -11432,13 +11549,7 @@ compute_abbrevs (DSO *dso)
 		    {
 		      struct abbrev_tag *newt;
 		      arr[k]->entry = ++entry;
-		      newt = pool_alloc (abbrev_tag,
-					 sizeof (*newt)
-					 + arr[k]->nattr
-					   * sizeof (struct abbrev_attr));
-		      memcpy (newt, arr[k],
-			      sizeof (*newt)
-			      + arr[k]->nattr * sizeof (struct abbrev_attr));
+		      newt = pool_clone_abbrev (arr[k]);
 		      *slot = newt;
 		    }
 		}
@@ -11481,6 +11592,21 @@ compute_abbrevs (DSO *dso)
 	    {
 	      abbrev_size += size_of_uleb128 (arr[i]->attr[j].attr);
 	      abbrev_size += size_of_uleb128 (arr[i]->attr[j].form);
+	      if (arr[i]->attr[j].form == DW_FORM_implicit_const)
+		{
+		  /* If this is a shared abbrev for a file reference
+		     attribute, update to the new file number (in the
+		     mulifile .debug_line).  Note that this might
+		     change the abbrev size...  */
+		  if (unlikely (wr_multifile || op_multifile)
+		      && (arr[i]->attr[j].attr == DW_AT_decl_file
+			  || arr[i]->attr[j].attr == DW_AT_call_file))
+		    {
+		      if (arr[i]->values[j] < 0)
+			arr[i]->values[j] = -arr[i]->values[j];
+		    }
+		  abbrev_size += size_of_sleb128 (arr[i]->values[j]);
+		}
 	    }
 	  abbrev_size += 2;
 	}
@@ -11571,6 +11697,8 @@ write_abbrev (void)
 	    {
 	      write_uleb128 (ptr, arr[i]->attr[j].attr);
 	      write_uleb128 (ptr, arr[i]->attr[j].form);
+	      if (arr[i]->attr[j].form == DW_FORM_implicit_const)
+		write_sleb128 (ptr, arr[i]->values[j]);
 	    }
 	  *ptr++ = 0;
 	  *ptr++ = 0;
@@ -11932,22 +12060,51 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 	      && (reft->attr[i].attr == DW_AT_decl_file
 		  || reft->attr[i].attr == DW_AT_call_file))
 	    {
+	      bool update = false;
 	      switch (form)
 		{
-		case DW_FORM_data1: value = read_8 (inptr); break;
-		case DW_FORM_data2: value = read_16 (inptr); break;
-		case DW_FORM_data4: value = read_32 (inptr); break;
-		case DW_FORM_data8: value = read_64 (inptr); break;
-		case DW_FORM_udata: value = read_uleb128 (inptr); break;
+		case DW_FORM_data1:
+		  value = read_8 (inptr);
+		  update = true;
+		  break;
+		case DW_FORM_data2:
+		  value = read_16 (inptr);
+		  update = true;
+		  break;
+		case DW_FORM_data4:
+		  value = read_32 (inptr);
+		  update = true;
+		  break;
+		case DW_FORM_data8:
+		  value = read_64 (inptr);
+		  update = true;
+		  break;
+		case DW_FORM_udata:
+		  value = read_uleb128 (inptr);
+		  update = true;
+		  break;
+		case DW_FORM_implicit_const:
+		  /* Negative means, already transformed.  */
+		  if (reft->values[i] >= 0)
+		    update = true;
+		  value = reft->values[i];
+		  break;
 		default: abort ();
 		}
-	      value = line_htab_lookup (refcu, value);
-	      switch (t->attr[j].form)
+	      if (update)
 		{
-		case DW_FORM_data1: write_8 (ptr, value); break;
-		case DW_FORM_data2: write_16 (ptr, value); break;
-		case DW_FORM_data4: write_32 (ptr, value); break;
-		default: abort ();
+		  value = line_htab_lookup (refcu, value);
+		  switch (t->attr[j].form)
+		    {
+		    case DW_FORM_data1: write_8 (ptr, value); break;
+		    case DW_FORM_data2: write_16 (ptr, value); break;
+		    case DW_FORM_data4: write_32 (ptr, value); break;
+		    case DW_FORM_udata: write_uleb128 (ptr, value); break;
+		    case DW_FORM_implicit_const:
+		      reft->values[i] = -value; /* Note, negated.  */
+		      break;
+		    default: abort ();
+		    }
 		}
 	      j++;
 	      continue;
@@ -12039,6 +12196,7 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die,
 		}
 	      break;
 	    case DW_FORM_flag_present:
+	    case DW_FORM_implicit_const:
 	      break;
 	    case DW_FORM_flag:
 	    case DW_FORM_data1:
@@ -12375,7 +12533,9 @@ recompute_abbrevs (dw_cu_ref cu, unsigned int cu_size)
   t = (struct abbrev_tag *)
       obstack_alloc (&ob2,
 		     sizeof (*t)
-		     + (max_nattr + 4) * sizeof (struct abbrev_attr));
+		     + (max_nattr + 4) * sizeof (struct abbrev_attr)
+		     + (max_nattr + 4) * sizeof (int64_t));
+  t->values = (int64_t *) &t->attr[max_nattr + 4];
 
   build_abbrevs_for_die (cu->u1.cu_new_abbrev_owner
 			 ? cu->u1.cu_new_abbrev_owner->cu_new_abbrev
-- 
2.18.4


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] Handle DW_FORM_implicit_const
  2021-01-17 22:24 [PATCH] Handle DW_FORM_implicit_const Mark Wielaard
@ 2021-01-18  8:12 ` Jakub Jelinek
  0 siblings, 0 replies; 2+ messages in thread
From: Jakub Jelinek @ 2021-01-18  8:12 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: dwz

On Sun, Jan 17, 2021 at 11:24:00PM +0100, Mark Wielaard wrote:
> This handles DW_FORM_implicit_const. This form keeps the actual data
> value in the abbrev. This makes things tricky because we have to decide
> where to keep (a reference to) the value and when to update the value
> if necessary.
> 
> To not bloat each abbrev_attr struct we add an int64 *values to the
> abbrev_tag struct which points to an array of values at the end. We
> only allocate values up to the highest implicit_const form (if any)
> when we know those upfront. In compute_abbrevs and recompute_abbrevs
> we have to allocate a maximum number of values (just like we have to
> allocate the maximum number of attributes). But when cloning those
> we reduce the number of values (and attributes) to the minimum needed.
> To keep the values field up to date always call pool_clone_abbrev
> when copying an abbrev.
> 
> When a DW_AT_decl_file or DW_AT_call_file attribute references a
> file number using DW_FORM_implicit_const we need to be careful when
> updating the value for a new file table. The abbrev can be used by
> more than one DIE, but the value only needs to be updated once. We
> use the fact that file references are positive, but an implicit_const
> is signed. When updating we negate the new file number and don't update
> a negative file number. Negative file numbers are made positive again when
> calculating the new abbrev sizes in compute_abbrevs.
> 
> 	* dwz.c (write_sleb128): New macro.
> 	(struct abbrev_tag): Add values pointer field.
> 	(pool_clone_abbrev): New function.
> 	(abbrev_eq2): Handle DW_FORM_implicit_const by also comparing
> 	the value.
> 	(compute_abbrev_hash): Likewise.
> 	(read_abbrev): Read DW_FORM_implicit_const. Keep track of
> 	highest_implicit_value_ndx. Allocate values.
> 	(get_AT): Return pointer to value for DW_FORM_implicit_const.
> 	(get_AT_int): Return value of DW_FORM_implicit_const.
> 	(checksum_die): Get value for DW_AT_decl_file or DW_AT_call_file
> 	from DW_FORM_implicit_const, skip for others.
> 	(checksum_ref_die): Likewise.
> 	(die_eq_1): Likewise.
> 	(mark_refs): Handle DW_FORM_implicit_const.
> 	(read_debug_info): Handle DW_FORM_implicit_const, set cu_lang
> 	for compile/partial units.
> 	(size_of_sleb128): New function.
> 	(build_abbrevs_for_die): Handle DW_FORM_implicit_const value.
> 	Use pool_clone_abbrev.
> 	(abbrev_cmp): Also compare DW_FORM_implicit_const values.
> 	(compute_abbrevs): Use pool_clone_abbrev. Switch any negative
> 	file implicit_const values back before calculating size.
> 	(write_abbrev): Also write DW_FORM_implicit_const value.
> 	(write_die): Handle DW_FORM_implicit_const, but don't change
> 	form/value for DW_AT_decl_file and DW_AT_call_file.
> 	(recompute_abbrevs): Alloc space for max_nattr values, set
> 	abbrev_tag values field.

Ok, thanks.

	Jakub


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-01-18  8:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-17 22:24 [PATCH] Handle DW_FORM_implicit_const Mark Wielaard
2021-01-18  8:12 ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).