]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Dwarf: Fortran, support DW_TAG_entry_point.
authorBernhard Heckel <bernhard.heckel@intel.com>
Tue, 31 May 2016 09:11:51 +0000 (11:11 +0200)
committerBernhard Heckel <bernhard.heckel@intel.com>
Fri, 23 Dec 2016 11:20:01 +0000 (12:20 +0100)
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.

Change-Id: I886699802fc940cd9b995806c32a85a05cf57dc4

gdb/dwarf2read.c
gdb/testsuite/gdb.fortran/entry_point.exp [new file with mode: 0755]
gdb/testsuite/gdb.fortran/entry_point.f90 [new file with mode: 0755]

index ed10e03812f381ccdb5c51e1c689df8d61ab87f6..945ca614ac16545489e385faa7b7d36b7d14f17c 100644 (file)
@@ -1425,6 +1425,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);
@@ -6911,6 +6915,25 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 
   switch (pdi->tag)
     {
+    case DW_TAG_entry_point:
+      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 != NULL,
+                            VAR_DOMAIN, LOC_BLOCK,
+                            &objfile->global_psymbols,
+                            addr, cu->language, objfile);
+      else
+       add_psymbol_to_list (actual_name, strlen (actual_name),
+                            built_actual_name != NULL,
+                            VAR_DOMAIN, LOC_BLOCK,
+                            &objfile->static_psymbols,
+                            addr, cu->language, objfile);
+      break;
     case DW_TAG_subprogram:
       addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);
       if (pdi->is_external || cu->language == language_ada)
@@ -7108,6 +7131,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 == NULL)
+    complaint (&symfile_complaints, _("DW_TAG_entry_point have to have a name"));
+  else
+    add_partial_symbol (pdi, cu);
+}
+
 /* Read a partial die corresponding to a subprogram and create a partial
    symbol for that subprogram.  When the CU language allows it, this
    routine also defines a partial symbol for each nested subprogram
@@ -7178,6 +7212,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 != NULL)
+       {
+         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.  */
@@ -8282,6 +8326,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);
@@ -12063,6 +12108,27 @@ 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 (PC_BOUNDS_INVALID == dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst))
+       return PC_BOUNDS_INVALID;
+
+      attr = dwarf2_attr (die, DW_AT_low_pc, cu);
+      if (!attr)
+       {
+         complaint (&symfile_complaints,
+                    _("DW_TAG_entry_point is missing DW_AT_low_pc"));
+         return PC_BOUNDS_INVALID;
+       }
+      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)
     {
@@ -15632,6 +15698,7 @@ load_partial_dies (const struct die_reader_specs *reader,
          && abbrev->tag != DW_TAG_constant
          && abbrev->tag != DW_TAG_enumerator
          && abbrev->tag != DW_TAG_subprogram
+         && abbrev->tag != DW_TAG_entry_point
          && abbrev->tag != DW_TAG_lexical_block
          && abbrev->tag != DW_TAG_variable
          && abbrev->tag != DW_TAG_namespace
@@ -15758,6 +15825,7 @@ load_partial_dies (const struct die_reader_specs *reader,
       if (load_all
          || abbrev->tag == DW_TAG_constant
          || abbrev->tag == DW_TAG_subprogram
+         || abbrev->tag == DW_TAG_entry_point
          || abbrev->tag == DW_TAG_variable
          || abbrev->tag == DW_TAG_namespace
          || part_die->is_declaration)
@@ -15799,7 +15867,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;
@@ -18440,6 +18510,20 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
          SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
          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.  */
+         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 = &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.  */
@@ -19124,6 +19208,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 100755 (executable)
index 0000000..5c3accf
--- /dev/null
@@ -0,0 +1,70 @@
+# Copyright 2016 Free Software Foundation, Inc.\r
+\r
+# This program is free software; you can redistribute it and/or modify\r
+# it under the terms of the GNU General Public License as published by\r
+# the Free Software Foundation; either version 3 of the License, or\r
+# (at your option) any later version.\r
+#\r
+# This program is distributed in the hope that it will be useful,\r
+# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+# GNU General Public License for more details.\r
+#\r
+# You should have received a copy of the GNU General Public License\r
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+\r
+if { [skip_fortran_tests] } { return -1 }\r
+\r
+standard_testfile .f90\r
+load_lib "fortran.exp"\r
+\r
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug f90}]} {\r
+    return -1\r
+}\r
+\r
+if ![runto MAIN__] then {\r
+    perror "couldn't run to breakpoint MAIN__"\r
+    continue\r
+}\r
+\r
+# Test if we can set a breakpoint via entry-point name\r
+set ept_name "foo"\r
+gdb_breakpoint $ept_name\r
+gdb_test "continue" \\r
+    [multi_line "Breakpoint $decimal, $ept_name \\(j=1, k=2, l=3, i1=4\\) at .*" \\r
+                ".*"] \\r
+    "continue to breakpoint: $ept_name"\r
+\r
+gdb_test "print j" "= 1" "print j, entered via $ept_name"\r
+gdb_test "print k" "= 2" "print k, entered via $ept_name"\r
+gdb_test "print l" "= 3" "print l, entered via $ept_name"\r
+gdb_test "print i1" "= 4" "print i1, entered via $ept_name"\r
+gdb_test "info args" \\r
+  [multi_line "j = 1" \\r
+              "k = 2" \\r
+              "l = 3" \\r
+              "i1 = 4"] \\r
+   "info args, entered via $ept_name"\r
+\r
+# Test if we can set a breakpoint via function name\r
+set ept_name "bar"\r
+gdb_breakpoint $ept_name\r
+gdb_test "continue" \\r
+    [multi_line "Breakpoint $decimal, $ept_name \\(i=4, j=5, k=6, i1=7\\) at .*" \\r
+                ".*"] \\r
+    "continue to breakpoint: $ept_name"\r
+\r
+gdb_test "print i" "= 4" "print i, entered via $ept_name"\r
+gdb_test "print j" "= 5" "print j, entered via $ept_name"\r
+gdb_test "print k" "= 6" "print k, entered via $ept_name"\r
+gdb_test "print i1" "= 7" "print i1, entered via $ept_name"\r
+\r
+set ept_name "tim"\r
+gdb_breakpoint $ept_name\r
+gdb_test "continue" \\r
+    [multi_line "Breakpoint $decimal, $ept_name \\(j=1\\) at .*" \\r
+                ".*"] \\r
+    "continue to breakpoint: $ept_name"\r
+\r
+gdb_test "print j" "= 1" "print j, entered via $ept_name"\r
+gdb_test "info args" "j = 1" "info args, entered via $ept_name"\r
diff --git a/gdb/testsuite/gdb.fortran/entry_point.f90 b/gdb/testsuite/gdb.fortran/entry_point.f90
new file mode 100755 (executable)
index 0000000..1aa6fbd
--- /dev/null
@@ -0,0 +1,48 @@
+! Copyright 2016 Free Software Foundation, Inc.\r
+!\r
+! This program is free software; you can redistribute it and/or modify\r
+! it under the terms of the GNU General Public License as published by\r
+! the Free Software Foundation; either version 3 of the License, or\r
+! (at your option) any later version.\r
+!\r
+! This program is distributed in the hope that it will be useful,\r
+! but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+! GNU General Public License for more details.\r
+!\r
+! You should have received a copy of the GNU General Public License\r
+! along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+\r
+program TestEntryPoint\r
+\r
+  call foo(1,2,3,4)\r
+  call bar(4,5,6,7)\r
+  call tim(1)\r
+\r
+end program TestEntryPoint\r
+\r
+  subroutine bar(I,J,K,I1)\r
+    INTEGER I,J,K,L,I1\r
+    INTEGER A\r
+    REAL    C\r
+\r
+    A = 0\r
+    C = 0.0\r
+\r
+    A = I + K + I1\r
+    goto 1000\r
+\r
+    entry foo(J,K,L,I1)\r
+    A = J + K + L + I1\r
+\r
+200 C = J\r
+    goto 1000\r
+\r
+    entry tim(J)\r
+    goto 200\r
+\r
+1000 A = C + 1\r
+     C = J * 1.5\r
+\r
+    return\r
+  end subroutine\r