]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/symtab] Bail out for too short line header
authorTom de Vries <tdevries@suse.de>
Wed, 3 Dec 2025 07:58:13 +0000 (08:58 +0100)
committerTom de Vries <tdevries@suse.de>
Wed, 3 Dec 2025 07:58:13 +0000 (08:58 +0100)
The Free Pascal Compiler fpc supports generating different versions of DWARF:
...
$ fpc -h
Free Pascal Compiler version 3.2.2 [2025/09/10] for x86_64
  ...
      -gw        Generate DWARFv2 debug information (same as -gw2)
      -gw2       Generate DWARFv2 debug information
      -gw3       Generate DWARFv3 debug information
      -gw4       Generate DWARFv4 debug information (experimental)
...

The v4 support is experimental, and indeed the line number information is
broken (missing maximum_operations_per_instruction field in the .debug_line
header), so setting a breakpoint on a line number is not possible:
...
$ fpc -gw4 hello.pas
  ...
$ gdb -q hello
Reading symbols from hello...
(gdb) b hello.pas:8
No compiled code for line 8 in file "hello.pas".
Make breakpoint pending on future shared library load? (y or [n])
...

The brokenness is detected by llvm-dwarfdump (second warning):
...
$ llvm-dwarfdump -debug-line hello
hello: file format elf64-x86-64

.debug_line contents:
debug_line[0x00000000]
warning: parsing line table prologue at offset 0x0 found opcode base of 0. \
  Assuming no standard opcodes
warning: unknown data in line table prologue at offset 0x0: parsing ended (at \
  offset 0x00000017) before reaching the prologue end at offset 0x2a
...

Likewise, detect the situation the second warning describes in
dwarf_decode_line_header, getting us instead:
...
(gdb) b hello.pas:8
āŒmalformed line number program header, advertised length does not match \
  actual length
(gdb)
...

Tested on x86_64-linux.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
gdb/dwarf2/line-header.c
gdb/testsuite/gdb.dwarf2/malformed-line-header.exp [new file with mode: 0644]
gdb/testsuite/lib/dwarf.exp

index 46523069337384b9414a03bb075fa4cb0e1d9866..d2cd06c4a3b38da28a72f326b3d86c213e0efdcf 100644 (file)
@@ -415,5 +415,9 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
     complaint (_("line number info header doesn't "
                 "fit in `.debug_line' section"));
 
+  if (line_ptr != lh->statement_program_start)
+    error (_("malformed line number program header, advertised length does"
+            " not match actual length"));
+
   return lh;
 }
diff --git a/gdb/testsuite/gdb.dwarf2/malformed-line-header.exp b/gdb/testsuite/gdb.dwarf2/malformed-line-header.exp
new file mode 100644 (file)
index 0000000..4f8e76d
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check handling of v3 .debug_line header advertised as v4, as produced by
+# fpc <= v3.2.4.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support the DWARF
+# assembler.
+require dwarf2_support
+
+standard_testfile main.c -dw.S
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    declare_labels Llines
+
+    cu {} {
+       compile_unit {
+           DW_AT_language @DW_LANG_C
+           DW_AT_name $::srcfile
+           DW_AT_stmt_list $Llines DW_FORM_sec_offset
+       } {
+       }
+    }
+
+    lines {
+       version 3
+       advertised_version 4
+    } Llines {
+       include_dir "$::srcdir/$::subdir"
+       file_name "$::srcfile" 1
+    }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+         [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+gdb_test "info line 1" \
+    [string cat \
+        "malformed line number program header," \
+        " advertised length does not match actual length"]
index acec46df71cbabd7dafd3e86a7b93740524e0053..96a6d28d507efa32a31484b06e037a2f2f5cb124 100644 (file)
@@ -2458,8 +2458,11 @@ namespace eval Dwarf {
     # Current options are:
     # is_64 0|1    - boolean indicating if you want to emit 64-bit DWARF
     #                default = 0 (32-bit)
-    # version n    - DWARF version number to emit
+    # version n    - DWARF version to determine .debug_line format
     #                default = 4
+    # advertised_version n
+    #              - DWARF version to emit (used only for invalid DWARF)
+    #                default = value provided by <version n>
     # addr_size n  - the size of addresses in bytes: 4, 8, or default
     #                default = default
     # seg_sel_size n
@@ -2487,12 +2490,14 @@ namespace eval Dwarf {
        variable _line_header_finalized
        variable _line_header_end_label
        variable _line_unit_version
+       variable _line_advertised_unit_version
        variable _line_is_64
        variable _line_string_form
 
        # Establish the defaults.
        set _line_is_64 0
        set _line_unit_version 4
+       set _line_advertised_unit_version default
        set _unit_addr_size default
        set _line_include_dirs {}
        set _line_file_names {}
@@ -2506,6 +2511,7 @@ namespace eval Dwarf {
            switch -exact -- $name {
                is_64 { set _line_is_64 $value }
                version { set _line_unit_version $value }
+               advertised_version { set _line_unit_advertised_version $value }
                addr_size { set _unit_addr_size $value }
                seg_sel_size { set _seg_sel_size $value }
                default_is_stmt { set _default_is_stmt $value }
@@ -2520,6 +2526,9 @@ namespace eval Dwarf {
                set _unit_addr_size 4
            }
        }
+       if {$_line_unit_advertised_version == "default"} {
+           set _line_unit_advertised_version $_line_unit_version
+       }
 
        set unit_num [incr _line_count]
 
@@ -2545,7 +2554,7 @@ namespace eval Dwarf {
 
        define_label $unit_len_label
 
-       _op .2byte $_line_unit_version version
+       _op .2byte $_line_unit_advertised_version version
 
        if { $_line_unit_version >= 5 } {
            _op .byte $_unit_addr_size "address_size"