From patchwork Fri Aug 11 11:06:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wiederhake, Tim" X-Patchwork-Id: 22077 Received: (qmail 71030 invoked by alias); 11 Aug 2017 11:07:36 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 70915 invoked by uid 89); 11 Aug 2017 11:07:34 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_STOCKGEN, RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=child's, childs X-HELO: mga01.intel.com Received: from mga01.intel.com (HELO mga01.intel.com) (192.55.52.88) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 Aug 2017 11:07:32 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Aug 2017 04:07:23 -0700 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga001.jf.intel.com with ESMTP; 11 Aug 2017 04:07:22 -0700 Received: from ulvlx001.iul.intel.com (ulvlx001.iul.intel.com [172.28.207.17]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id v7BB7LVX007189; Fri, 11 Aug 2017 12:07:21 +0100 Received: from ulvlx001.iul.intel.com (localhost [127.0.0.1]) by ulvlx001.iul.intel.com with ESMTP id v7BB7E5R009145; Fri, 11 Aug 2017 13:07:14 +0200 Received: (from twiederh@localhost) by ulvlx001.iul.intel.com with LOCAL id v7BB7Evn009141; Fri, 11 Aug 2017 13:07:14 +0200 From: Tim Wiederhake To: gdb-patches@sourceware.org Cc: qiyaoltc@gmail.com, Bernhard Heckel Subject: [PATCH v3 4/6] Dwarf: Fortran, support DW_TAG_entry_point. Date: Fri, 11 Aug 2017 13:06:49 +0200 Message-Id: <1502449611-8865-5-git-send-email-tim.wiederhake@intel.com> In-Reply-To: <1502449611-8865-1-git-send-email-tim.wiederhake@intel.com> References: <1502449611-8865-1-git-send-email-tim.wiederhake@intel.com> X-IsSubscribed: yes From: Bernhard Heckel 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. xxxx-yy-zz Bernhard Heckel Tim Wiederhake gdb/ChangeLog: PR fortran/8043 PR fortran/9279 * gdb/dwarf2read.c (add_partial_symbol): Handle DW_TAG_entry_point. (add_partial_entry_point): New function. (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 file. * gdb.fortran/entry_point.exp: New file. --- gdb/dwarf2read.c | 97 +++++++++++++++++++++++++++++-- gdb/testsuite/gdb.fortran/entry_point.exp | 70 ++++++++++++++++++++++ gdb/testsuite/gdb.fortran/entry_point.f90 | 48 +++++++++++++++ 3 files changed, 211 insertions(+), 4 deletions(-) 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 b7df134..0349db0 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -1556,6 +1556,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); @@ -7132,6 +7136,27 @@ 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. */ + auto psymbols = pdi->die_parent->is_external + ? &objfile->global_psymbols : &objfile->static_psymbols; + + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name != NULL, VAR_DOMAIN, + LOC_BLOCK, 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) @@ -7333,6 +7358,18 @@ 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 @@ -7403,6 +7440,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. */ @@ -8509,6 +8556,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); @@ -12500,6 +12548,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 its enveloping subprogram and get the lowpc from DWARF. */ + ret = dwarf2_get_pc_bounds (die->parent, lowpc, highpc, cu, pst); + if (ret == PC_BOUNDS_NOT_PRESENT || ret == PC_BOUNDS_INVALID) + return ret; + + 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) { @@ -16030,6 +16099,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 @@ -16156,6 +16226,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) @@ -16181,7 +16252,9 @@ load_partial_dies (const struct die_reader_specs *reader, For Ada, we need to scan the children of subprograms and lexical blocks as well because Ada allows the definition of nested entities that could be interesting for the debugger, such as - nested subprograms for instance. */ + nested subprograms for instance. + + For Fortran, we need to scan the children of subprogram. */ if (last_die->has_children && (load_all || last_die->tag == DW_TAG_namespace @@ -16198,7 +16271,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; @@ -19061,12 +19136,25 @@ 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: case DW_TAG_subprogram: + /* Don't know any other language than fortran which is + using DW_TAG_entry_point. */ + if ((die->tag == DW_TAG_entry_point) + && (cu->language != language_fortran)) + break; + /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by finish_block. */ SYMBOL_ACLASS_INDEX (sym) = LOC_BLOCK; - attr2 = dwarf2_attr (die, DW_AT_external, cu); - if ((attr2 && (DW_UNSND (attr2) != 0)) + + /* 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->tag == DW_TAG_entry_point ? die->parent + : die, DW_AT_external, cu); + if ((attr2 != NULL && (DW_UNSND (attr2) != 0)) || cu->language == language_ada) { /* Subprograms marked external are stored as a global symbol. @@ -19746,6 +19834,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 0000000..1ed18a2 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/entry_point.exp @@ -0,0 +1,70 @@ +# Copyright 2017 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 . + +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 { + untested "couldn't run to breakpoint MAIN__" + return -1 +} + +# 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 "baz" +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 0000000..1d43930 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/entry_point.f90 @@ -0,0 +1,48 @@ +! Copyright 2017 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 . + +program TestEntryPoint + + call foo(1,2,3,4) + call bar(4,5,6,7) + call baz(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 baz(J) + goto 200 + +1000 A = C + 1 + C = J * 1.5 + + return + end subroutine