[PATCH v3 1/1] dwarf, fortran: add support for DW_TAG_entry_point
Andrew Burgess
aburgess@redhat.com
Mon Jul 11 13:02:31 GMT 2022
Nils-Christian Kempke via Gdb-patches <gdb-patches@sourceware.org>
writes:
> Fortran provides additional entry points for subroutines and functions.
> These entry points may use only a subset (or a different set) of the
> parameters of the original subroutine. The entry points may be described
> via the DWARF tag DW_TAG_entry_point.
>
> This commit adds support for parsing the DW_TAG_entry_point DWARF tag.
> Currently, between ifx/ifort/gfortran, only ifort is actually emitting
> this tag. Both, ifx and gfortran use the DW_TAG_subprogram tag as
> workaround/alternative. Thus, this patch really only adds more ifort
> support. Even so, some of the attached tests still fail for ifort, due
> to some wrong line info generated for the entry points in ifort.
>
> After this patch it is possible to set a breakpoint in gdb with the
> ifort compiled example at the entry points 'foo' and 'foobar', which was not
> possible before.
>
> As gcc and ifx do not emit the tag I also added a test to gdb.dwarf2
> which uses some underlying c compiled code and adds some Fortran style DWARF
> to it emitting the DW_TAG_entry_point. Before this patch it was not
> possible to actually define breakpoint at the entry point tags.
>
> For gfortran there actually exists a bug on bugzilla, asking for the use
> of DW_TAG_entry_point over DW_TAG_subprogram:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37134
>
> This patch was originally posted here
>
> https://sourceware.org/legacy-ml/gdb-patches/2017-07/msg00317.html
>
> but its review/pinging got lost after a while. I reworked it to fit the
> current GDB.
Thanks for the revisions. I took a look through as I have an interest
in Fortran support, and I had some pretty minor feedback. I'm no expert
on the DWARF indexes and CU expansion in GDB, but that side of things
looks reasonable to me - at least I'd be happy to debug this code if
anything came up later.
Anyway, my feedback is inline below.
Thanks,
Andrew
>
> Co-authored-by: Bernhard Heckel <bernhard.heckel@intel.com>
> Co-authored-by: Tim Wiederhake <tim.wiederhake@intel.com>
> ---
> gdb/dwarf2/abbrev.c | 1 +
> gdb/dwarf2/cooked-index.h | 3 +-
> gdb/dwarf2/index-write.c | 3 +-
> gdb/dwarf2/read.c | 72 +++++-
> gdb/testsuite/gdb.dwarf2/dw2-entry-points.c | 39 ++++
> gdb/testsuite/gdb.dwarf2/dw2-entry-points.exp | 215 ++++++++++++++++++
> gdb/testsuite/gdb.fortran/entry-point.exp | 84 +++++++
> gdb/testsuite/gdb.fortran/entry-point.f90 | 67 ++++++
> 8 files changed, 481 insertions(+), 3 deletions(-)
> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-entry-points.c
> create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-entry-points.exp
> create mode 100644 gdb/testsuite/gdb.fortran/entry-point.exp
> create mode 100644 gdb/testsuite/gdb.fortran/entry-point.f90
>
> diff --git a/gdb/dwarf2/abbrev.c b/gdb/dwarf2/abbrev.c
> index 4ca27eaa7e0..f9f87203e3e 100644
> --- a/gdb/dwarf2/abbrev.c
> +++ b/gdb/dwarf2/abbrev.c
> @@ -88,6 +88,7 @@ tag_interesting_for_index (dwarf_tag tag)
> case DW_TAG_base_type:
> case DW_TAG_class_type:
> case DW_TAG_constant:
> + case DW_TAG_entry_point:
> case DW_TAG_enumeration_type:
> case DW_TAG_enumerator:
> case DW_TAG_imported_declaration:
> diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
> index 439cbb19fa7..e63d3001d2a 100644
> --- a/gdb/dwarf2/cooked-index.h
> +++ b/gdb/dwarf2/cooked-index.h
> @@ -113,7 +113,8 @@ struct cooked_index_entry : public allocate_on_obstack
> || tag == DW_TAG_constant
> || tag == DW_TAG_enumerator);
> case FUNCTIONS_DOMAIN:
> - return tag == DW_TAG_subprogram;
> + return (tag == DW_TAG_subprogram
> + || tag == DW_TAG_entry_point);
> case TYPES_DOMAIN:
> return tag_is_type (tag);
> case MODULES_DOMAIN:
> diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
> index c3aad8dd999..a819fd49032 100644
> --- a/gdb/dwarf2/index-write.c
> +++ b/gdb/dwarf2/index-write.c
> @@ -1128,7 +1128,8 @@ write_cooked_index (cooked_index_vector *table,
> const char *name = entry->full_name (&symtab->m_string_obstack);
>
> gdb_index_symbol_kind kind;
> - if (entry->tag == DW_TAG_subprogram)
> + if (entry->tag == DW_TAG_subprogram
> + || entry->tag == DW_TAG_entry_point)
> kind = GDB_INDEX_SYMBOL_KIND_FUNCTION;
> else if (entry->tag == DW_TAG_variable
> || entry->tag == DW_TAG_constant
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 23fe5679cbd..64a255c6487 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -8607,6 +8607,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
> && die->parent->tag == DW_TAG_subprogram)
> cu->processing_has_namespace_info = true;
> /* Fall through. */
> + case DW_TAG_entry_point:
> case DW_TAG_inlined_subroutine:
> read_func_scope (die, cu);
> break;
> @@ -8723,6 +8724,7 @@ die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu)
> case DW_TAG_enumerator:
> case DW_TAG_subprogram:
> case DW_TAG_inlined_subroutine:
> + case DW_TAG_entry_point:
> case DW_TAG_member:
> case DW_TAG_imported_declaration:
> return 1;
> @@ -12994,6 +12996,53 @@ dwarf2_ranges_read_low_addrs (unsigned offset, struct dwarf2_cu *cu,
> });
> }
>
> +/* Determine the low and high pc of a DW_TAG_entry_point. */
> +
> +static pc_bounds_kind
> +dwarf2_get_pc_bounds_entry_point (die_info *die, CORE_ADDR *lowpc,
> + CORE_ADDR *highpc, dwarf2_cu *cu)
> +{
> + CORE_ADDR low = 0;
> + CORE_ADDR high = 0;
> +
> + if (die->parent->tag != DW_TAG_subprogram)
> + {
> + complaint (_("DW_TAG_entry_point not embedded in DW_TAG_subprogram"));
> + return PC_BOUNDS_INVALID;
> + }
> +
> + /* A DW_TAG_entry_point is embedded in an subprogram. Therefore, we can use
> + the highpc from its enveloping subprogram and get the lowpc from
> + DWARF. */
> + const enum pc_bounds_kind bounds_kind = dwarf2_get_pc_bounds (die->parent,
> + &low, &high,
> + cu, nullptr,
> + nullptr);
> + if (bounds_kind == PC_BOUNDS_INVALID || bounds_kind == PC_BOUNDS_NOT_PRESENT)
> + return PC_BOUNDS_INVALID;
Is there a reason why PC_BOUNDS_NOT_PRESENT is transformed to
PC_BOUNDS_INVALID here? I guess I would have expected 'return
bounds_kind' instead.
> +
> + attribute *attr_low = dwarf2_attr (die, DW_AT_low_pc, cu);
> + if (!attr_low)
> + {
> + complaint (_("DW_TAG_entry_point is missing DW_AT_low_pc"));
> + return PC_BOUNDS_INVALID;
> + }
> + low = attr_low->as_address ();
> + if (high <= low)
> + return PC_BOUNDS_INVALID;
> + if (low == 0 && !cu->per_objfile->per_bfd->has_section_at_zero)
> + return PC_BOUNDS_INVALID;
> +
> + if (lowpc)
> + *lowpc = low;
> + if (highpc)
> + *highpc = high;
These should be 'lowpc != nullptr' and 'highpc != nullptr'. We don't
make use of automatic pointer to bool conversion in GDB.
Also, I'm suspicious of the conditional write to *lowpc. There's only
one call to dwarf2_get_pc_bounds_entry_point, from dwarf2_get_pc_bounds,
and that function seems to write unconditionally to lowpc. I'd be more
inclined to just add a 'gdb_assert (lowpc != nullptr)' and then
unconditional write to *lowpc, like dwarf2_get_pc_bounds does.
With that change done, I notice that everything after 'if (high <= low)'
is duplicated between dwarf2_get_pc_bounds_entry_point and
dwarf2_get_pc_bounds, so I wonder if there's any scope to have more code
sharing, I'm thinking something like this:
static enum pc_bounds_kind
dwarf2_get_pc_bounds ( .... )
{
...
enum pc_bounds_kind ret;
if (die->tag == DW_TAG_entry_point)
ret = dwarf2_get_pc_bounds_entry_point (die, lowpc, highpc, cu);
else
ret = dwarf2_get_pc_bounds_???? ( .... );
/* partial_die_info::read has also the strict LOW < HIGH requirement. */
if (high <= low)
return PC_BOUNDS_INVALID;
... etc ...
}
That's a pretty iffy explanation, but hopefully you can see what I'm thinking.
> +
> + /* Return PC_BOUNDS_RANGES/PC_BOUNDS_HIGH_LOW depending on the parent
> + die's bounds kind. */
> + return bounds_kind;
> +}
> +
> /* Get low and high pc attributes from a die. See enum pc_bounds_kind
> definition for the return value. *LOWPC and *HIGHPC are set iff
> neither PC_BOUNDS_NOT_PRESENT nor PC_BOUNDS_INVALID are returned. */
> @@ -13010,6 +13059,9 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
> CORE_ADDR high = 0;
> enum pc_bounds_kind ret;
>
> + if (die->tag == DW_TAG_entry_point)
> + return dwarf2_get_pc_bounds_entry_point (die, lowpc, highpc, cu);
> +
> attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
> if (attr_high)
> {
> @@ -20760,6 +20812,20 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
> sym->set_domain (LABEL_DOMAIN);
> add_symbol_to_list (sym, cu->list_in_scope);
> break;
> + case DW_TAG_entry_point:
> + /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
> + finish_block. */
> + sym->set_aclass_index (LOC_BLOCK);
> + /* DW_TAG_entry_point provides an additional entry_point to an
> + existing sub_program. Therefore, we inherit the "external"
> + attribute from the sub_program to which the entry_point
> + belongs to. */
> + attr2 = dwarf2_attr (die->parent, DW_AT_external, cu);
> + if (attr2 != nullptr && attr2->as_boolean ())
> + list_to_add = cu->get_builder ()->get_global_symbols ();
> + else
> + list_to_add = cu->list_in_scope;
> + break;
> case DW_TAG_subprogram:
> /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
> finish_block. */
> @@ -21464,6 +21530,7 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu)
> case DW_TAG_enumeration_type:
> this_type = read_enumeration_type (die, cu);
> break;
> + case DW_TAG_entry_point:
> case DW_TAG_subprogram:
> case DW_TAG_subroutine_type:
> case DW_TAG_inlined_subroutine:
> @@ -21783,12 +21850,15 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu)
> return "";
> case DW_TAG_subprogram:
> /* Nested subroutines in Fortran get a prefix with the name
> - of the parent's subroutine. */
> + of the parent's subroutine. Entry points are prefixed by the
> + parent's namespace. */
> if (cu->per_cu->lang () == language_fortran)
> {
> if ((die->tag == DW_TAG_subprogram)
> && (dwarf2_name (parent, cu) != NULL))
> return dwarf2_name (parent, cu);
> + else if (die->tag == DW_TAG_entry_point)
> + return determine_prefix (parent, cu);
> }
> return "";
> case DW_TAG_enumeration_type:
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-entry-points.c b/gdb/testsuite/gdb.dwarf2/dw2-entry-points.c
> new file mode 100644
> index 00000000000..e8c99d1f52e
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-entry-points.c
> @@ -0,0 +1,39 @@
> +/* Copyright 2022 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/>. */
> +
> +/* In the generated DWARF, we'll use the locations of foo_entry_label and
> + foobar_entry_label as the low_pc's of our entry point TAGs. */
> +
> +int I = 0;
> +int J = 0;
> +int K = 0;
> +
> +__attribute__((noinline))
> +void bar_helper () {
I think GNU coding standard should be followed here, and throughout this
source, unless the test requires that standard to be broken. So:
void
bar_helper (void)
{
etc.
> + __asm__("bar_helper_label: .globl bar_helper_label");
I notice you used '__asm__' while all the other tests seem to use just
'asm'. Is there a reason for this difference? Also there should be a
space before the '('.
> + I++;
> + J++;
> + __asm__("foo_entry_label: .globl foo_entry_label");
> + J++;
> + K++;
> + __asm__("foobar_entry_label: .globl foobar_entry_label");
> +}
> +
> +int main() {
> + __asm__("main_label: .globl main_label");
> + bar_helper ();
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-entry-points.exp b/gdb/testsuite/gdb.dwarf2/dw2-entry-points.exp
> new file mode 100644
> index 00000000000..1b5ae52fd8a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-entry-points.exp
> @@ -0,0 +1,215 @@
> +# Copyright 2022 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/>.
> +
> +# Test that the DW_TAG_entry_point is handled properly by GDB and that we can
> +# set breakpoints on function entry points.
> +
> +load_lib dwarf.exp
> +
> +# This test can only be run on targets that support DWARF-2 and use
> +# gas.
> +if {![dwarf2_support]} {
> + return 0
> +}
> +
> +standard_testfile .c -dw.S
> +
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> + return -1
> +}
> +
> +set int_size [get_sizeof "int" 4]
I don't think 'int_size' is used, but maybe it should be? Right now,
I/J/K are defined as 4 bytes, but declared as 'int'. You could maybe
declard I/J/K as 'int32_t' and stick with the DWARF hard-coded to 4, or
maybe make use of $int_size to adjust the DWARF for I/J/K...
> +
> +# Make some DWARF for the test.
> +set asm_file [standard_output_file $srcfile2]
> +Dwarf::assemble $asm_file {
> + global srcfile
> + declare_labels int_label int2_label
> +
> + get_func_info main
> + get_func_info bar_helper
> +
> + set prog_line 1
> + set bar_line 2
> + set foo_line 3
> + set foobar_line 4
> +
> + set global_I [gdb_target_symbol I]
> + set global_J [gdb_target_symbol J]
> + set global_K [gdb_target_symbol K]
> +
> + cu {} {
> + compile_unit {
> + {language @DW_LANG_Fortran90}
> + {name dw2-entry-points.f90}
> + {comp_dir /tmp}
> + } {
> + int_label: base_type {
> + {name "int"}
> + {byte_size 4 sdata}
> + {encoding @DW_ATE_signed}
> + }
> + subprogram {
> + {name prog}
> + {decl_file 1 data1}
> + {decl_line $prog_line data1}
> + {low_pc $main_start addr}
> + {high_pc "$main_start + $main_len" addr}
> + {external 1 flag}
> + {main_subprogram 1 flag}
> + }
> + subprogram {
> + {name bar}
> + {decl_file 1 data1}
> + {decl_line $bar_line data1}
> + {external 1 flag}
> + {low_pc $bar_helper_start addr}
> + {high_pc "$bar_helper_start + $bar_helper_len" addr}
> + } {
> + formal_parameter {
> + {name I}
> + {type :$int_label}
> + {location {addr $global_I} SPECIAL_expr}
> + }
> + formal_parameter {
> + {name J}
> + {type :$int_label}
> + {location {addr $global_J} SPECIAL_expr}
> + }
> + entry_point {
> + {name foo}
> + {decl_file 1 data1}
> + {decl_line $foo_line data1}
> + {low_pc foo_entry_label addr}
> + } {
> + formal_parameter {
> + {name J}
> + {type :$int_label}
> + {location {addr $global_J} SPECIAL_expr}
> + }
> + formal_parameter {
> + {name K}
> + {type :$int_label}
> + {location {addr $global_K} SPECIAL_expr}
> + }
> + }
> + entry_point {
> + {name foobar}
> + {decl_file 1 data1}
> + {decl_line $foobar_line data1}
> + {low_pc foobar_entry_label addr}
> + } {
> + formal_parameter {
> + {name J}
> + {type :$int_label}
> + {location {addr $global_J} SPECIAL_expr}
> + }
> + }
> + }
> + }
> + }
> +
> + cu {} {
> + compile_unit {
> + {language @DW_LANG_Fortran90}
> + {name dw2-entry-points-2.f90}
> + {comp_dir /tmp}
> + } {
> + int2_label: base_type {
> + {name "int"}
> + {byte_size 4 sdata}
> + {encoding @DW_ATE_signed}
> + }
> + subprogram {
> + {name barso}
> + {decl_file 1 data1}
> + {decl_line $bar_line data1}
> + {external 1 flag}
> + {low_pc $bar_helper_start addr}
> + {high_pc "$bar_helper_start + $bar_helper_len" addr}
> + } {
> + formal_parameter {
> + {name I}
> + {type :$int2_label}
> + {location {addr $global_I} SPECIAL_expr}
> + }
> + formal_parameter {
> + {name J}
> + {type :$int2_label}
> + {location {addr $global_J} SPECIAL_expr}
> + }
> + entry_point {
> + {name fooso}
> + {decl_file 1 data1}
> + {decl_line $foo_line data1}
> + {low_pc foo_entry_label addr}
> + } {
> + formal_parameter {
> + {name J}
> + {type :$int2_label}
> + {location {addr $global_J} SPECIAL_expr}
> + }
> + formal_parameter {
> + {name K}
> + {type :$int2_label}
> + {location {addr $global_K} SPECIAL_expr}
> + }
> + }
> + }
> + }
> + }
> +}
> +
> +if {[prepare_for_testing "failed to prepare" ${testfile} \
> + [list $srcfile $asm_file] {nodebug}]} {
> + return -1
> +}
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +# Try whether we can set and hit breakpoints at the entry_points.
> +gdb_breakpoint "foo"
> +gdb_breakpoint "foobar"
> +
> +# Now hit the entry_point break point and check their call-stack.
> +gdb_continue_to_breakpoint "foo"
> +gdb_test "bt" [multi_line \
> + "#0.*${hex} in foo \\(J=1, K=0\\).*" \
> + "#1.*${hex} in prog \\(\\).*" \
> + ] "bt foo"
> +
> +gdb_continue_to_breakpoint "foobar"
> +gdb_test "bt" [multi_line \
> + "#0.*${hex} in foobar \\(J=2\\).*" \
> + "#1.*${hex} in prog \\(\\).*" \
> + ] "bt foobar"
> +
> +# Now try whether we can also set breakpoints on entry_points from other CUs.
> +
> +clean_restart ${testfile}
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +gdb_breakpoint "fooso"
> +gdb_continue_to_breakpoint "foo_so"
> +
> +gdb_test "bt" [multi_line \
> + "#0.*${hex} in foo \\(J=1, K=0\\).*" \
> + "#1.*${hex} in prog \\(\\).*" \
> +] "bt fooso"
> diff --git a/gdb/testsuite/gdb.fortran/entry-point.exp b/gdb/testsuite/gdb.fortran/entry-point.exp
> new file mode 100644
> index 00000000000..679191f79f8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.fortran/entry-point.exp
> @@ -0,0 +1,84 @@
> +# Copyright 2022 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/>.
> +#
> +# Test Fortran entry points for subroutines.
> +
> +if { [skip_fortran_tests] } { return -1 }
> +
> +standard_testfile .f90
> +load_lib "fortran.exp"
> +
> +if { [prepare_for_testing $testfile.exp $testfile $srcfile {debug f90}] } {
> + return -1
> +}
> +
> +if { ![fortran_runto_main] } {
> + untested "could not run to main"
> + return -1
> +}
> +
> +# Test if we can set a breakpoint via the entry-point name.
> +set entry_point_name "foo"
> +gdb_breakpoint $entry_point_name
> +gdb_continue_to_breakpoint "continue to breakpoint: $entry_point_name" \
> + ".*entry foo\\(J,K,L,I1\\).*"
> +
> +gdb_test "print j" "= 11" "print j, entered via $entry_point_name"
> +gdb_test "print k" "= 22" "print k, entered via $entry_point_name"
> +gdb_test "print l" "= 33" "print l, entered via $entry_point_name"
> +gdb_test "print i1" "= 44" "print i1, entered via $entry_point_name"
> +gdb_test "info args" \
> + [multi_line "j = 11" \
> + "k = 22" \
> + "l = 33" \
> + "i1 = 44"] \
> + "info args, entered via $entry_point_name"
> +
> +# Test if we can set a breakpoint via the function name.
> +set entry_point_name "bar"
> +gdb_breakpoint $entry_point_name
> +gdb_continue_to_breakpoint "continue to breakpoint: $entry_point_name" \
> + ".*subroutine bar\\(I,J,K,I1\\).*"
> +
> +gdb_test "print i" "= 444" "print i, entered via $entry_point_name"
> +gdb_test "print j" "= 555" "print j, entered via $entry_point_name"
> +gdb_test "print k" "= 666" "print k, entered via $entry_point_name"
> +gdb_test "print i1" "= 777" "print i1, entered via $entry_point_name"
> +
> +# Test a second entry point.
> +set entry_point_name "foobar"
> +gdb_breakpoint $entry_point_name
> +gdb_continue_to_breakpoint "continue to breakpoint: $entry_point_name" \
> + ".* entry foobar\\(J\\).*"
> +
> +gdb_test "print j" "= 1" "print j, entered via $entry_point_name"
> +gdb_test "info args" "j = 1" "info args, entered via $entry_point_name"
> +
> +# Test breaking at the entrypoint defined inside the module mod via its
> +# scoped name.
> +set entry_point_name "mod::mod_foo"
> +
> +# GCC moves subroutines with entry points out of the module scope into the
> +# compile unit scope.
> +if {[test_compiler_info {gcc-*}]} {
> + setup_xfail "gcc/105272" *-*-*
> +}
> +gdb_breakpoint $entry_point_name
> +
> +if {[test_compiler_info {gcc-*}]} {
> + setup_xfail "gcc/105272" *-*-*
> +}
> +gdb_continue_to_breakpoint "continue to breakpoint: $entry_point_name" \
> + ".* entry mod_foo\\(\\).*"
> diff --git a/gdb/testsuite/gdb.fortran/entry-point.f90 b/gdb/testsuite/gdb.fortran/entry-point.f90
> new file mode 100644
> index 00000000000..12a0557e787
> --- /dev/null
> +++ b/gdb/testsuite/gdb.fortran/entry-point.f90
> @@ -0,0 +1,67 @@
> +! Copyright 2022 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/>.
> +
> +module mod
> +implicit none
> +
> +contains
> + subroutine mod_bar
> + integer :: I = 3
> +
> + goto 100
> +
> + entry mod_foo
> + I = 33
> +
> +100 print *, I
> + end subroutine mod_bar
> +end module mod
> +
> +
> +subroutine bar(I,J,K,I1)
> + integer :: I,J,K,L,I1
> + integer :: A
> + real :: C
> +
> + A = 0
> + C = 0.0
> +
> + A = I + K + I1
> + goto 300
> +
> + entry foo(J,K,L,I1)
> + A = J + K + L + I1
> +
> +200 C = J
> + goto 300
> +
> + entry foobar(J)
> + goto 200
> +
> +300 A = C + 1
> + C = J * 1.5
> +
> + return
> +end subroutine
> +
> +program TestEntryPoint
> + use mod
> +
> + call foo(11,22,33,44)
> + call bar(444,555,666,777)
> + call foobar(1)
> +
> + call mod_foo()
> +end program TestEntryPoint
> --
> 2.25.1
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
More information about the Gdb-patches
mailing list