From patchwork Wed Sep 25 22:39:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 34663 Received: (qmail 37228 invoked by alias); 25 Sep 2019 22:39:35 -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 37219 invoked by uid 89); 25 Sep 2019 22:39:34 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=gdblinespec, gdb.linespec, UD:gdb.linespec, UD:linespec X-HELO: mail-wr1-f66.google.com Received: from mail-wr1-f66.google.com (HELO mail-wr1-f66.google.com) (209.85.221.66) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 25 Sep 2019 22:39:30 +0000 Received: by mail-wr1-f66.google.com with SMTP id l3so450528wru.7 for ; Wed, 25 Sep 2019 15:39:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=J1Fs6WXeAZ0degCucVtnFZVo4m8AgYErN2PoBwf571k=; b=O08TxIr8f+B/5ygtJqfkTrjXzNVDZc38VCuwlrp7Sz2kdIHWf+deiEs4hfTIyQ2KX3 dPKn6F45LizNUlsZDjOhKRcewuuruFPuoOcAaljzCkHHZkRrgGzjuAbaqwKc0JSpIPUJ JK94lhAdOC6wkZIR6KiNVuF38TIAHekU+OiC+dL3lJoIjletCNujB4jnu8SvcqRdKknP s9g0yTeZ7RNAZ9a6m+PYYer5A2NEUNakLJTe7KRGimhPmCkiIoGkG0rOY27Ev/V4rM9N DQ9cpBtQMF3dTVGpInv2+qScLnOLTMiZSXGpm9IycMuAcfds1hUz/YkNT7azAa2ohEBu Y/DA== Return-Path: Received: from localhost (host86-128-12-122.range86-128.btcentralplus.com. [86.128.12.122]) by smtp.gmail.com with ESMTPSA id y186sm925281wmb.41.2019.09.25.15.39.26 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 25 Sep 2019 15:39:26 -0700 (PDT) Date: Wed, 25 Sep 2019 23:39:25 +0100 From: Andrew Burgess To: Simon Marchi Cc: gdb-patches@sourceware.org, Richard Bunt Subject: Re: [PATCH 1/2] gdb/fortran: Nested subroutine support Message-ID: <20190925223925.GP4962@embecosm.com> References: <8552e67173720858f0feb35685c1e9ed95bc5939.1567546519.git.andrew.burgess@embecosm.com> <143ec768-0ff9-b737-05aa-3619453998e1@simark.ca> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <143ec768-0ff9-b737-05aa-3619453998e1@simark.ca> X-Fortune: Every day it's the same thing -- variety. I want something different. X-Editor: GNU Emacs [ http://www.gnu.org/software/emacs ] User-Agent: Mutt/1.9.2 (2017-12-15) X-IsSubscribed: yes * Simon Marchi [2019-09-24 22:09:34 -0400]: > On 2019-09-03 5:38 p.m., Andrew Burgess wrote: > > This patch is a rebase and update of the following three patches: > > > > https://sourceware.org/ml/gdb-patches/2018-11/msg00298.html > > https://sourceware.org/ml/gdb-patches/2018-11/msg00302.html > > https://sourceware.org/ml/gdb-patches/2018-11/msg00301.html > > > > I have merged these together into a single commit as the second patch, > > adding scope support to nested subroutines, means that some of the > > changes in the first patch are now no longer useful and would have to > > be backed out. The third patch is tightly coupled to the changes in > > the second of these patches and I think deserves to live together with > > it. > > > > There is an extra change in cp-namespace.c that is new, this resolves > > an issue with symbol lookup when placing breakpoints from within > > nested subroutines. > > > > There is also an extra test added to this commit 'nested-funcs-2.exp' > > that was written by Richard Bunt from ARM, this offers some additional > > testing of breakpoints on nested functions. > > > > After this commit it is possible to place breakpoints on nested > > Fortran subroutines and functions by using a fully scoped name, for > > example, given this simple Fortran program: > > > > program greeting > > call message > > contains > > subroutine message > > print *, "Hello World" > > end subroutine message > > end program greeting > > > > It is possible to place a breakpoint in 'message' with: > > > > (gdb) break greeting::message > > Breakpoint 1 at 0x4006c9: file basic.f90, line 5. > > > > What doesn't work with this commit is placing a breakpoint like this: > > > > (gdb) break message > > Function "message" not defined. > > > > Making this work will come in a later commit. > > Hi Andrew, > > I tried to look at and understand the cp-namespace.c change. I am not > knowledgeable enough in that area to convince myself 100% that the change > is fine. But to my eyes it does not look wrong. > > The code with your patch makes more sense to me: why would we initiate a > search in the VAR_DOMAIN if the requested domain was a different one. > > I was trying to figure out if, for C++, `domain` could ever be something > else than VAR_DOMAIN, but couldn't find a case where it was something else. > So it would suggest that for C++, you change is a no-op, therefore ok. And > I guess that since you did that change, it's because it happens that `domain` > is something else than VAR_DOMAIN when debugging Fortran. And as I said above, > it wouldn't make sense to return something from the VAR_DOMAIN when another > domain is requested. The following C++ tests all have domain != VAR_DOMAIN: gdb.linespec/cpcompletion.exp gdb.linespec/ls-errs.exp gdb.cp/cplusfuncs.exp gdb.cp/typeid.exp However, non of them have get to the specific area of code that I changed with a scope of type FUNC or METHOD. As for where this problem hits in Fortran, the issue springs from some lookup code in f-exp.y, around line 1288 - where symbol names are looked up as STRUCT, VAR, MODULE in that order. The problem is that we end up finding VAR symbols when we are looking for a STRUCT, with the result that we find things we shouldn't. The real example is the test gdb.fortran/nested-funcs-2.exp, but I'll try to sketch out what happens, consider this fortran code: sub outer_function integer :: my_var contains sub inner_function integer :: my_var ! Break here. end end We stop at 'Break here' and then ask GDB to print 'my_var'. Thanks to the lookup code mentioned above we first try to find the symbol as a STRUCT in the local scope - we don't find anything. Then we examine the scope for our current location, we're in outer_function::inner_function, and outer_function is a FUNC, so we enter the block of code that I modified in the patch (previously all we needed was the scope to be a FUNC or METHOD and the domain to be not LABEL), so then we search outer_domain for VAR, and we find the outer my_var, which we returned. The result was that we were unable to find the inner 'my_var', but would always find the outer 'my_var'. There was a similar issue with placing breakpoints on functions from within included modules - ironically in that case GDB would allow the user to place a breakpoint on functions from modules without providing a nested scope, something they shouldn't be able to do after this first patch - it's only the second patch in this series that provides this functionality. The problem is that even though the module functions were being found GDB was getting very confused thinking it had actually found a variable - I think the wrong block was being associated with the symbol somewhere in the search.... I stopped digging into all the ways things were going wrong at some point. Anyway, with this fix in place things seem to behave much nicer. > > Also this reminded me that GNU C also allows nested functions, like this: > > int main() { > void hello() { > printf("hello "); > > void world() { > printf("world\n"); > } > > world(); > } > > hello(); > return 0; > } > > But GDB doesn't let you put breakpoints on these inner functions: > > (gdb) b hello > Function "hello" not defined. > Make breakpoint pending on future shared library load? (y or [n]) n > (gdb) b main::hello > Function "main::hello" not defined. > Make breakpoint pending on future shared library load? (y or [n]) n > > I suppose it's a very similar situation than what you're doing here > for Fortran. Yes, I might take a look at that, could be a fun little fix. > > In Fortran, is the "::" operator a thing, or it's the GDB-specific way > of accessing inner elements? The '::' is just a GDB thing to access nested scopes. Fortran requires USE directives to gain access to modules. With the second patch in this series in most cases a user can just places breakpoints using unqualified names, but you'll still need the ability to provide a scope for accessing variables and placing breakpoints for things that are masked in the current scope. In the above example, from 'Break here' you might want to 'p outer_function::my_var' for example. Anyway, the '::' is documented in the Fortran section of the manual. > > > @@ -8847,12 +8851,15 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) > > case DW_TAG_subprogram: > > addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr) > > - baseaddr); > > - if (pdi->is_external || cu->language == language_ada) > > - { > > - /* brobecker/2007-12-26: Normally, only "external" DIEs are part > > - of the global scope. But in Ada, we want to be able to access > > - nested procedures globally. So all Ada subprograms are stored > > - in the global scope. */ > > + if (pdi->is_external > > + || cu->language == language_ada > > + || (cu->language == language_fortran > > + && pdi->die_parent > > pdi->die_parent != NULL > > > + && pdi->die_parent->tag == DW_TAG_subprogram)) > > + { > > + /* Normally, only "external" DIEs are part of the global scope. > > + But in Ada and Fortran, we want to be able to access nested procedures > > + globally. So all Ada subprograms are stored in the global scope. */ > > I guess the last sentence should mention Fortran too. Thanks, I fixed both of these. Andrew --- commit 9c03c7303e8ad2f2d57a0fc28984b0a3256622fc Author: Andrew Burgess Date: Thu Aug 15 14:57:13 2019 +0100 gdb/fortran: Nested subroutine support This patch is a rebase and update of the following three patches: https://sourceware.org/ml/gdb-patches/2018-11/msg00298.html https://sourceware.org/ml/gdb-patches/2018-11/msg00302.html https://sourceware.org/ml/gdb-patches/2018-11/msg00301.html I have merged these together into a single commit as the second patch, adding scope support to nested subroutines, means that some of the changes in the first patch are now no longer useful and would have to be backed out. The third patch is tightly coupled to the changes in the second of these patches and I think deserves to live together with it. There is an extra change in cp-namespace.c that is new, this resolves an issue with symbol lookup when placing breakpoints from within nested subroutines. There is also an extra test added to this commit 'nested-funcs-2.exp' that was written by Richard Bunt from ARM, this offers some additional testing of breakpoints on nested functions. After this commit it is possible to place breakpoints on nested Fortran subroutines and functions by using a fully scoped name, for example, given this simple Fortran program: program greeting call message contains subroutine message print *, "Hello World" end subroutine message end program greeting It is possible to place a breakpoint in 'message' with: (gdb) break greeting::message Breakpoint 1 at 0x4006c9: file basic.f90, line 5. What doesn't work with this commit is placing a breakpoint like this: (gdb) break message Function "message" not defined. Making this work will come in a later commit. gdb/ChangeLog: * cp-namespace.c (cp_search_static_and_baseclasses): Only search for nested static variables when searchin VAR_DOMAIN. * dwarf2read.c (add_partial_symbol): Add nested subroutines to the global scope, update comment. (add_partial_subprogram): Call add_partial_subprogram recursively for nested subroutines when processinng Fortran. (load_partial_dies): Process the child entities of a subprogram when processing Fortran. (partial_die_parent_scope): Handle building scope for Fortran nested functions. (process_die): Record that nested functions have a scope. (new_symbol): Always record Fortran subprograms on the global symbol list. (determine_prefix): How to build the prefix for Fortran subprograms. gdb/testsuite/ChangeLog: * gdb.fortran/nested-funcs.exp: Tests for placing breakpoints on nested functions. * gdb.fortran/nested-funcs.f90: Update expected results. * gdb.fortran/nested-funcs-2.exp: New file. * gdb.fortran/nested-funcs-2.f90: New file. gdb/doc/ChangeLog: * doc/gdb.texinfo (Fortran Operators): Describe scope operator. diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index 5b352d1d77b..e15b77e701d 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -278,8 +278,9 @@ cp_search_static_and_baseclasses (const char *name, /* If the scope is a function/method, then look up NESTED as a local static variable. E.g., "print 'function()::static_var'". */ - if (TYPE_CODE (scope_type) == TYPE_CODE_FUNC - || TYPE_CODE (scope_type) == TYPE_CODE_METHOD) + if ((TYPE_CODE (scope_type) == TYPE_CODE_FUNC + || TYPE_CODE (scope_type) == TYPE_CODE_METHOD) + && domain == VAR_DOMAIN) return lookup_symbol (nested, SYMBOL_BLOCK_VALUE (scope_sym.symbol), VAR_DOMAIN, NULL); diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index f2713c03960..cd1d1c8abee 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -16554,6 +16554,10 @@ types. Also suitable for unions. As unions aren't part of regular Fortran, this can only happen when accessing a register that uses a gdbarch-defined union type. +@item :: +The scope operator. Normally used to access variables in modules or +to set breakpoints on subroutines nested in modules or in other +subroutines (internal subroutines). @end table @node Fortran Defaults diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 1052501c351..6f99c3425c7 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -8816,6 +8816,7 @@ partial_die_parent_scope (struct partial_die_info *pdi, return NULL; } + /* Nested subroutines in Fortran get a prefix. */ if (pdi->tag == DW_TAG_enumerator) /* Enumerators should not get the name of the enumeration as a prefix. */ parent->scope = grandparent_scope; @@ -8825,7 +8826,10 @@ partial_die_parent_scope (struct partial_die_info *pdi, || parent->tag == DW_TAG_class_type || parent->tag == DW_TAG_interface_type || parent->tag == DW_TAG_union_type - || parent->tag == DW_TAG_enumeration_type) + || parent->tag == DW_TAG_enumeration_type + || (cu->language == language_fortran + && parent->tag == DW_TAG_subprogram + && pdi->tag == DW_TAG_subprogram)) { if (grandparent_scope == NULL) parent->scope = parent->name; @@ -8916,12 +8920,16 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) case DW_TAG_subprogram: addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr) - baseaddr); - if (pdi->is_external || cu->language == language_ada) - { - /* brobecker/2007-12-26: Normally, only "external" DIEs are part - of the global scope. But in Ada, we want to be able to access - nested procedures globally. So all Ada subprograms are stored - in the global scope. */ + if (pdi->is_external + || cu->language == language_ada + || (cu->language == language_fortran + && pdi->die_parent != NULL + && pdi->die_parent->tag == DW_TAG_subprogram)) + { + /* Normally, only "external" DIEs are part of the global scope. + But in Ada and Fortran, we want to be able to access nested + procedures globally. So all Ada and Fortran subprograms are + stored in the global scope. */ add_psymbol_to_list (actual_name, strlen (actual_name), built_actual_name != NULL, VAR_DOMAIN, LOC_BLOCK, @@ -9177,7 +9185,7 @@ add_partial_subprogram (struct partial_die_info *pdi, if (! pdi->has_children) return; - if (cu->language == language_ada) + if (cu->language == language_ada || cu->language == language_fortran) { pdi = pdi->die_child; while (pdi != NULL) @@ -10613,6 +10621,12 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) read_type_unit_scope (die, cu); break; case DW_TAG_subprogram: + /* Nested subprograms in Fortran get a prefix. */ + if (cu->language == language_fortran + && die->parent != NULL + && die->parent->tag == DW_TAG_subprogram) + cu->processing_has_namespace_info = true; + /* Fall through. */ case DW_TAG_inlined_subroutine: read_func_scope (die, cu); break; @@ -18640,10 +18654,10 @@ load_partial_dies (const struct die_reader_specs *reader, inside functions to find template arguments (if the name of the function does not already contain the template arguments). - 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. */ + For Ada and Fortran, we need to scan the children of subprograms + and lexical blocks as well because these languages allow the + definition of nested entities that could be interesting for the + debugger, such as nested subprograms for instance. */ if (last_die->has_children && (load_all || last_die->tag == DW_TAG_namespace @@ -18658,7 +18672,8 @@ load_partial_dies (const struct die_reader_specs *reader, || last_die->tag == DW_TAG_interface_type || last_die->tag == DW_TAG_structure_type || last_die->tag == DW_TAG_union_type)) - || (cu->language == language_ada + || ((cu->language == language_ada + || cu->language == language_fortran) && (last_die->tag == DW_TAG_subprogram || last_die->tag == DW_TAG_lexical_block)))) { @@ -21619,14 +21634,15 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, SYMBOL_ACLASS_INDEX (sym) = LOC_BLOCK; attr2 = dwarf2_attr (die, DW_AT_external, cu); if ((attr2 && (DW_UNSND (attr2) != 0)) - || cu->language == language_ada) + || cu->language == language_ada + || cu->language == language_fortran) { /* Subprograms marked external are stored as a global symbol. - Ada subprograms, whether marked external or not, are always - stored as a global symbol, because we want to be able to - access them globally. For instance, we want to be able - to break on a nested subprogram without having to - specify the context. */ + Ada and Fortran subprograms, whether marked external or + not, are always stored as a global symbol, because we want + to be able to access them globally. For instance, we want + to be able to break on a nested subprogram without having + to specify the context. */ list_to_add = cu->get_builder ()->get_global_symbols (); } else @@ -22621,6 +22637,16 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu) return name; } return ""; + case DW_TAG_subprogram: + /* Nested subroutines in Fortran get a prefix with the name + of the parent's subroutine. */ + if (cu->language == language_fortran) + { + if ((die->tag == DW_TAG_subprogram) + && (dwarf2_name (parent, cu) != NULL)) + return dwarf2_name (parent, cu); + } + return determine_prefix (parent, cu); case DW_TAG_enumeration_type: parent_type = read_type_die (parent, cu); if (TYPE_DECLARED_CLASS (parent_type)) diff --git a/gdb/testsuite/gdb.fortran/nested-funcs-2.exp b/gdb/testsuite/gdb.fortran/nested-funcs-2.exp new file mode 100644 index 00000000000..e23d8bad4b2 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/nested-funcs-2.exp @@ -0,0 +1,156 @@ +# Copyright 2019 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 . + +# Further testing of placing breakpoints in nested subroutines. + +if {[skip_fortran_tests]} { return -1 } +load_lib "fortran.exp" + +standard_testfile ".f90" + +if {[prepare_for_testing ${testfile}.exp ${testfile} \ + ${srcfile} {debug f90}]} { + return -1 +} + +set int4 [fortran_int4] + +# When WITH_SRC_PREFIX_P is true then some symbol references will be +# prefixed with the filename. When WITH_NEST_PREFIX_P is true then +# nested subroutine symbols will be prefixed with their parent +# subroutine scope. +proc do_bp_tests {with_src_prefix_p with_nest_prefix_p} { + global testfile srcfile + global int4 + global hex + + clean_restart ${testfile} + + if { $with_src_prefix_p } { + set src_prefix "${srcfile}:" + } else { + set src_prefix "" + } + + if { $with_nest_prefix_p } { + set nest_prefix "contains_keyword::" + } else { + set nest_prefix "" + } + + # Test setting up breakpoints and otherwise examining nested + # functions before the program starts. + with_test_prefix "before start" { + foreach entry \ + [list \ + [list "increment" "${int4} \\\(${int4}\\\)"] \ + [list "increment_program_global" "${int4} \\\(void\\\)"] \ + [list "hidden_variable" "void \\\(void\\\)"]] { + set function [lindex $entry 0] + set type [lindex $entry 1] + + # Currently referencing symbols using 'info', + # 'whatis' and 'ptype' before the program is + # started doesn't work. This is the same + # behaviour we see in C++ so I don't think this + # is a failure, just a limitation in current GDB. + if { ${with_nest_prefix_p} } { + gdb_test "info symbol ${nest_prefix}${function}" \ + "${function} in section .*" + gdb_test "whatis ${nest_prefix}${function}" "type = ${type}" + gdb_test "ptype ${nest_prefix}${function}" "type = ${type}" + gdb_test "print ${nest_prefix}${function}" "{${type}} $hex " + } + + gdb_breakpoint "${src_prefix}${nest_prefix}${function}" + } + } + + # Break on a contained function and run to it. + if {![runto ${src_prefix}[gdb_get_line_number "pre_init"]]} then { + perror "couldn't run to breakpoint pre_init" + continue + } + + # Call a contained function. + if { ${with_nest_prefix_p} } { + gdb_test "call ${nest_prefix}subroutine_to_call()" " called" + } + + # Break on another contained function and run to it. + gdb_breakpoint "${src_prefix}${nest_prefix}increment" + gdb_continue_to_breakpoint "increment" ".*increment = i \\\+ 1" + gdb_breakpoint ${src_prefix}[gdb_get_line_number "post_increment"] + gdb_continue_to_breakpoint "post_increment" + + # Check arguments and locals report the correct values. 12 is + # passed in and 13 is the result after adding 1. + gdb_test "info args" "i = 12" + gdb_test "info locals" " = 13" + + # Check we can see variables from an outer program scope. + gdb_breakpoint ${src_prefix}[gdb_get_line_number "post_increment_global"] + gdb_continue_to_breakpoint "post_increment_global" \ + ".*print \\\*, program_i ! post_increment_global" + gdb_test "info args" "No arguments." \ + "no argument subroutine has no arguments" + gdb_test "p program_i" " = 7" "printing outer scoped variable" + + # Stepping into a contained subroutine. + gdb_breakpoint ${src_prefix}[gdb_get_line_number "pre_step"] + gdb_continue_to_breakpoint "pre_step" ".*call step\\\(\\\) ! pre_step" + gdb_test "step" \ + ".*print '\\\(A\\\)', \\\"step\\\" ! post_step" \ + "step into the correct place" + + # Local hides program global. + gdb_breakpoint ${src_prefix}[gdb_get_line_number "post_hidden"] + gdb_continue_to_breakpoint "post_hidden" \ + ".*print \\\*, program_i ! post_hidden" + gdb_test "p program_i" " = 30" "printing hidden global" + + # Check that the methods in the container module still require the + # module name as context. + gdb_test_no_output "set confirm off" + gdb_test "break print_from_module" \ + "Function \\\"print_from_module\\\" not defined." + + # Check info symbol, whatis and ptype can find information on + # these nested functions. + foreach entry \ + [list \ + [list "increment" "${int4} \\\(${int4}\\\)"] \ + [list "increment_program_global" "${int4} \\\(void\\\)"]] { + set function [lindex $entry 0] + set type [lindex $entry 1] + with_test_prefix $function { + gdb_test "info symbol ${nest_prefix}$function" \ + "$function in section .*" + gdb_test "whatis ${nest_prefix}$function" \ + "type = ${type}" + gdb_test "ptype ${nest_prefix}$function" \ + "type = ${type}" + } + } +} + +foreach_with_prefix src_prefix { 0 1 } { + # For now this loop is only run with a value of '1'. A later + # patch will extend this with the value '0', at which point this + # comment will be removed. + foreach_with_prefix nest_prefix { 1 } { + do_bp_tests ${src_prefix} ${nest_prefix} + } +} diff --git a/gdb/testsuite/gdb.fortran/nested-funcs-2.f90 b/gdb/testsuite/gdb.fortran/nested-funcs-2.f90 new file mode 100644 index 00000000000..c3b4e2ba05f --- /dev/null +++ b/gdb/testsuite/gdb.fortran/nested-funcs-2.f90 @@ -0,0 +1,62 @@ +! Copyright 2019 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 . + +module container + implicit none + integer :: a + contains + subroutine print_from_module() + print *, "hello." + end subroutine +end module + +program contains_keyword + use container + implicit none + integer :: program_i, program_j + program_j = 12 ! pre_init + program_i = 7 + program_j = increment(program_j) ! pre_increment + program_i = increment_program_global() ! pre_increment_program_global + call subroutine_to_call() + call step() ! pre_step + call hidden_variable() + call print_from_module() + print '(I2)', program_j, program_i ! post_init + +contains + subroutine subroutine_to_call() + print *, "called" + end subroutine + integer function increment(i) + integer :: i + increment = i + 1 + print *, i ! post_increment + end function + integer function increment_program_global() + increment_program_global = program_i + 1 + ! Need to put in a dummy print here to break on as on some systems the + ! variables leave scope at "end function", but on others they do not. + print *, program_i ! post_increment_global + end function + subroutine step() + print '(A)', "step" ! post_step + end subroutine + subroutine hidden_variable() + integer :: program_i + program_i = 30 + print *, program_i ! post_hidden + end subroutine +end program contains_keyword diff --git a/gdb/testsuite/gdb.fortran/nested-funcs.exp b/gdb/testsuite/gdb.fortran/nested-funcs.exp index 2cfd402937a..613572ebebb 100755 --- a/gdb/testsuite/gdb.fortran/nested-funcs.exp +++ b/gdb/testsuite/gdb.fortran/nested-funcs.exp @@ -30,6 +30,10 @@ if ![runto MAIN__] then { continue } +# Test if we can set a breakpoint in a nested function +gdb_breakpoint "testnestedfuncs::sub_nested_outer" +gdb_continue_to_breakpoint "testnestedfuncs::sub_nested_outer" ".*local_int = 19" + # Test if we can access local and # non-local variables defined one level up. gdb_breakpoint [gdb_get_line_number "! BP_outer"] @@ -43,6 +47,10 @@ gdb_test "print local_int" "= 19" "print local_int in outer function" gdb_test "up" gdb_test "print index" "= 42" "print index at BP1, one frame up" +# Test if we can set a breakpoint in a nested function +gdb_breakpoint "testnestedfuncs::sub_nested_inner" +gdb_continue_to_breakpoint "testnestedfuncs::sub_nested_inner" ".*local_int = 17" + # Test if we can access local and # non-local variables defined two level up. gdb_breakpoint [gdb_get_line_number "! BP_inner"] @@ -57,6 +65,18 @@ gdb_continue_to_breakpoint "! BP_outer_2" ".*! BP_outer_2" gdb_test "print local_int" "= 19" \ "print local_int in outer function, after sub_nested_inner" +# Test if we can set a breakpoint in public routine with the same name as the internal +gdb_breakpoint "sub_nested_outer" +gdb_continue_to_breakpoint "sub_nested_outer" ".*name = 'sub_nested_outer external'" + +# Test if we can set a breakpoint in public routine with the same name as the internal +gdb_breakpoint "sub_with_sub_nested_outer::sub_nested_outer" +gdb_continue_to_breakpoint "sub_with_sub_nested_outer::sub_nested_outer" ".*local_int = 11" + +# Test if we can set a breakpoint in public routine with the same name as the internal +gdb_breakpoint "mod1::sub_nested_outer" +gdb_continue_to_breakpoint "mod1::sub_nested_outer" ".*name = 'sub_nested_outer_mod1'" + # Sanity check in main. gdb_breakpoint [gdb_get_line_number "! BP_main"] gdb_continue_to_breakpoint "! BP_main" ".*! BP_main" diff --git a/gdb/testsuite/gdb.fortran/nested-funcs.f90 b/gdb/testsuite/gdb.fortran/nested-funcs.f90 index 3431705a756..ce2f269e484 100755 --- a/gdb/testsuite/gdb.fortran/nested-funcs.f90 +++ b/gdb/testsuite/gdb.fortran/nested-funcs.f90 @@ -13,8 +13,62 @@ ! You should have received a copy of the GNU General Public License ! along with this program. If not, see . -program TestNestedFuncs +module mod1 + integer :: var_i = 1 + integer :: var_const + parameter (var_const = 20) + +CONTAINS + + SUBROUTINE sub_nested_outer + integer :: local_int + character (len=20) :: name + + name = 'sub_nested_outer_mod1' + local_int = 11 + + END SUBROUTINE sub_nested_outer +end module mod1 + +! Public sub_nested_outer +SUBROUTINE sub_nested_outer + integer :: local_int + character (len=16) :: name + + name = 'sub_nested_outer external' + local_int = 11 +END SUBROUTINE sub_nested_outer + +! Needed indirection to call public sub_nested_outer from main +SUBROUTINE sub_nested_outer_ind + character (len=20) :: name + + name = 'sub_nested_outer_ind' + CALL sub_nested_outer +END SUBROUTINE sub_nested_outer_ind + +! public routine with internal subroutine +SUBROUTINE sub_with_sub_nested_outer() + integer :: local_int + character (len=16) :: name + + name = 'subroutine_with_int_sub' + local_int = 1 + + CALL sub_nested_outer ! Should call the internal fct + +CONTAINS + SUBROUTINE sub_nested_outer + integer :: local_int + local_int = 11 + END SUBROUTINE sub_nested_outer + +END SUBROUTINE sub_with_sub_nested_outer + +! Main +program TestNestedFuncs + USE mod1, sub_nested_outer_use_mod1 => sub_nested_outer IMPLICIT NONE TYPE :: t_State @@ -22,10 +76,13 @@ program TestNestedFuncs END TYPE t_State TYPE (t_State) :: v_state - integer index + integer index, local_int index = 13 - CALL sub_nested_outer + CALL sub_nested_outer ! Call internal sub_nested_outer + CALL sub_nested_outer_ind ! Call external sub_nested_outer via sub_nested_outer_ind + CALL sub_with_sub_nested_outer ! Call external routine with nested sub_nested_outer + CALL sub_nested_outer_use_mod1 ! Call sub_nested_outer imported via module index = 11 ! BP_main v_state%code = 27