| # Copyright 2024-2026 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/>. |
| |
| # Define an inline function `foo` within the function `main`. The |
| # function `foo` uses DW_AT_low_pc and DW_AT_high_pc to define its |
| # range, except that DW_AT_high_pc is the constant 0. |
| # |
| # This should indicate that there is no code associated with `foo`, |
| # however, with gcc versions at least between 8.x and 14.x (latest at |
| # the time of writing this comment), it is observed that when these |
| # empty inline functions are created, if GDB stops at the address |
| # given in DW_AT_low_pc, then locals associated with the inline |
| # function can usually be read. |
| # |
| # At the very least, stopping at the location of the inline function |
| # means that the user can place a breakpoint on the inline function |
| # and have GDB stop in a suitable location, that alone is helpful. |
| # |
| # This test defines an inline function, places a breakpoint, and then |
| # runs and expects GDB to stop, and report the stop as being inside |
| # the inline function. |
| # |
| # We then check that the next outer frame is `main` as expected, and |
| # that the block for `foo` has been extended to a single byte, which |
| # is how GDB gives the previously empty block some range. |
| |
| load_lib dwarf.exp |
| |
| require dwarf2_support |
| |
| standard_testfile .c .S |
| |
| # Lines we reference in the generated DWARF. |
| set main_decl_line [gdb_get_line_number "main decl line"] |
| set foo_call_line [gdb_get_line_number "foo call line"] |
| |
| get_func_info main |
| |
| set asm_file [standard_output_file $srcfile2] |
| Dwarf::assemble $asm_file { |
| upvar entry_label entry_label |
| |
| declare_labels lines_table inline_func |
| |
| cu { } { |
| DW_TAG_compile_unit { |
| DW_AT_producer "GNU C 14.1.0" |
| DW_AT_language @DW_LANG_C |
| DW_AT_name $::srcfile |
| DW_AT_comp_dir /tmp |
| DW_AT_low_pc 0 addr |
| DW_AT_stmt_list $lines_table DW_FORM_sec_offset |
| } { |
| inline_func: subprogram { |
| DW_AT_name foo |
| DW_AT_inline @DW_INL_declared_inlined |
| } |
| subprogram { |
| DW_AT_name main |
| DW_AT_decl_file 1 data1 |
| DW_AT_decl_line $::main_decl_line data1 |
| DW_AT_decl_column 1 data1 |
| DW_AT_low_pc $::main_start addr |
| DW_AT_high_pc $::main_len data4 |
| DW_AT_external 1 flag |
| } { |
| inlined_subroutine { |
| DW_AT_abstract_origin %$inline_func |
| DW_AT_call_file 1 data1 |
| DW_AT_call_line $::foo_call_line data1 |
| DW_AT_low_pc main_1 addr |
| DW_AT_high_pc 0 data4 |
| } |
| } |
| } |
| } |
| |
| lines {version 2} lines_table { |
| include_dir "$::srcdir/$::subdir" |
| file_name "$::srcfile" 1 |
| } |
| } |
| |
| if {[prepare_for_testing "failed to prepare" $testfile \ |
| [list $srcfile $asm_file] {nodebug}]} { |
| return |
| } |
| |
| if {![runto_main]} { |
| return |
| } |
| |
| gdb_breakpoint foo |
| gdb_test "continue" \ |
| "Breakpoint $decimal, $hex in foo \\(\\)" \ |
| "continue to b/p in foo" |
| |
| set foo_start [get_hexadecimal_valueof "&main_1" "*UNKNOWN*" \ |
| "get address of foo start"] |
| set foo_end [get_hexadecimal_valueof "&main_1 + 1" "*UNKNOWN*" \ |
| "get address of foo end"] |
| |
| gdb_test "maintenance info blocks" \ |
| [multi_line \ |
| "\\\[\\(block \\*\\) $hex\\\] $foo_start\\.\\.$foo_end" \ |
| " entry pc: $foo_start" \ |
| " inline function: foo" \ |
| " symbol count: $decimal" \ |
| " is contiguous"] \ |
| "block for foo has some content" |
| |
| gdb_test "frame 1" \ |
| [multi_line \ |
| "#1 main \\(\\) at \[^\r\n\]+/$srcfile:$foo_call_line" \ |
| "$foo_call_line\\s+\[^\r\n\]+/\\* foo call line \\*/"] \ |
| "frame 1 is for main" |