* readelf.c (do_debug_frames_interp): New.
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 2f03f4a919cc3c56b66e251ce5530d4e6d61bd79..e8cf75eb65ab4ed25c2a1007b523ad13aac4fd5f 100644 (file)
@@ -118,6 +118,7 @@ int                     do_debug_lines;
 int                     do_debug_pubnames;
 int                     do_debug_aranges;
 int                     do_debug_frames;
+int                     do_debug_frames_interp;
 int                     do_arch;
 int                     do_notes;
 int                    is_32bit_elf;
@@ -376,11 +377,13 @@ byte_get_little_endian (field, size)
       return  ((unsigned int) (field [0]))
        |    (((unsigned int) (field [1])) << 8);
 
+#ifndef BFD64
     case 8:
       /* We want to extract data from an 8 byte wide field and
         place it into a 4 byte wide field.  Since this is a little
         endian source we can juts use the 4 byte extraction code.  */
       /* Fall through.  */
+#endif
     case 4:
       return  ((unsigned long) (field [0]))
        |    (((unsigned long) (field [1])) << 8)
@@ -388,6 +391,7 @@ byte_get_little_endian (field, size)
        |    (((unsigned long) (field [3])) << 24);
 
 #ifdef BFD64
+    case 8:
     case -8:
       /* This is a special case, generated by the BYTE_GET8 macro.
         It means that we are loading an 8 byte value from a field
@@ -516,6 +520,7 @@ byte_get_big_endian (field, size)
        |   (((unsigned long) (field [1])) << 16)
        |   (((unsigned long) (field [0])) << 24);
 
+#ifndef BFD64
     case 8:
       /* Although we are extracing data from an 8 byte wide field, we
         are returning only 4 bytes of data.  */
@@ -523,8 +528,8 @@ byte_get_big_endian (field, size)
        |   (((unsigned long) (field [6])) << 8)
        |   (((unsigned long) (field [5])) << 16)
        |   (((unsigned long) (field [4])) << 24);
-
-#ifdef BFD64
+#else
+    case 8:
     case -8:
       /* This is a special case, generated by the BYTE_GET8 macro.
         It means that we are loading an 8 byte value from a field
@@ -2164,8 +2169,9 @@ parse_args (argc, argv)
                  do_debug_aranges = 1;
                  break;
 
-               case 'f':
                case 'F':
+                 do_debug_frames_interp = 1;
+               case 'f':
                  do_debug_frames = 1;
                  break;
 
@@ -2895,7 +2901,8 @@ process_section_headers (file)
                          dynamic_strings, char *, "dynamic strings");
        }
       else if ((do_debugging || do_debug_info || do_debug_abbrevs
-               || do_debug_lines || do_debug_pubnames || do_debug_aranges || do_debug_frames)
+               || do_debug_lines || do_debug_pubnames || do_debug_aranges
+               || do_debug_frames)
               && strncmp (name, ".debug_", 7) == 0)
        {
          name += 7;
@@ -6991,12 +6998,13 @@ typedef struct Frame_Chunk
   int *                col_offset;
   char *               augmentation;
   unsigned int         code_factor;
-  unsigned int         data_factor;
+  int                  data_factor;
   unsigned long        pc_begin;
   unsigned long        pc_range;
   int                  cfa_reg;
   int                  cfa_offset;
   int                  ra;
+  unsigned char        fde_encoding;
 }
 Frame_Chunk;
 
@@ -7058,7 +7066,7 @@ frame_display_row (fc, need_col_headers, max_regs)
       printf ("\n");
     }
 
-  printf ("%08x ", (unsigned int) fc->pc_begin);
+  printf ("%08lx ", fc->pc_begin);
   sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
   printf ("%-8s ", tmp);
 
@@ -7090,6 +7098,20 @@ frame_display_row (fc, need_col_headers, max_regs)
   printf ("\n");
 }
 
+static int
+size_of_encoded_value (encoding)
+     int encoding;
+{
+  switch (encoding & 0x7)
+    {
+    default:   /* ??? */
+    case 0:    return is_32bit_elf ? 4 : 8;
+    case 2:    return 2;
+    case 3:    return 4;
+    case 4:    return 8;
+    }
+}
+
 #define GET(N) byte_get (start, N); start += N
 #define LEB()  read_leb128 (start, & length_return, 0); start += length_return
 #define SLEB() read_leb128 (start, & length_return, 1); start += length_return
@@ -7108,6 +7130,7 @@ display_debug_frames (section, start, file)
   int             is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0);
   int             length_return;
   int             max_regs = 0;
+  int             addr_size = is_32bit_elf ? 4 : 8;
 
   printf (_("The section %s contains:\n"), SECTION_NAME (section));
 
@@ -7120,6 +7143,9 @@ display_debug_frames (section, start, file)
       Frame_Chunk *   fc;
       Frame_Chunk *   cie;
       int             need_col_headers = 1;
+      unsigned char * augmentation_data = NULL;
+      unsigned long   augmentation_data_len = 0;
+      int            encoded_ptr_size = addr_size;
 
       saved_start = start;
       length = byte_get (start, 4); start += 4;
@@ -7130,10 +7156,10 @@ display_debug_frames (section, start, file)
       block_end = saved_start + length + 4;
       cie_id = byte_get (start, 4); start += 4;
 
-      printf ("\n%08x %08lx %08lx ", saved_start - section_start, length, cie_id);
-
       if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
        {
+         int version;
+
          fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
          memset (fc, 0, sizeof (Frame_Chunk));
 
@@ -7145,27 +7171,23 @@ display_debug_frames (section, start, file)
          fc->col_offset = (int *) xmalloc (sizeof (int));
          frame_need_space (fc, max_regs-1);
 
-         start ++; /* version */
-         fc->augmentation = start;
-
-         while (* start)
-           start++;
+         version = *start++;
 
-         start++; /* skip past NUL */
+         fc->augmentation = start;
+         start = strchr (start, '\0') + 1;
 
          if (fc->augmentation[0] == 'z')
            {
-             int xtra;
              fc->code_factor = LEB ();
              fc->data_factor = SLEB ();
              fc->ra = byte_get (start, 1); start += 1;
-             xtra = LEB ();
-             printf ("skipping %d extra bytes\n", xtra);
-             start += xtra;
+             augmentation_data_len = LEB ();
+             augmentation_data = start;
+             start += augmentation_data_len;
            }
          else if (strcmp (fc->augmentation, "eh") == 0)
            {
-             start += 4;
+             start += addr_size;
              fc->code_factor = LEB ();
              fc->data_factor = SLEB ();
              fc->ra = byte_get (start, 1); start += 1;
@@ -7177,8 +7199,55 @@ display_debug_frames (section, start, file)
              fc->ra = byte_get (start, 1); start += 1;
            }
          cie = fc;
-         printf ("CIE \"%s\" cf=%d df=%d ra=%d\n",
-                 fc->augmentation, fc->code_factor, fc->data_factor, fc->ra);
+
+         if (do_debug_frames_interp)
+           printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n",
+                   saved_start - section_start, length, cie_id,
+                   fc->augmentation, fc->code_factor, fc->data_factor,
+                   fc->ra);
+         else
+           {
+             printf ("\n%08lx %08lx %08lx CIE\n",
+                     saved_start - section_start, length, cie_id);
+             printf ("  Version:               %d\n", version);
+             printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
+             printf ("  Code alignment factor: %u\n", fc->code_factor);
+             printf ("  Data alignment factor: %d\n", fc->data_factor);
+             printf ("  Return address column: %d\n", fc->ra);
+
+             if (augmentation_data_len)
+               {
+                 unsigned long i;
+                 printf ("  Augmentation data:    ");
+                 for (i = 0; i < augmentation_data_len; ++i)
+                   printf (" %02x", augmentation_data[i]);
+                 putchar ('\n');
+               }
+             putchar ('\n');
+           }
+
+         if (augmentation_data_len)
+           {
+             unsigned char *p, *q;
+             p = 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
+                   break;
+                 p++;
+               }
+
+             if (fc->fde_encoding)
+               encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
+           }
 
          frame_need_space (fc, fc->ra);
        }
@@ -7186,19 +7255,21 @@ display_debug_frames (section, start, file)
        {
          unsigned char *    look_for;
          static Frame_Chunk fde_fc;
+         int size;
 
          fc = & fde_fc;
          memset (fc, 0, sizeof (Frame_Chunk));
 
-         look_for = is_eh ? start-4-cie_id : (unsigned char *) cie_id;
+         look_for = is_eh ? start - 4 - cie_id : section_start + cie_id;
 
-         fc->pc_begin = byte_get (start, 4); start += 4;
-         fc->pc_range = byte_get (start, 4); start += 4;
+         for (cie=chunks; cie ; cie = cie->next)
+           if (cie->chunk_start == look_for)
+             break;
 
-         for (cie=chunks; cie && (cie->chunk_start != look_for); cie = cie->next);
          if (!cie)
            {
-             warn ("Invalid CIE pointer %08x in FDE at %08x\n", cie_id, saved_start);
+             warn ("Invalid CIE pointer %08lx in FDE at %08lx\n",
+                   cie_id, saved_start);
              start = block_end;
              fc->ncols = 0;
              fc->col_type = (short int *) xmalloc (sizeof (short int));
@@ -7206,6 +7277,7 @@ display_debug_frames (section, start, file)
              frame_need_space (fc, max_regs - 1);
              cie = fc;
              fc->augmentation = "";
+             fc->fde_encoding = 0;
            }
          else
            {
@@ -7221,25 +7293,43 @@ display_debug_frames (section, start, file)
              fc->cfa_offset = cie->cfa_offset;
              fc->ra = cie->ra;
              frame_need_space (fc, max_regs-1);
+             fc->fde_encoding = cie->fde_encoding;
            }
 
+         if (fc->fde_encoding)
+           encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
+
+         fc->pc_begin = byte_get (start, encoded_ptr_size);
+         start += encoded_ptr_size;
+         fc->pc_range = byte_get (start, encoded_ptr_size);
+         start += encoded_ptr_size;
+
          if (cie->augmentation[0] == 'z')
            {
-             unsigned long l = LEB ();
-             start += l;
+             augmentation_data_len = LEB ();
+             augmentation_data = start;
+             start += augmentation_data_len;
            }
 
-         printf ("FDE cie=%08x pc=%08lx..%08lx\n",
-                 cie->chunk_start-section_start, fc->pc_begin,
+         printf ("\n%08lx %08lx %08lx FDE cie=%08x pc=%08lx..%08lx\n",
+                 saved_start - section_start, length, cie_id, 
+                 cie->chunk_start - section_start, fc->pc_begin,
                  fc->pc_begin + fc->pc_range);
+         if (! do_debug_frames_interp && augmentation_data_len)
+           {
+             unsigned long i;
+             printf ("  Augmentation data:    ");
+             for (i = 0; i < augmentation_data_len; ++i)
+               printf (" %02x", augmentation_data[i]);
+             putchar ('\n');
+             putchar ('\n');
+           }
        }
 
       /* At this point, fc is the current chunk, cie (if any) is set, and we're
         about to interpret instructions for the chunk.  */
 
-      /* This exists for readelf maintainers.  */
-#define FDEBUG 0
-
+      if (do_debug_frames_interp)
       {
        /* Start by making a pass over the chunk, allocating storage
            and taking note of what registers are used.  */
@@ -7272,7 +7362,7 @@ display_debug_frames (section, start, file)
                fc->col_type[opa] = DW_CFA_undefined;
                break;
              case DW_CFA_set_loc:
-               start += sizeof (vma);
+               start += encoded_ptr_size;
                break;
              case DW_CFA_advance_loc1:
                start += 1;
@@ -7358,103 +7448,104 @@ display_debug_frames (section, start, file)
          switch (op)
            {
            case DW_CFA_advance_loc:
-             frame_display_row (fc, &need_col_headers, &max_regs);
-#if FDEBUG
-             printf ("  DW_CFA_advance_loc: %08x = %08x + %d*%d\n",
-                     fc->pc_begin + opa * fc->code_factor, fc->pc_begin, opa, fc->code_factor);
-#endif
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_advance_loc: %d to %08lx\n",
+                       opa * fc->code_factor,
+                       fc->pc_begin + opa * fc->code_factor);
              fc->pc_begin += opa * fc->code_factor;
              break;
 
            case DW_CFA_offset:
              roffs = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_offset: r%d = cfa[%d*%d]\n", opa, roffs, fc->data_factor);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_offset: r%d at cfa%+d\n",
+                       opa, roffs * fc->data_factor);
              fc->col_type[opa] = DW_CFA_offset;
              fc->col_offset[opa] = roffs * fc->data_factor;
              break;
 
            case DW_CFA_restore:
-#if FDEBUG
-             printf ("  DW_CFA_restore: r%d\n", opa);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_restore: r%d\n", opa);
              fc->col_type[opa] = cie->col_type[opa];
              fc->col_offset[opa] = cie->col_offset[opa];
              break;
 
            case DW_CFA_set_loc:
-             frame_display_row (fc, &need_col_headers, &max_regs);
-             vma = byte_get (start, sizeof (vma)); start += sizeof (vma);
-#if FDEBUG
-             printf ("  DW_CFA_set_loc: %08x\n", vma);
-#endif
+             vma = byte_get (start, encoded_ptr_size);
+             start += encoded_ptr_size;
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_set_loc: %08x\n", vma);
              fc->pc_begin = vma;
              break;
 
            case DW_CFA_advance_loc1:
-             frame_display_row (fc, &need_col_headers, &max_regs);
              ofs = byte_get (start, 1); start += 1;
-#if FDEBUG
-             printf ("  DW_CFA_advance_loc1: %08x = %08x + %d*%d\n",
-                     fc->pc_begin + ofs * fc->code_factor, fc->pc_begin, ofs, fc->code_factor);
-#endif
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_advance_loc1: %d to %08lx\n",
+                       ofs * fc->code_factor,
+                       fc->pc_begin + ofs * fc->code_factor);
              fc->pc_begin += ofs * fc->code_factor;
              break;
 
            case DW_CFA_advance_loc2:
-             frame_display_row (fc, &need_col_headers, &max_regs);
              ofs = byte_get (start, 2); start += 2;
-#if FDEBUG
-             printf ("  DW_CFA_advance_loc2: %08x = %08x + %d*%d\n",
-                     fc->pc_begin + ofs * fc->code_factor, fc->pc_begin, ofs, fc->code_factor);
-#endif
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_advance_loc2: %d to %08lx\n",
+                       ofs * fc->code_factor,
+                       fc->pc_begin + ofs * fc->code_factor);
              fc->pc_begin += ofs * fc->code_factor;
              break;
 
            case DW_CFA_advance_loc4:
-             frame_display_row (fc, &need_col_headers, &max_regs);
              ofs = byte_get (start, 4); start += 4;
-#if FDEBUG
-             printf ("  DW_CFA_advance_loc4: %08x = %08x + %d*%d\n",
-                     fc->pc_begin + ofs * fc->code_factor, fc->pc_begin, ofs, fc->code_factor);
-#endif
+             if (do_debug_frames_interp)
+               frame_display_row (fc, &need_col_headers, &max_regs);
+             else
+               printf ("  DW_CFA_advance_loc4: %d to %08lx\n",
+                       ofs * fc->code_factor,
+                       fc->pc_begin + ofs * fc->code_factor);
              fc->pc_begin += ofs * fc->code_factor;
              break;
 
            case DW_CFA_offset_extended:
              reg = LEB ();
              roffs = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_offset_extended: r%d = cfa[%d*%d]\n", reg, roffs, fc->data_factor);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_offset_extended: r%d at cfa%+d\n",
+                       reg, roffs * fc->data_factor);
              fc->col_type[reg] = DW_CFA_offset;
              fc->col_offset[reg] = roffs * fc->data_factor;
              break;
 
            case DW_CFA_restore_extended:
              reg = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_restore_extended: r%d\n", reg);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_restore_extended: r%d\n", reg);
              fc->col_type[reg] = cie->col_type[reg];
              fc->col_offset[reg] = cie->col_offset[reg];
              break;
 
            case DW_CFA_undefined:
              reg = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_undefined: r%d\n", reg);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_undefined: r%d\n", reg);
              fc->col_type[reg] = DW_CFA_undefined;
              fc->col_offset[reg] = 0;
              break;
 
            case DW_CFA_same_value:
              reg = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_same_value: r%d\n", reg);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_same_value: r%d\n", reg);
              fc->col_type[reg] = DW_CFA_same_value;
              fc->col_offset[reg] = 0;
              break;
@@ -7462,17 +7553,15 @@ display_debug_frames (section, start, file)
            case DW_CFA_register:
              reg = LEB ();
              roffs = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_register: r%d\n", reg);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_register: r%d\n", reg);
              fc->col_type[reg] = DW_CFA_register;
              fc->col_offset[reg] = roffs;
              break;
 
            case DW_CFA_remember_state:
-#if FDEBUG
-             printf ("  DW_CFA_remember_state\n");
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_remember_state\n");
              rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
              rs->ncols = fc->ncols;
              rs->col_type = (short int *) xmalloc (rs->ncols * sizeof (short int));
@@ -7484,9 +7573,8 @@ display_debug_frames (section, start, file)
              break;
 
            case DW_CFA_restore_state:
-#if FDEBUG
-             printf ("  DW_CFA_restore_state\n");
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_restore_state\n");
              rs = remembered_state;
              remembered_state = rs->next;
              frame_need_space (fc, rs->ncols-1);
@@ -7500,60 +7588,49 @@ display_debug_frames (section, start, file)
            case DW_CFA_def_cfa:
              fc->cfa_reg = LEB ();
              fc->cfa_offset = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_def_cfa: reg %d ofs %d\n", fc->cfa_reg, fc->cfa_offset);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_def_cfa: r%d ofs %d\n",
+                       fc->cfa_reg, fc->cfa_offset);
              break;
 
            case DW_CFA_def_cfa_register:
              fc->cfa_reg = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_def_cfa_reg: %d\n", fc->cfa_reg);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
              break;
 
            case DW_CFA_def_cfa_offset:
              fc->cfa_offset = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
              break;
 
            case DW_CFA_nop:
-#if FDEBUG
-             printf ("  DW_CFA_nop\n");
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_nop\n");
              break;
 
 #ifndef DW_CFA_GNU_window_save
 #define DW_CFA_GNU_window_save 0x2d
 #endif
            case DW_CFA_GNU_window_save:
-#if FDEBUG
-             printf ("  DW_CFA_GNU_window_save\n");
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_GNU_window_save\n");
              break;
 
-#ifndef DW_CFA_GNU_args_size
-#define DW_CFA_GNU_args_size 0x2e
-#endif
            case DW_CFA_GNU_args_size:
              ul = LEB ();
-#if FDEBUG
-             printf ("  DW_CFA_GNU_args_size: %d\n", ul);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_GNU_args_size: %d\n", ul);
              break;
 
-#ifndef DW_CFA_GNU_negative_offset_extended
-#define DW_CFA_GNU_negative_offset_extended 0x2f
-#endif
            case DW_CFA_GNU_negative_offset_extended:
              reg = LEB ();
              l = - LEB ();
              frame_need_space (fc, reg);
-#if FDEBUG
-             printf ("  DW_CFA_GNU_negative_offset_extended: r%d = cfa[%d*%d]\n", reg, l, fc->data_factor);
-#endif
+             if (! do_debug_frames_interp)
+               printf ("  DW_CFA_GNU_negative_offset_extended: r%d at cfa%+d\n",
+                       reg, l * fc->data_factor);
              fc->col_type[reg] = DW_CFA_offset;
              fc->col_offset[reg] = l * fc->data_factor;
              break;
@@ -7564,7 +7641,8 @@ display_debug_frames (section, start, file)
            }
        }
 
-      frame_display_row (fc, &need_col_headers, &max_regs);
+      if (do_debug_frames_interp)
+        frame_display_row (fc, &need_col_headers, &max_regs);
 
       start = block_end;
     }
@@ -7627,7 +7705,6 @@ debug_displays[] =
   { ".debug_frame",       display_debug_frames, NULL },
   { ".eh_frame",          display_debug_frames, NULL },
   { ".debug_macinfo",     display_debug_not_supported, NULL },
-  { ".debug_frame",       display_debug_not_supported, NULL },
   { ".debug_str",         display_debug_not_supported, NULL },
   { ".debug_static_func", display_debug_not_supported, NULL },
   { ".debug_static_vars", display_debug_not_supported, NULL },
This page took 0.031939 seconds and 4 git commands to generate.