diff options
author | Bernhard Heckel <bernhard.heckel@intel.com> | 2016-05-31 11:11:51 +0200 |
---|---|---|
committer | Bernhard Heckel <bernhard.heckel@intel.com> | 2016-12-23 12:20:01 +0100 |
commit | 57ed8b65ccd5ab8391a83d064e0bca5301ff0f94 (patch) | |
tree | 7715ca3df85dc654d4d0b83460efa711e098fb5b | |
parent | 4eabf3446367832693a1baf145f6ff02baae197b (diff) | |
download | binutils-gdb-57ed8b65ccd5ab8391a83d064e0bca5301ff0f94.tar.gz |
Dwarf: Fortran, support DW_TAG_entry_point.
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
-rw-r--r-- | gdb/dwarf2read.c | 87 | ||||
-rwxr-xr-x | gdb/testsuite/gdb.fortran/entry_point.exp | 70 | ||||
-rwxr-xr-x | gdb/testsuite/gdb.fortran/entry_point.f90 | 48 |
3 files changed, 204 insertions, 1 deletions
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index ed10e03812f..945ca614ac1 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -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 index 00000000000..5c3accf3505 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/entry_point.exp @@ -0,0 +1,70 @@ +# Copyright 2016 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 100755 index 00000000000..1aa6fbd9ab3 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/entry_point.f90 @@ -0,0 +1,48 @@ +! Copyright 2016 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
|