From: Tom de Vries Date: Wed, 3 Dec 2025 07:58:13 +0000 (+0100) Subject: [gdb/symtab] Bail out for too short line header X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a8ea3fb759651f97e0340c30b200b7389daf436d;p=thirdparty%2Fbinutils-gdb.git [gdb/symtab] Bail out for too short line header 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 --- diff --git a/gdb/dwarf2/line-header.c b/gdb/dwarf2/line-header.c index 46523069337..d2cd06c4a3b 100644 --- a/gdb/dwarf2/line-header.c +++ b/gdb/dwarf2/line-header.c @@ -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 index 00000000000..4f8e76d2f1f --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/malformed-line-header.exp @@ -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 . + +# 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"] diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index acec46df71c..96a6d28d507 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -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 # 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"