[v2,2/7] Dwarf: Fortran, support DW_TAG_entry_point.

Message ID 1542663530-140490-2-git-send-email-pwodkowski@pl.sii.eu
State New
Headers show
Series
  • [v2,1/7] DWARF: Don't add nameless modules to partial symbol table.
Related show

Commit Message

Paweł Wódkowski Nov. 19, 2018, 9:38 p.m.
From: Bernhard Heckel <bernhard.heckel@intel.com>


Fortran provides additional entry-points to an subprogram.
Those entry-points may have only a subset of parameters
of the original subprogram as well.
Add support for parsing DW_TAG_entry_point's for Fortran.

2016-06-01  Bernhard Heckel  <bernhard.heckel@intel.com>

gdb/Changelog:
	* gdb/dwarf2read.c (add_partial_symbol): Handle DW_TAG_entry_point.
	(add_partial_entry_point): New.
	(add_partial_subprogram): Search for entry_points.
	(process_die): Handle DW_TAG_entry_point.
	(dwarf2_get_pc_bounds): Update low pc from DWARF.
	(load_partial_dies): Save DW_TAG_entry_point's.
	(load_partial_dies): Save DW_TAG_entry_point to hash table.
	(load_partial_dies): Look into child's of DW_TAG_sub_program
	for fortran.
	(new_symbol_full): Process DW_TAG_entry_point.
	(read_type_die_1): Handle DW_TAG_entry_point.

gdb/Testsuite/Changelog:
	* gdb.fortran/entry_point.f90: New.
	* gdb.fortran/entry_point.exp: New.
---
 gdb/dwarf2read.c                          | 98 ++++++++++++++++++++++++++++++-
 gdb/testsuite/gdb.fortran/entry-point.exp | 70 ++++++++++++++++++++++
 gdb/testsuite/gdb.fortran/entry-point.f90 | 48 +++++++++++++++
 3 files changed, 215 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.fortran/entry-point.exp
 create mode 100644 gdb/testsuite/gdb.fortran/entry-point.f90

-- 
2.7.4

Comments

Andrew Burgess Nov. 27, 2018, 10:09 p.m. | #1
* Pawel Wodkowski <pwodkowski@pl.sii.eu> [2018-11-19 22:38:45 +0100]:

> From: Bernhard Heckel <bernhard.heckel@intel.com>

> 

> Fortran provides additional entry-points to an subprogram.

> Those entry-points may have only a subset of parameters

> of the original subprogram as well.

> Add support for parsing DW_TAG_entry_point's for Fortran.


As with patch #1 it's probably worth documenting which compilers you
see DW_TAG_entry_point in, along with an example of what the generated
DWARF looks like.

This means that in the future if/when others start to use this DWARF
feature we can figure out which other compilers we need to test.

> 

> 2016-06-01  Bernhard Heckel  <bernhard.heckel@intel.com>

> 

> gdb/Changelog:

> 	* gdb/dwarf2read.c (add_partial_symbol): Handle DW_TAG_entry_point.

> 	(add_partial_entry_point): New.

> 	(add_partial_subprogram): Search for entry_points.

> 	(process_die): Handle DW_TAG_entry_point.

> 	(dwarf2_get_pc_bounds): Update low pc from DWARF.

> 	(load_partial_dies): Save DW_TAG_entry_point's.

> 	(load_partial_dies): Save DW_TAG_entry_point to hash table.

> 	(load_partial_dies): Look into child's of DW_TAG_sub_program

> 	for fortran.

> 	(new_symbol_full): Process DW_TAG_entry_point.

> 	(read_type_die_1): Handle DW_TAG_entry_point.

> 

> gdb/Testsuite/Changelog:

> 	* gdb.fortran/entry_point.f90: New.

> 	* gdb.fortran/entry_point.exp: New.

> ---

>  gdb/dwarf2read.c                          | 98 ++++++++++++++++++++++++++++++-

>  gdb/testsuite/gdb.fortran/entry-point.exp | 70 ++++++++++++++++++++++

>  gdb/testsuite/gdb.fortran/entry-point.f90 | 48 +++++++++++++++

>  3 files changed, 215 insertions(+), 1 deletion(-)

>  create mode 100644 gdb/testsuite/gdb.fortran/entry-point.exp

>  create mode 100644 gdb/testsuite/gdb.fortran/entry-point.f90

> 

> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c

> index 89fd4ae15e80..88e57d7ab68e 100644

> --- a/gdb/dwarf2read.c

> +++ b/gdb/dwarf2read.c

> @@ -1473,6 +1473,10 @@ static void add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,

>  static void add_partial_enumeration (struct partial_die_info *enum_pdi,

>  				     struct dwarf2_cu *cu);

>  

> +static void add_partial_entry_point (struct partial_die_info *pdi,

> +				     CORE_ADDR *lowpc, CORE_ADDR *highpc,

> +				     int need_pc, struct dwarf2_cu *cu);

> +

>  static void add_partial_subprogram (struct partial_die_info *pdi,

>  				    CORE_ADDR *lowpc, CORE_ADDR *highpc,

>  				    int need_pc, struct dwarf2_cu *cu);

> @@ -8876,6 +8880,32 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)

>  

>    switch (pdi->tag)

>      {

> +    case DW_TAG_entry_point:

> +      /* Don't know any other language than fortran which is

> +	 using DW_TAG_entry_point.  */

> +      if (cu->language == language_fortran)

> +	{


I'm not sure the language check is needed here.  The description for
DW_TAG_entry_point in the DWARF spec seems pretty generic.  I don't
see how a different language would expect significantly different
results, and so, I would suggest we should just add this as general
purpose code.

> +	  addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);


When compared to DW_TAG_subprogram, this line doesn't include a '-
baseaddr'.  I think that deserves a comment explaining why.

> +	  /* 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.  */

> +	  if (pdi->die_parent->is_external)

> +	    add_psymbol_to_list (actual_name, strlen (actual_name),

> +				 built_actual_name != nullptr,

> +				 VAR_DOMAIN, LOC_BLOCK,

> +				 SECT_OFF_TEXT (objfile),

> +				 &objfile->global_psymbols,

> +				 addr, cu->language, objfile);

> +	  else

> +	    add_psymbol_to_list (actual_name, strlen (actual_name),

> +				 built_actual_name != nullptr,

> +				 VAR_DOMAIN, LOC_BLOCK,

> +				 SECT_OFF_TEXT (objfile),

> +				 &objfile->static_psymbols,

> +				 addr, cu->language, objfile);


I think these two add_psymbol_to_list calls, and the two for
DW_TAG_subprogram should be factored out.  Just my opinion though...

> +	}

> +      break;

>      case DW_TAG_inlined_subroutine:

>      case DW_TAG_subprogram:

>        addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)

> @@ -9082,6 +9112,17 @@ add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,

>      scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);

>  }

>  

> +static void

> +add_partial_entry_point (struct partial_die_info *pdi,

> +			 CORE_ADDR *p_lowpc, CORE_ADDR *p_highpc,

> +			 int set_addrmap, struct dwarf2_cu *cu)

> +{

> +  if (pdi->name == nullptr)

> +    complaint (_("DW_TAG_entry_point must have a name"));

> +  else

> +    add_partial_symbol (pdi, cu);

> +}


This function should have a header comment, however, a quick look at
add_partial_subprogram seems to indicate that at this point GDB is not
complaining, but just ignoring weird looking DWARF.  For example this
code in add_partial_subprogram:

     /* Ignore subprogram DIEs that do not have a name, they are
        illegal.  Do not emit a complaint at this point, we will
        do so when we convert this psymtab into a symtab.  */
     if (pdi->name)
       add_partial_symbol (pdi, cu);

I think the same logic should apply for DW_TAG_entry_point maybe? So,
add_partial_entry_point is possibly redundant.

> +

>  /* Read a partial die corresponding to a subprogram or an inlined

>     subprogram and create a partial symbol for that subprogram.

>     When the CU language allows it, this routine also defines a partial

> @@ -9158,6 +9199,16 @@ add_partial_subprogram (struct partial_die_info *pdi,

>  	  pdi = pdi->die_sibling;

>  	}

>      }

> +  else if (cu->language == language_fortran)

> +    {


Like before, I'm not convinced we should tie this to Fortran...

> +      pdi = pdi->die_child;

> +      while (pdi != nullptr)

> +	{

> +	  if (pdi->tag == DW_TAG_entry_point)

> +	    add_partial_entry_point (pdi, lowpc, highpc, set_addrmap, cu);


You can probably just make the add_partial_symbol call directly here
(after a check that pdi->name is not null.

> +	  pdi = pdi->die_sibling;

> +	}

> +    }

>  }

>  

>  /* Read a partial die corresponding to an enumeration type.  */

> @@ -10596,6 +10647,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)

>      case DW_TAG_type_unit:

>        read_type_unit_scope (die, cu);

>        break;

> +    case DW_TAG_entry_point:

>      case DW_TAG_subprogram:

>      case DW_TAG_inlined_subroutine:

>        read_func_scope (die, cu);

> @@ -14669,6 +14721,26 @@ 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)

> +    {

> +      /* Entry_point is embedded in an subprogram. Therefore, we can use

> +	 the highpc from it's enveloping subprogram and get the

> +	 lowpc from DWARF.  */

> +      if (0 == dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst))


Compare to 'PC_BOUNDS_NOT_PRESENT' not 0.

> +	return PC_BOUNDS_NOT_PRESENT;

> +

> +      attr = dwarf2_attr (die, DW_AT_low_pc, cu);

> +      if (!attr)

> +	{

> +	  complaint (_("DW_TAG_entry_point is missing DW_AT_low_pc"));

> +	  return PC_BOUNDS_NOT_PRESENT;

> +	}

> +      low = attr_value_as_address (attr);

> +      *lowpc = low;

> +

> +      return PC_BOUNDS_HIGH_LOW;

> +    }

> +

>    attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);

>    if (attr_high)

>      {

> @@ -18399,6 +18471,7 @@ load_partial_dies (const struct die_reader_specs *reader,

>  	  && !is_type_tag_for_partial (abbrev->tag)

>  	  && abbrev->tag != DW_TAG_constant

>  	  && abbrev->tag != DW_TAG_enumerator

> +	  && abbrev->tag != DW_TAG_entry_point

>  	  && abbrev->tag != DW_TAG_subprogram

>  	  && abbrev->tag != DW_TAG_inlined_subroutine

>  	  && abbrev->tag != DW_TAG_lexical_block

> @@ -18529,6 +18602,7 @@ load_partial_dies (const struct die_reader_specs *reader,

>  

>        if (load_all

>  	  || abbrev->tag == DW_TAG_constant

> +	  || abbrev->tag == DW_TAG_entry_point

>  	  || abbrev->tag == DW_TAG_subprogram

>  	  || abbrev->tag == DW_TAG_variable

>  	  || abbrev->tag == DW_TAG_namespace

> @@ -18570,7 +18644,9 @@ load_partial_dies (const struct die_reader_specs *reader,

>  		      || last_die->tag == DW_TAG_union_type))

>  	      || (cu->language == language_ada

>  		  && (last_die->tag == DW_TAG_subprogram

> -		      || last_die->tag == DW_TAG_lexical_block))))

> +		      || last_die->tag == DW_TAG_lexical_block))

> +	      || (cu->language == language_fortran

> +		  && last_die->tag == DW_TAG_subprogram)))

>  	{

>  	  nesting_level++;

>  	  parent_die = last_die;

> @@ -21442,6 +21518,25 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,

>  	  SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;

>  	  dw2_add_symbol_to_list (sym, cu->list_in_scope);

>  	  break;

> +	case DW_TAG_entry_point:

> +	  /* Don't know any other language than fortran which is

> +	     using DW_TAG_entry_point.  */

> +	  if (cu->language == language_fortran)

> +	    {

> +	      /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by

> +		 finish_block.  */

> +	      SYMBOL_ACLASS_INDEX (sym) = 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 && (DW_UNSND (attr2) != 0))

> +		list_to_add = cu->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.  */

> @@ -22129,6 +22224,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:

> diff --git a/gdb/testsuite/gdb.fortran/entry-point.exp b/gdb/testsuite/gdb.fortran/entry-point.exp

> new file mode 100644

> index 000000000000..a1f3f2bebdb9

> --- /dev/null

> +++ b/gdb/testsuite/gdb.fortran/entry-point.exp

> @@ -0,0 +1,70 @@

> +# Copyright 2018 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/>.

> +

> +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 ![runto MAIN__] then {

> +    perror "couldn't run to breakpoint MAIN__"

> +    continue

> +}

> +

> +# Test if we can set a breakpoint via entry-point name

> +set ept_name "foo"

> +gdb_breakpoint $ept_name

> +gdb_test "continue" \

> +    [multi_line "Breakpoint $decimal, $ept_name \\(j=1, k=2, l=3, i1=4\\) at .*" \

> +                ".*"] \

> +    "continue to breakpoint: $ept_name"

> +

> +gdb_test "print j" "= 1" "print j, entered via $ept_name"

> +gdb_test "print k" "= 2" "print k, entered via $ept_name"

> +gdb_test "print l" "= 3" "print l, entered via $ept_name"

> +gdb_test "print i1" "= 4" "print i1, entered via $ept_name"

> +gdb_test "info args" \

> +  [multi_line "j = 1" \

> +              "k = 2" \

> +              "l = 3" \

> +              "i1 = 4"] \

> +   "info args, entered via $ept_name"

> +

> +# Test if we can set a breakpoint via function name

> +set ept_name "bar"

> +gdb_breakpoint $ept_name

> +gdb_test "continue" \

> +    [multi_line "Breakpoint $decimal, $ept_name \\(i=4, j=5, k=6, i1=7\\) at .*" \

> +                ".*"] \

> +    "continue to breakpoint: $ept_name"

> +

> +gdb_test "print i" "= 4" "print i, entered via $ept_name"

> +gdb_test "print j" "= 5" "print j, entered via $ept_name"

> +gdb_test "print k" "= 6" "print k, entered via $ept_name"

> +gdb_test "print i1" "= 7" "print i1, entered via $ept_name"

> +

> +set ept_name "tim"

> +gdb_breakpoint $ept_name

> +gdb_test "continue" \

> +    [multi_line "Breakpoint $decimal, $ept_name \\(j=1\\) at .*" \

> +                ".*"] \

> +    "continue to breakpoint: $ept_name"

> +

> +gdb_test "print j" "= 1" "print j, entered via $ept_name"

> +gdb_test "info args" "j = 1" "info args, entered via $ept_name"

> diff --git a/gdb/testsuite/gdb.fortran/entry-point.f90 b/gdb/testsuite/gdb.fortran/entry-point.f90

> new file mode 100644

> index 000000000000..cb663b956982

> --- /dev/null

> +++ b/gdb/testsuite/gdb.fortran/entry-point.f90

> @@ -0,0 +1,48 @@

> +! Copyright 2018 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/>.

> +

> +program TestEntryPoint

> +

> +  call foo(1,2,3,4)

> +  call bar(4,5,6,7)

> +  call tim(1)

> +

> +end program TestEntryPoint

> +

> +  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 1000

> +

> +    entry foo(J,K,L,I1)

> +    A = J + K + L + I1

> +

> +200 C = J

> +    goto 1000

> +

> +    entry tim(J)

> +    goto 200

> +

> +1000 A = C + 1

> +     C = J * 1.5

> +

> +    return

> +  end subroutine

> -- 

> 2.7.4

> 



Thanks,
Andrew
Paweł Wódkowski Dec. 2, 2018, 9:32 p.m. | #2
On 27.11.2018 23:08, Andrew Burgess wrote:
> * Pawel Wodkowski <pwodkowski@pl.sii.eu> [2018-11-19 22:38:45 +0100]:

> 

>> From: Bernhard Heckel <bernhard.heckel@intel.com>

>>

>> Fortran provides additional entry-points to an subprogram.

>> Those entry-points may have only a subset of parameters

>> of the original subprogram as well.

>> Add support for parsing DW_TAG_entry_point's for Fortran.

> 

> As with patch #1 it's probably worth documenting which compilers you

> see DW_TAG_entry_point in, along with an example of what the generated

> DWARF looks like.

> 

> This means that in the future if/when others start to use this DWARF

> feature we can figure out which other compilers we need to test.

> 


As I checked gfortran will not generate entry point tags so for now it 
is only for Intel ifort compiler. The entry-point.f90 example compiled 
using ifort produce following entry point tag:

...
<2><9e>: Abbrev Number: 5 (DW_TAG_entry_point)
     <9f>   DW_AT_decl_line   : 35
     <a0>   DW_AT_decl_file   : 1
     <a1>   DW_AT_name        : foo
     <a5>   DW_AT_low_pc      : 0x402ba8
...
<3><c9>: Abbrev Number: 4 (DW_TAG_formal_parameter)
     <ca>   DW_AT_decl_line   : 35
     <cb>   DW_AT_decl_file   : 1
     <cc>   DW_AT_type        : <0x120>
     <d0>   DW_AT_name        : l
     <d2>   DW_AT_location    : 4 byte block: 76 f4 7e 6 
(DW_OP_breg6 (rbp): -140; DW_OP_deref)
...

I will add this to commit message.

Thanks
Pawel

>>

>> 2016-06-01  Bernhard Heckel  <bernhard.heckel@intel.com>

>>

>> gdb/Changelog:

>> 	* gdb/dwarf2read.c (add_partial_symbol): Handle DW_TAG_entry_point.

>> 	(add_partial_entry_point): New.

>> 	(add_partial_subprogram): Search for entry_points.

>> 	(process_die): Handle DW_TAG_entry_point.

>> 	(dwarf2_get_pc_bounds): Update low pc from DWARF.

>> 	(load_partial_dies): Save DW_TAG_entry_point's.

>> 	(load_partial_dies): Save DW_TAG_entry_point to hash table.

>> 	(load_partial_dies): Look into child's of DW_TAG_sub_program

>> 	for fortran.

>> 	(new_symbol_full): Process DW_TAG_entry_point.

>> 	(read_type_die_1): Handle DW_TAG_entry_point.

>>

>> gdb/Testsuite/Changelog:

>> 	* gdb.fortran/entry_point.f90: New.

>> 	* gdb.fortran/entry_point.exp: New.

>> ---

>>   gdb/dwarf2read.c                          | 98 ++++++++++++++++++++++++++++++-

>>   gdb/testsuite/gdb.fortran/entry-point.exp | 70 ++++++++++++++++++++++

>>   gdb/testsuite/gdb.fortran/entry-point.f90 | 48 +++++++++++++++

>>   3 files changed, 215 insertions(+), 1 deletion(-)

>>   create mode 100644 gdb/testsuite/gdb.fortran/entry-point.exp

>>   create mode 100644 gdb/testsuite/gdb.fortran/entry-point.f90

>>

>> diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c

>> index 89fd4ae15e80..88e57d7ab68e 100644

>> --- a/gdb/dwarf2read.c

>> +++ b/gdb/dwarf2read.c

>> @@ -1473,6 +1473,10 @@ static void add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,

>>   static void add_partial_enumeration (struct partial_die_info *enum_pdi,

>>   				     struct dwarf2_cu *cu);

>>   

>> +static void add_partial_entry_point (struct partial_die_info *pdi,

>> +				     CORE_ADDR *lowpc, CORE_ADDR *highpc,

>> +				     int need_pc, struct dwarf2_cu *cu);

>> +

>>   static void add_partial_subprogram (struct partial_die_info *pdi,

>>   				    CORE_ADDR *lowpc, CORE_ADDR *highpc,

>>   				    int need_pc, struct dwarf2_cu *cu);

>> @@ -8876,6 +8880,32 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)

>>   

>>     switch (pdi->tag)

>>       {

>> +    case DW_TAG_entry_point:

>> +      /* Don't know any other language than fortran which is

>> +	 using DW_TAG_entry_point.  */

>> +      if (cu->language == language_fortran)

>> +	{

> 

> I'm not sure the language check is needed here.  The description for

> DW_TAG_entry_point in the DWARF spec seems pretty generic.  I don't

> see how a different language would expect significantly different

> results, and so, I would suggest we should just add this as general

> purpose code.

> 

>> +	  addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);

> 

> When compared to DW_TAG_subprogram, this line doesn't include a '-

> baseaddr'.  I think that deserves a comment explaining why.

> 

>> +	  /* 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.  */

>> +	  if (pdi->die_parent->is_external)

>> +	    add_psymbol_to_list (actual_name, strlen (actual_name),

>> +				 built_actual_name != nullptr,

>> +				 VAR_DOMAIN, LOC_BLOCK,

>> +				 SECT_OFF_TEXT (objfile),

>> +				 &objfile->global_psymbols,

>> +				 addr, cu->language, objfile);

>> +	  else

>> +	    add_psymbol_to_list (actual_name, strlen (actual_name),

>> +				 built_actual_name != nullptr,

>> +				 VAR_DOMAIN, LOC_BLOCK,

>> +				 SECT_OFF_TEXT (objfile),

>> +				 &objfile->static_psymbols,

>> +				 addr, cu->language, objfile);

> 

> I think these two add_psymbol_to_list calls, and the two for

> DW_TAG_subprogram should be factored out.  Just my opinion though...

> 

>> +	}

>> +      break;

>>       case DW_TAG_inlined_subroutine:

>>       case DW_TAG_subprogram:

>>         addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)

>> @@ -9082,6 +9112,17 @@ add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,

>>       scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);

>>   }

>>   

>> +static void

>> +add_partial_entry_point (struct partial_die_info *pdi,

>> +			 CORE_ADDR *p_lowpc, CORE_ADDR *p_highpc,

>> +			 int set_addrmap, struct dwarf2_cu *cu)

>> +{

>> +  if (pdi->name == nullptr)

>> +    complaint (_("DW_TAG_entry_point must have a name"));

>> +  else

>> +    add_partial_symbol (pdi, cu);

>> +}

> 

> This function should have a header comment, however, a quick look at

> add_partial_subprogram seems to indicate that at this point GDB is not

> complaining, but just ignoring weird looking DWARF.  For example this

> code in add_partial_subprogram:

> 

>       /* Ignore subprogram DIEs that do not have a name, they are

>          illegal.  Do not emit a complaint at this point, we will

>          do so when we convert this psymtab into a symtab.  */

>       if (pdi->name)

>         add_partial_symbol (pdi, cu);

> 

> I think the same logic should apply for DW_TAG_entry_point maybe? So,

> add_partial_entry_point is possibly redundant.

> 

>> +

>>   /* Read a partial die corresponding to a subprogram or an inlined

>>      subprogram and create a partial symbol for that subprogram.

>>      When the CU language allows it, this routine also defines a partial

>> @@ -9158,6 +9199,16 @@ add_partial_subprogram (struct partial_die_info *pdi,

>>   	  pdi = pdi->die_sibling;

>>   	}

>>       }

>> +  else if (cu->language == language_fortran)

>> +    {

> 

> Like before, I'm not convinced we should tie this to Fortran...

> 

>> +      pdi = pdi->die_child;

>> +      while (pdi != nullptr)

>> +	{

>> +	  if (pdi->tag == DW_TAG_entry_point)

>> +	    add_partial_entry_point (pdi, lowpc, highpc, set_addrmap, cu);

> 

> You can probably just make the add_partial_symbol call directly here

> (after a check that pdi->name is not null.

> 

>> +	  pdi = pdi->die_sibling;

>> +	}

>> +    }

>>   }

>>   

>>   /* Read a partial die corresponding to an enumeration type.  */

>> @@ -10596,6 +10647,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)

>>       case DW_TAG_type_unit:

>>         read_type_unit_scope (die, cu);

>>         break;

>> +    case DW_TAG_entry_point:

>>       case DW_TAG_subprogram:

>>       case DW_TAG_inlined_subroutine:

>>         read_func_scope (die, cu);

>> @@ -14669,6 +14721,26 @@ 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)

>> +    {

>> +      /* Entry_point is embedded in an subprogram. Therefore, we can use

>> +	 the highpc from it's enveloping subprogram and get the

>> +	 lowpc from DWARF.  */

>> +      if (0 == dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst))

> 

> Compare to 'PC_BOUNDS_NOT_PRESENT' not 0.

> 

>> +	return PC_BOUNDS_NOT_PRESENT;

>> +

>> +      attr = dwarf2_attr (die, DW_AT_low_pc, cu);

>> +      if (!attr)

>> +	{

>> +	  complaint (_("DW_TAG_entry_point is missing DW_AT_low_pc"));

>> +	  return PC_BOUNDS_NOT_PRESENT;

>> +	}

>> +      low = attr_value_as_address (attr);

>> +      *lowpc = low;

>> +

>> +      return PC_BOUNDS_HIGH_LOW;

>> +    }

>> +

>>     attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);

>>     if (attr_high)

>>       {

>> @@ -18399,6 +18471,7 @@ load_partial_dies (const struct die_reader_specs *reader,

>>   	  && !is_type_tag_for_partial (abbrev->tag)

>>   	  && abbrev->tag != DW_TAG_constant

>>   	  && abbrev->tag != DW_TAG_enumerator

>> +	  && abbrev->tag != DW_TAG_entry_point

>>   	  && abbrev->tag != DW_TAG_subprogram

>>   	  && abbrev->tag != DW_TAG_inlined_subroutine

>>   	  && abbrev->tag != DW_TAG_lexical_block

>> @@ -18529,6 +18602,7 @@ load_partial_dies (const struct die_reader_specs *reader,

>>   

>>         if (load_all

>>   	  || abbrev->tag == DW_TAG_constant

>> +	  || abbrev->tag == DW_TAG_entry_point

>>   	  || abbrev->tag == DW_TAG_subprogram

>>   	  || abbrev->tag == DW_TAG_variable

>>   	  || abbrev->tag == DW_TAG_namespace

>> @@ -18570,7 +18644,9 @@ load_partial_dies (const struct die_reader_specs *reader,

>>   		      || last_die->tag == DW_TAG_union_type))

>>   	      || (cu->language == language_ada

>>   		  && (last_die->tag == DW_TAG_subprogram

>> -		      || last_die->tag == DW_TAG_lexical_block))))

>> +		      || last_die->tag == DW_TAG_lexical_block))

>> +	      || (cu->language == language_fortran

>> +		  && last_die->tag == DW_TAG_subprogram)))

>>   	{

>>   	  nesting_level++;

>>   	  parent_die = last_die;

>> @@ -21442,6 +21518,25 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,

>>   	  SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;

>>   	  dw2_add_symbol_to_list (sym, cu->list_in_scope);

>>   	  break;

>> +	case DW_TAG_entry_point:

>> +	  /* Don't know any other language than fortran which is

>> +	     using DW_TAG_entry_point.  */

>> +	  if (cu->language == language_fortran)

>> +	    {

>> +	      /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by

>> +		 finish_block.  */

>> +	      SYMBOL_ACLASS_INDEX (sym) = 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 && (DW_UNSND (attr2) != 0))

>> +		list_to_add = cu->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.  */

>> @@ -22129,6 +22224,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:

>> diff --git a/gdb/testsuite/gdb.fortran/entry-point.exp b/gdb/testsuite/gdb.fortran/entry-point.exp

>> new file mode 100644

>> index 000000000000..a1f3f2bebdb9

>> --- /dev/null

>> +++ b/gdb/testsuite/gdb.fortran/entry-point.exp

>> @@ -0,0 +1,70 @@

>> +# Copyright 2018 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/>.

>> +

>> +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 ![runto MAIN__] then {

>> +    perror "couldn't run to breakpoint MAIN__"

>> +    continue

>> +}

>> +

>> +# Test if we can set a breakpoint via entry-point name

>> +set ept_name "foo"

>> +gdb_breakpoint $ept_name

>> +gdb_test "continue" \

>> +    [multi_line "Breakpoint $decimal, $ept_name \\(j=1, k=2, l=3, i1=4\\) at .*" \

>> +                ".*"] \

>> +    "continue to breakpoint: $ept_name"

>> +

>> +gdb_test "print j" "= 1" "print j, entered via $ept_name"

>> +gdb_test "print k" "= 2" "print k, entered via $ept_name"

>> +gdb_test "print l" "= 3" "print l, entered via $ept_name"

>> +gdb_test "print i1" "= 4" "print i1, entered via $ept_name"

>> +gdb_test "info args" \

>> +  [multi_line "j = 1" \

>> +              "k = 2" \

>> +              "l = 3" \

>> +              "i1 = 4"] \

>> +   "info args, entered via $ept_name"

>> +

>> +# Test if we can set a breakpoint via function name

>> +set ept_name "bar"

>> +gdb_breakpoint $ept_name

>> +gdb_test "continue" \

>> +    [multi_line "Breakpoint $decimal, $ept_name \\(i=4, j=5, k=6, i1=7\\) at .*" \

>> +                ".*"] \

>> +    "continue to breakpoint: $ept_name"

>> +

>> +gdb_test "print i" "= 4" "print i, entered via $ept_name"

>> +gdb_test "print j" "= 5" "print j, entered via $ept_name"

>> +gdb_test "print k" "= 6" "print k, entered via $ept_name"

>> +gdb_test "print i1" "= 7" "print i1, entered via $ept_name"

>> +

>> +set ept_name "tim"

>> +gdb_breakpoint $ept_name

>> +gdb_test "continue" \

>> +    [multi_line "Breakpoint $decimal, $ept_name \\(j=1\\) at .*" \

>> +                ".*"] \

>> +    "continue to breakpoint: $ept_name"

>> +

>> +gdb_test "print j" "= 1" "print j, entered via $ept_name"

>> +gdb_test "info args" "j = 1" "info args, entered via $ept_name"

>> diff --git a/gdb/testsuite/gdb.fortran/entry-point.f90 b/gdb/testsuite/gdb.fortran/entry-point.f90

>> new file mode 100644

>> index 000000000000..cb663b956982

>> --- /dev/null

>> +++ b/gdb/testsuite/gdb.fortran/entry-point.f90

>> @@ -0,0 +1,48 @@

>> +! Copyright 2018 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/>.

>> +

>> +program TestEntryPoint

>> +

>> +  call foo(1,2,3,4)

>> +  call bar(4,5,6,7)

>> +  call tim(1)

>> +

>> +end program TestEntryPoint

>> +

>> +  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 1000

>> +

>> +    entry foo(J,K,L,I1)

>> +    A = J + K + L + I1

>> +

>> +200 C = J

>> +    goto 1000

>> +

>> +    entry tim(J)

>> +    goto 200

>> +

>> +1000 A = C + 1

>> +     C = J * 1.5

>> +

>> +    return

>> +  end subroutine

>> -- 

>> 2.7.4

>>

> 

> 

> Thanks,

> Andrew

>

Patch

diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 89fd4ae15e80..88e57d7ab68e 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1473,6 +1473,10 @@  static void add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
 static void add_partial_enumeration (struct partial_die_info *enum_pdi,
 				     struct dwarf2_cu *cu);
 
+static void add_partial_entry_point (struct partial_die_info *pdi,
+				     CORE_ADDR *lowpc, CORE_ADDR *highpc,
+				     int need_pc, struct dwarf2_cu *cu);
+
 static void add_partial_subprogram (struct partial_die_info *pdi,
 				    CORE_ADDR *lowpc, CORE_ADDR *highpc,
 				    int need_pc, struct dwarf2_cu *cu);
@@ -8876,6 +8880,32 @@  add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 
   switch (pdi->tag)
     {
+    case DW_TAG_entry_point:
+      /* Don't know any other language than fortran which is
+	 using DW_TAG_entry_point.  */
+      if (cu->language == language_fortran)
+	{
+	  addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);
+	  /* 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.  */
+	  if (pdi->die_parent->is_external)
+	    add_psymbol_to_list (actual_name, strlen (actual_name),
+				 built_actual_name != nullptr,
+				 VAR_DOMAIN, LOC_BLOCK,
+				 SECT_OFF_TEXT (objfile),
+				 &objfile->global_psymbols,
+				 addr, cu->language, objfile);
+	  else
+	    add_psymbol_to_list (actual_name, strlen (actual_name),
+				 built_actual_name != nullptr,
+				 VAR_DOMAIN, LOC_BLOCK,
+				 SECT_OFF_TEXT (objfile),
+				 &objfile->static_psymbols,
+				 addr, cu->language, objfile);
+	}
+      break;
     case DW_TAG_inlined_subroutine:
     case DW_TAG_subprogram:
       addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)
@@ -9082,6 +9112,17 @@  add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
     scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);
 }
 
+static void
+add_partial_entry_point (struct partial_die_info *pdi,
+			 CORE_ADDR *p_lowpc, CORE_ADDR *p_highpc,
+			 int set_addrmap, struct dwarf2_cu *cu)
+{
+  if (pdi->name == nullptr)
+    complaint (_("DW_TAG_entry_point must have a name"));
+  else
+    add_partial_symbol (pdi, cu);
+}
+
 /* Read a partial die corresponding to a subprogram or an inlined
    subprogram and create a partial symbol for that subprogram.
    When the CU language allows it, this routine also defines a partial
@@ -9158,6 +9199,16 @@  add_partial_subprogram (struct partial_die_info *pdi,
 	  pdi = pdi->die_sibling;
 	}
     }
+  else if (cu->language == language_fortran)
+    {
+      pdi = pdi->die_child;
+      while (pdi != nullptr)
+	{
+	  if (pdi->tag == DW_TAG_entry_point)
+	    add_partial_entry_point (pdi, lowpc, highpc, set_addrmap, cu);
+	  pdi = pdi->die_sibling;
+	}
+    }
 }
 
 /* Read a partial die corresponding to an enumeration type.  */
@@ -10596,6 +10647,7 @@  process_die (struct die_info *die, struct dwarf2_cu *cu)
     case DW_TAG_type_unit:
       read_type_unit_scope (die, cu);
       break;
+    case DW_TAG_entry_point:
     case DW_TAG_subprogram:
     case DW_TAG_inlined_subroutine:
       read_func_scope (die, cu);
@@ -14669,6 +14721,26 @@  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)
+    {
+      /* Entry_point is embedded in an subprogram. Therefore, we can use
+	 the highpc from it's enveloping subprogram and get the
+	 lowpc from DWARF.  */
+      if (0 == dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst))
+	return PC_BOUNDS_NOT_PRESENT;
+
+      attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+      if (!attr)
+	{
+	  complaint (_("DW_TAG_entry_point is missing DW_AT_low_pc"));
+	  return PC_BOUNDS_NOT_PRESENT;
+	}
+      low = attr_value_as_address (attr);
+      *lowpc = low;
+
+      return PC_BOUNDS_HIGH_LOW;
+    }
+
   attr_high = dwarf2_attr (die, DW_AT_high_pc, cu);
   if (attr_high)
     {
@@ -18399,6 +18471,7 @@  load_partial_dies (const struct die_reader_specs *reader,
 	  && !is_type_tag_for_partial (abbrev->tag)
 	  && abbrev->tag != DW_TAG_constant
 	  && abbrev->tag != DW_TAG_enumerator
+	  && abbrev->tag != DW_TAG_entry_point
 	  && abbrev->tag != DW_TAG_subprogram
 	  && abbrev->tag != DW_TAG_inlined_subroutine
 	  && abbrev->tag != DW_TAG_lexical_block
@@ -18529,6 +18602,7 @@  load_partial_dies (const struct die_reader_specs *reader,
 
       if (load_all
 	  || abbrev->tag == DW_TAG_constant
+	  || abbrev->tag == DW_TAG_entry_point
 	  || abbrev->tag == DW_TAG_subprogram
 	  || abbrev->tag == DW_TAG_variable
 	  || abbrev->tag == DW_TAG_namespace
@@ -18570,7 +18644,9 @@  load_partial_dies (const struct die_reader_specs *reader,
 		      || last_die->tag == DW_TAG_union_type))
 	      || (cu->language == language_ada
 		  && (last_die->tag == DW_TAG_subprogram
-		      || last_die->tag == DW_TAG_lexical_block))))
+		      || last_die->tag == DW_TAG_lexical_block))
+	      || (cu->language == language_fortran
+		  && last_die->tag == DW_TAG_subprogram)))
 	{
 	  nesting_level++;
 	  parent_die = last_die;
@@ -21442,6 +21518,25 @@  new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
 	  SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
 	  dw2_add_symbol_to_list (sym, cu->list_in_scope);
 	  break;
+	case DW_TAG_entry_point:
+	  /* Don't know any other language than fortran which is
+	     using DW_TAG_entry_point.  */
+	  if (cu->language == language_fortran)
+	    {
+	      /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by
+		 finish_block.  */
+	      SYMBOL_ACLASS_INDEX (sym) = 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 && (DW_UNSND (attr2) != 0))
+		list_to_add = cu->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.  */
@@ -22129,6 +22224,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:
diff --git a/gdb/testsuite/gdb.fortran/entry-point.exp b/gdb/testsuite/gdb.fortran/entry-point.exp
new file mode 100644
index 000000000000..a1f3f2bebdb9
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/entry-point.exp
@@ -0,0 +1,70 @@ 
+# Copyright 2018 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/>.
+
+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 ![runto MAIN__] then {
+    perror "couldn't run to breakpoint MAIN__"
+    continue
+}
+
+# Test if we can set a breakpoint via entry-point name
+set ept_name "foo"
+gdb_breakpoint $ept_name
+gdb_test "continue" \
+    [multi_line "Breakpoint $decimal, $ept_name \\(j=1, k=2, l=3, i1=4\\) at .*" \
+                ".*"] \
+    "continue to breakpoint: $ept_name"
+
+gdb_test "print j" "= 1" "print j, entered via $ept_name"
+gdb_test "print k" "= 2" "print k, entered via $ept_name"
+gdb_test "print l" "= 3" "print l, entered via $ept_name"
+gdb_test "print i1" "= 4" "print i1, entered via $ept_name"
+gdb_test "info args" \
+  [multi_line "j = 1" \
+              "k = 2" \
+              "l = 3" \
+              "i1 = 4"] \
+   "info args, entered via $ept_name"
+
+# Test if we can set a breakpoint via function name
+set ept_name "bar"
+gdb_breakpoint $ept_name
+gdb_test "continue" \
+    [multi_line "Breakpoint $decimal, $ept_name \\(i=4, j=5, k=6, i1=7\\) at .*" \
+                ".*"] \
+    "continue to breakpoint: $ept_name"
+
+gdb_test "print i" "= 4" "print i, entered via $ept_name"
+gdb_test "print j" "= 5" "print j, entered via $ept_name"
+gdb_test "print k" "= 6" "print k, entered via $ept_name"
+gdb_test "print i1" "= 7" "print i1, entered via $ept_name"
+
+set ept_name "tim"
+gdb_breakpoint $ept_name
+gdb_test "continue" \
+    [multi_line "Breakpoint $decimal, $ept_name \\(j=1\\) at .*" \
+                ".*"] \
+    "continue to breakpoint: $ept_name"
+
+gdb_test "print j" "= 1" "print j, entered via $ept_name"
+gdb_test "info args" "j = 1" "info args, entered via $ept_name"
diff --git a/gdb/testsuite/gdb.fortran/entry-point.f90 b/gdb/testsuite/gdb.fortran/entry-point.f90
new file mode 100644
index 000000000000..cb663b956982
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/entry-point.f90
@@ -0,0 +1,48 @@ 
+! Copyright 2018 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/>.
+
+program TestEntryPoint
+
+  call foo(1,2,3,4)
+  call bar(4,5,6,7)
+  call tim(1)
+
+end program TestEntryPoint
+
+  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 1000
+
+    entry foo(J,K,L,I1)
+    A = J + K + L + I1
+
+200 C = J
+    goto 1000
+
+    entry tim(J)
+    goto 200
+
+1000 A = C + 1
+     C = J * 1.5
+
+    return
+  end subroutine