This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Readelf: Handle forward references to CIEs


The linker side of pr16563 was fixed with commit 18cd5bce, but
unfortunately people continue to use older linkers with -flto.  This
means we have binaries with working .eh_frame that can't be dumped by
readelf, and I'm seeing internal IBM bug reports about this fact.

	PR 16563
	* dwarf.c (GET): Remove semicolon.
	(read_cie): New function, extracted from..
	(display_debug_frames): ..here.  Correctly handle signed offset
	from FDE to CIE in .eh_frame.  Decode forward referenced CIEs too.

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 348e20f..3f4095a 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -5232,10 +5232,97 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
   printf ("\n");
 }
 
-#define GET(VAR, N)	SAFE_BYTE_GET_AND_INC (VAR, start, N, end);
+#define GET(VAR, N)	SAFE_BYTE_GET_AND_INC (VAR, start, N, end)
 #define LEB()	read_uleb128 (start, & length_return, end); start += length_return
 #define SLEB()	read_sleb128 (start, & length_return, end); start += length_return
 
+static unsigned char *
+read_cie (unsigned char *start, unsigned char *end,
+	  Frame_Chunk **p_cie, int *p_version,
+	  unsigned long *p_aug_len, unsigned char **p_aug)
+{
+  int version;
+  Frame_Chunk *fc;
+  unsigned int length_return;
+  unsigned char *augmentation_data = NULL;
+  unsigned long augmentation_data_len = 0;
+
+  fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
+  memset (fc, 0, sizeof (Frame_Chunk));
+
+  fc->col_type = (short int *) xmalloc (sizeof (short int));
+  fc->col_offset = (int *) xmalloc (sizeof (int));
+
+  version = *start++;
+
+  fc->augmentation = (char *) start;
+  start = (unsigned char *) strchr ((char *) start, '\0') + 1;
+
+  if (strcmp (fc->augmentation, "eh") == 0)
+    start += eh_addr_size;
+
+  if (version >= 4)
+    {
+      GET (fc->ptr_size, 1);
+      GET (fc->segment_size, 1);
+      eh_addr_size = fc->ptr_size;
+    }
+  else
+    {
+      fc->ptr_size = eh_addr_size;
+      fc->segment_size = 0;
+    }
+  fc->code_factor = LEB ();
+  fc->data_factor = SLEB ();
+  if (version == 1)
+    {
+      GET (fc->ra, 1);
+    }
+  else
+    {
+      fc->ra = LEB ();
+    }
+
+  if (fc->augmentation[0] == 'z')
+    {
+      augmentation_data_len = LEB ();
+      augmentation_data = start;
+      start += augmentation_data_len;
+    }
+
+  if (augmentation_data_len)
+    {
+      unsigned char *p, *q;
+      p = (unsigned char *) fc->augmentation + 1;
+      q = augmentation_data;
+
+      while (1)
+	{
+	  if (*p == 'L')
+	    q++;
+	  else if (*p == 'P')
+	    q += 1 + size_of_encoded_value (*q);
+	  else if (*p == 'R')
+	    fc->fde_encoding = *q++;
+	  else if (*p == 'S')
+	    ;
+	  else
+	    break;
+	  p++;
+	}
+    }
+
+  *p_cie = fc;
+  if (p_version)
+    *p_version = version;
+  if (p_aug_len)
+    {
+      *p_aug_len = augmentation_data_len;
+      *p_aug = augmentation_data;
+    }
+  return start;
+}
+
 static int
 display_debug_frames (struct dwarf_section *section,
 		      void *file ATTRIBUTE_UNUSED)
@@ -5243,7 +5330,7 @@ display_debug_frames (struct dwarf_section *section,
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
   unsigned char *section_start = start;
-  Frame_Chunk *chunks = 0;
+  Frame_Chunk *chunks = 0, *forward_refs = 0;
   Frame_Chunk *remembered_state = 0;
   Frame_Chunk *rs;
   int is_eh = strcmp (section->name, ".eh_frame") == 0;
@@ -5306,55 +5393,20 @@ display_debug_frames (struct dwarf_section *section,
 				   || (offset_size == 8 && cie_id == DW64_CIE_ID)))
 	{
 	  int version;
+	  int mreg;
 
-	  fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
-	  memset (fc, 0, sizeof (Frame_Chunk));
-
+	  start = read_cie (start, end, &cie, &version,
+			    &augmentation_data_len, &augmentation_data);
+	  fc = cie;
 	  fc->next = chunks;
 	  chunks = fc;
 	  fc->chunk_start = saved_start;
-	  fc->ncols = 0;
-	  fc->col_type = (short int *) xmalloc (sizeof (short int));
-	  fc->col_offset = (int *) xmalloc (sizeof (int));
-	  frame_need_space (fc, max_regs - 1);
-
-	  version = *start++;
-
-	  fc->augmentation = (char *) start;
-	  start = (unsigned char *) strchr ((char *) start, '\0') + 1;
-
-	  if (strcmp (fc->augmentation, "eh") == 0)
-	    start += eh_addr_size;
-
-	  if (version >= 4)
-	    {
-	      GET (fc->ptr_size, 1);
-	      GET (fc->segment_size, 1);
-	      eh_addr_size = fc->ptr_size;
-	    }
-	  else
-	    {
-	      fc->ptr_size = eh_addr_size;
-	      fc->segment_size = 0;
-	    }
-	  fc->code_factor = LEB ();
-	  fc->data_factor = SLEB ();
-	  if (version == 1)
-	    {
-	      GET (fc->ra, 1);
-	    }
-	  else
-	    {
-	      fc->ra = LEB ();
-	    }
-
-	  if (fc->augmentation[0] == 'z')
-	    {
-	      augmentation_data_len = LEB ();
-	      augmentation_data = start;
-	      start += augmentation_data_len;
-	    }
-	  cie = fc;
+	  mreg = max_regs - 1;
+	  if (mreg < fc->ra)
+	    mreg = fc->ra;
+	  frame_need_space (fc, mreg);
+	  if (fc->fde_encoding)
+	    encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
 
 	  printf ("\n%08lx ", (unsigned long) (saved_start - section_start));
 	  print_dwarf_vma (length, fc->ptr_size);
@@ -5389,33 +5441,6 @@ display_debug_frames (struct dwarf_section *section,
 		}
 	      putchar ('\n');
 	    }
-
-	  if (augmentation_data_len)
-	    {
-	      unsigned char *p, *q;
-	      p = (unsigned char *) fc->augmentation + 1;
-	      q = augmentation_data;
-
-	      while (1)
-		{
-		  if (*p == 'L')
-		    q++;
-		  else if (*p == 'P')
-		    q += 1 + size_of_encoded_value (*q);
-		  else if (*p == 'R')
-		    fc->fde_encoding = *q++;
-		  else if (*p == 'S')
-		    ;
-		  else
-		    break;
-		  p++;
-		}
-
-	      if (fc->fde_encoding)
-		encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
-	    }
-
-	  frame_need_space (fc, fc->ra);
 	}
       else
 	{
@@ -5423,14 +5448,70 @@ display_debug_frames (struct dwarf_section *section,
 	  static Frame_Chunk fde_fc;
 	  unsigned long segment_selector;
 
-	  fc = & fde_fc;
-	  memset (fc, 0, sizeof (Frame_Chunk));
+	  if (is_eh)
+	    {
+	      dwarf_vma sign = (dwarf_vma) 1 << (offset_size * 8 - 1);
+	      look_for = start - 4 - ((cie_id ^ sign) - sign);
+	    }
+	  else
+	    look_for = section_start + cie_id;
+
+	  if (look_for <= saved_start)
+	    {
+	      for (cie = chunks; cie ; cie = cie->next)
+		if (cie->chunk_start == look_for)
+		  break;
+	    }
+	  else
+	    {
+	      for (cie = forward_refs; cie ; cie = cie->next)
+		if (cie->chunk_start == look_for)
+		  break;
+	      if (!cie)
+		{
+		  unsigned int off_size;
+		  unsigned char *cie_scan;
 
-	  look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
+		  cie_scan = look_for;
+		  off_size = 4;
+		  SAFE_BYTE_GET_AND_INC (length, cie_scan, 4, end);
+		  if (length == 0xffffffff)
+		    {
+		      SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
+		      off_size = 8;
+		    }
+		  if (length != 0)
+		    {
+		      dwarf_vma c_id;
 
-	  for (cie = chunks; cie ; cie = cie->next)
-	    if (cie->chunk_start == look_for)
-	      break;
+		      SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size, end);
+		      if (is_eh
+			  ? c_id == 0
+			  : ((off_size == 4 && c_id == DW_CIE_ID)
+			     || (off_size == 8 && c_id == DW64_CIE_ID)))
+			{
+			  int version;
+			  int mreg;
+
+			  read_cie (cie_scan, end, &cie, &version,
+				    &augmentation_data_len, &augmentation_data);
+			  cie->next = forward_refs;
+			  forward_refs = cie;
+			  cie->chunk_start = look_for;
+			  mreg = max_regs - 1;
+			  if (mreg < cie->ra)
+			    mreg = cie->ra;
+			  frame_need_space (cie, mreg);
+			  if (cie->fde_encoding)
+			    encoded_ptr_size
+			      = size_of_encoded_value (cie->fde_encoding);
+			}
+		    }
+		}
+	    }
+
+	  fc = &fde_fc;
+	  memset (fc, 0, sizeof (Frame_Chunk));
 
 	  if (!cie)
 	    {

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]