PR29250, readelf erases CIE initial register state
authorAlan Modra <amodra@gmail.com>
Wed, 15 Jun 2022 13:00:51 +0000 (22:30 +0930)
committerAlan Modra <amodra@gmail.com>
Thu, 16 Jun 2022 00:24:55 +0000 (09:54 +0930)
PR 29250
binutils/
* dwarf.c (display_debug_frames): Set col_type[reg] on sizing
pass over FDE to cie->col_type[reg] if CIE specifies reg.
Handle DW_CFA_restore and DW_CFA_restore_extended on second
pass using the same logic.  Remove unnecessary casts.  Don't
call frame_need_space on second pass over FDE.
gas/
* testsuite/gas/i386/ehinterp.d,
* testsuite/gas/i386/ehinterp.s: New test.
* testsuite/gas/i386/i386.exp: Run it.

binutils/dwarf.c
gas/testsuite/gas/i386/ehinterp.d [new file with mode: 0644]
gas/testsuite/gas/i386/ehinterp.s [new file with mode: 0644]
gas/testsuite/gas/i386/i386.exp

index c16f5a891b7b9c4402b2d0843d52eaf3235da09a..f11eeaa24ce51dd9a8157f13c2e840f861529969 100644 (file)
@@ -9306,18 +9306,17 @@ display_debug_frames (struct dwarf_section *section,
 
              /* Warning: if you add any more cases to this switch, be
                 sure to add them to the corresponding switch below.  */
+             reg = -1u;
              switch (op)
                {
                case DW_CFA_advance_loc:
                  break;
                case DW_CFA_offset:
                  SKIP_ULEB (start, block_end);
-                 if (frame_need_space (fc, opa) >= 0)
-                   fc->col_type[opa] = DW_CFA_undefined;
+                 reg = opa;
                  break;
                case DW_CFA_restore:
-                 if (frame_need_space (fc, opa) >= 0)
-                   fc->col_type[opa] = DW_CFA_undefined;
+                 reg = opa;
                  break;
                case DW_CFA_set_loc:
                  if ((size_t) (block_end - start) < encoded_ptr_size)
@@ -9347,29 +9346,19 @@ display_debug_frames (struct dwarf_section *section,
                case DW_CFA_val_offset:
                  READ_ULEB (reg, start, block_end);
                  SKIP_ULEB (start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_restore_extended:
                  READ_ULEB (reg, start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_undefined:
                  READ_ULEB (reg, start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_same_value:
                  READ_ULEB (reg, start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_register:
                  READ_ULEB (reg, start, block_end);
                  SKIP_ULEB (start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa:
                  SKIP_ULEB (start, block_end);
@@ -9396,15 +9385,11 @@ display_debug_frames (struct dwarf_section *section,
                    start = block_end;
                  else
                    start += temp;
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_offset_extended_sf:
                case DW_CFA_val_offset_sf:
                  READ_ULEB (reg, start, block_end);
                  SKIP_SLEB (start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa_sf:
                  SKIP_ULEB (start, block_end);
@@ -9425,12 +9410,21 @@ display_debug_frames (struct dwarf_section *section,
                case DW_CFA_GNU_negative_offset_extended:
                  READ_ULEB (reg, start, block_end);
                  SKIP_ULEB (start, block_end);
-                 if (frame_need_space (fc, reg) >= 0)
-                   fc->col_type[reg] = DW_CFA_undefined;
                  break;
                default:
                  break;
                }
+             if (reg != -1u && frame_need_space (fc, reg) >= 0)
+               {
+                 /* Don't leave any reg as DW_CFA_unreferenced so
+                    that frame_display_row prints name of regs in
+                    header, and all referenced regs in each line.  */
+                 if (reg >= cie->ncols
+                     || cie->col_type[reg] == DW_CFA_unreferenced)
+                   fc->col_type[reg] = DW_CFA_undefined;
+                 else
+                   fc->col_type[reg] = cie->col_type[reg];
+               }
            }
          start = tmp;
        }
@@ -9480,7 +9474,7 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_offset:
              READ_ULEB (roffs, start, block_end);
-             if (opa >= (unsigned int) fc->ncols)
+             if (opa >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_offset: %s%s at cfa%+ld\n",
@@ -9494,7 +9488,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_restore:
-             if (opa >= (unsigned int) fc->ncols)
+             if (opa >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_restore: %s%s\n",
@@ -9502,9 +9496,8 @@ display_debug_frames (struct dwarf_section *section,
              if (*reg_prefix != '\0')
                break;
 
-             if (opa >= (unsigned int) cie->ncols
-                 || (do_debug_frames_interp
-                     && cie->col_type[opa] == DW_CFA_unreferenced))
+             if (opa >= cie->ncols
+                 || cie->col_type[opa] == DW_CFA_unreferenced)
                {
                  fc->col_type[opa] = DW_CFA_undefined;
                  fc->col_offset[opa] = 0;
@@ -9569,7 +9562,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_offset_extended:
              READ_ULEB (reg, start, block_end);
              READ_ULEB (roffs, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_offset_extended: %s%s at cfa%+ld\n",
@@ -9585,7 +9578,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_val_offset:
              READ_ULEB (reg, start, block_end);
              READ_ULEB (roffs, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_val_offset: %s%s is cfa%+ld\n",
@@ -9600,7 +9593,7 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_restore_extended:
              READ_ULEB (reg, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_restore_extended: %s%s\n",
@@ -9608,7 +9601,8 @@ display_debug_frames (struct dwarf_section *section,
              if (*reg_prefix != '\0')
                break;
 
-             if (reg >= (unsigned int) cie->ncols)
+             if (reg >= cie->ncols
+                 || cie->col_type[reg] == DW_CFA_unreferenced)
                {
                  fc->col_type[reg] = DW_CFA_undefined;
                  fc->col_offset[reg] = 0;
@@ -9622,7 +9616,7 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_undefined:
              READ_ULEB (reg, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_undefined: %s%s\n",
@@ -9636,7 +9630,7 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_same_value:
              READ_ULEB (reg, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_same_value: %s%s\n",
@@ -9651,7 +9645,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_register:
              READ_ULEB (reg, start, block_end);
              READ_ULEB (roffs, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                {
@@ -9761,7 +9755,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_expression:
              READ_ULEB (reg, start, block_end);
              READ_ULEB (ul, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              /* PR 17512: file: 069-133014-0.006.  */
              /* PR 17512: file: 98c02eb4.  */
@@ -9786,7 +9780,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_val_expression:
              READ_ULEB (reg, start, block_end);
              READ_ULEB (ul, start, block_end);
-             if (reg >= (unsigned int) fc->ncols)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (ul > (size_t) (block_end - start))
                {
@@ -9809,7 +9803,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_offset_extended_sf:
              READ_ULEB (reg, start, block_end);
              READ_SLEB (l, start, block_end);
-             if (frame_need_space (fc, reg) < 0)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
@@ -9825,7 +9819,7 @@ display_debug_frames (struct dwarf_section *section,
            case DW_CFA_val_offset_sf:
              READ_ULEB (reg, start, block_end);
              READ_SLEB (l, start, block_end);
-             if (frame_need_space (fc, reg) < 0)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_val_offset_sf: %s%s is cfa%+ld\n",
@@ -9885,7 +9879,7 @@ display_debug_frames (struct dwarf_section *section,
              READ_ULEB (reg, start, block_end);
              READ_SLEB (l, start, block_end);
              l = - l;
-             if (frame_need_space (fc, reg) < 0)
+             if (reg >= fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
diff --git a/gas/testsuite/gas/i386/ehinterp.d b/gas/testsuite/gas/i386/ehinterp.d
new file mode 100644 (file)
index 0000000..5b6ac85
--- /dev/null
@@ -0,0 +1,20 @@
+#readelf: --debug-dump=frames-interp
+
+Contents of the \.eh_frame section:
+
+0+ 0+14 0+ CIE "zR" cf=1 df=-8 ra=16
+ +LOC +CFA +ra *
+0+ rsp\+8 +c-8 *
+
+0+18 0+10 0+1c FDE cie=0+ pc=0+..0+6
+ +LOC +CFA +ra *
+0+ rsp\+8 +c-8 *
+0+4 rsp\+8 +u *
+
+0+2c 0+20 0+30 FDE cie=0+ pc=0+6..0+24
+ +LOC +CFA +rbp +ra *
+0+6 rsp\+8 +u +c-8 *
+0+b rsp\+16 +c-16 +c-8 *
+0+e rbp\+16 +c-16 +c-8 *
+0+23 rsp\+8 +c-16 +c-8 *
+
diff --git a/gas/testsuite/gas/i386/ehinterp.s b/gas/testsuite/gas/i386/ehinterp.s
new file mode 100644 (file)
index 0000000..634cef1
--- /dev/null
@@ -0,0 +1,35 @@
+       .file   "hello.c"
+       .text
+       .section        .rodata
+.LC0:
+       .string "Hello"
+       .text
+       .globl  dummy
+       .type   dummy, @function
+dummy:
+       .cfi_startproc
+       endbr64
+       .cfi_undefined rip
+       jmp .
+       .cfi_endproc
+       .size   dummy, .-dummy
+
+       .globl  main
+       .type   main, @function
+main:
+       .cfi_startproc
+       endbr64
+       pushq   %rbp
+       .cfi_def_cfa_offset 16
+       .cfi_offset 6, -16
+       movq    %rsp, %rbp
+       .cfi_def_cfa_register 6
+       leaq    .LC0(%rip), %rax
+       movq    %rax, %rdi
+       call    puts@PLT
+       movl    $0, %eax
+       popq    %rbp
+       .cfi_def_cfa 7, 8
+       ret
+       .cfi_endproc
+       .size   main, .-main
index 99a11ebde787776549eddd757c2d46700e05419d..a4fc5b4096bcafb2e95e368e17ccff253fe8da82 100644 (file)
@@ -1339,7 +1339,7 @@ if [gas_64_check] then {
        if {[istarget "*-*-linux*"]} then {
            run_dump_test "x86-64-align-branch-3"
        }
-
+       run_dump_test ehinterp
     }
     run_dump_test pr27198