From patchwork Mon Jun 5 11:04:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 70599 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5222C3850218 for ; Mon, 5 Jun 2023 11:06:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5222C3850218 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1685963171; bh=0bX1cCt92s11rxouVAIFn7LiBTA44K9hLkh0jgz3LWA=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=DVUVzW/S7RNUjoTu6TZCpKD4l4mJXbUo/VQvnJFz5dId+7fVzZpCyYaLI+lQ7AGNT rn3XFPqF5PnCmdO0ShiYfVde57RbK2BkTV90iP5H43SbUfuseoEBsXCE6QgH+MOQhH 0ejdTIZlTg+qjjvbHGoPKYekma+/j7B8OHN0/RYw= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by sourceware.org (Postfix) with ESMTPS id 510EE384645E for ; Mon, 5 Jun 2023 11:05:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 510EE384645E X-IronPort-AV: E=McAfee;i="6600,9927,10731"; a="359653647" X-IronPort-AV: E=Sophos;i="6.00,217,1681196400"; d="scan'208";a="359653647" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 04:05:14 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10731"; a="741683150" X-IronPort-AV: E=Sophos;i="6.00,217,1681196400"; d="scan'208";a="741683150" Received: from labpc2030.iul.intel.com (HELO localhost) ([172.28.48.46]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 04:05:13 -0700 To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com Subject: [PATCH v2 4/4] gdb: Skip trampoline frames in the stack for printing or finish command. Date: Mon, 5 Jun 2023 13:04:10 +0200 Message-Id: <20230605110410.3078-5-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230605110410.3078-1-abdul.b.ijaz@intel.com> References: <20230605110410.3078-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Abdul Basit Ijaz via Gdb-patches From: "Ijaz, Abdul B" Reply-To: Abdul Basit Ijaz Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Before the change, GDB prints the frames indicated by the compiler with DIE "DW_AT_trampoline" in the backtrace and finish command, but for better user experience, all such frames can be hidden from the user. So, after this change, now such frames are not printed any more in the backtrace command and also the 'finish' command skips the trampoline calls. So far, this DIE is added to DWARF only by the IFX compiler, so gdb.fortran/mixed-lang-stack test used to fail for this compiler because of these extra trampoline frames in the backtrace. After the commit, those trampoline frames are filtered so test is updated accordingly to handle the frame level of the filtered frames. Backtrace output in this test before the change: bt -frame-arguments all ''' ''' (gdb) FAIL: gdb.fortran/mixed-lang-stack.exp: lang=auto: bt -frame-arguments all Now, after the change: bt -frame-arguments all ''' ''' (gdb) PASS: gdb.fortran/mixed-lang-stack.exp: lang=auto: bt -frame-arguments all Below is the example where IFX emits DW_at_trampoline for functions first and second trampoline calls as following: F90 reproducer info: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-backtrace end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change at line with comment 'breakpt-backtrace': (gdb) backtrace 3 (gdb) finish Run till exit from #0 second (x=20, y=9) at test.f90:4 second_.t74p.t75p () at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt Value returned is $1 = 180 After the change: (gdb) backtrace 3 (gdb) finish Run till exit from #0 second (x=20, y=9) at test.f90:4 0x0000000000404333 in first (num1=16, num2=3) at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt Value returned is $1 = 180 New test func-trampoline is also added to test this in both backtrace and finish commands for Intel(R) Fortran Compiler. 2023-06-05 Abdul Basit Ijaz Reviewed-By: Eli Zaretskii --- gdb/doc/gdb.texinfo | 40 +++++++---- gdb/infcmd.c | 14 ++++ gdb/infrun.c | 8 +-- gdb/infrun.h | 6 ++ gdb/stack.c | 8 +++ gdb/symtab.c | 12 ++++ gdb/symtab.h | 5 ++ gdb/testsuite/gdb.fortran/func-trampoline.exp | 69 +++++++++++++++++++ gdb/testsuite/gdb.fortran/func-trampoline.f90 | 39 +++++++++++ .../gdb.fortran/mixed-lang-stack.exp | 10 ++- 10 files changed, 189 insertions(+), 22 deletions(-) create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.exp create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.f90 diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 44aba03fc44..627335a78a7 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6376,23 +6376,33 @@ so-called trampoline functions, which wrap the actual function call (the target of the trampoline). The compiler might mark such a trampoline in its debug information. Often, such trampolines do not have any source line information associated with them which will lead the @code{step} command to -behave like a @code{next} and skip the function call completely. +behave like a @code{next} and skip the function call completely. Similarly, +the @code{finish} command will return to some trampoline frame entry instead +of returning to the call site. The @code{set skip-trampoline-functions on} command will cause the @code{step} -command to treat these trampolines differently. When issuing a @code{step} at -the call site of a trampoline function if @code{skip-trampoline-functions} is -set @value{GDBN} will attempt to determine the target of the trampoline and -then step through the trampoline stopping at the target. If the target could -not be found or was not given in the debug info, @value{GDBN} will simply -continue execution until it leaves the trampoline code again, even if the -trampoline has no line info associated with it. When returning from a target -function call and stepping back into the trampoline, @value{GDBN} will again -step through the trampoline towards the call site. -Additionally, even if stopped in a trampoline function with source line -information, issuing a @code{step} will prompt @value{GDBN} to resume execution -until leaving the trampoline region again. The @code{stepi} command is not -affected by the setting which is enabled by default. Currently, only -DWARF trampolines marked via DW_AT_trampoline are supported by this. +and the @code{finish} command to treat these trampolines differently. + +When issuing a @code{step} at the call site of a trampoline function, if +@code{skip-trampoline-functions} is set, @value{GDBN} will attempt to determine +the target of the trampoline and then step through the trampoline stopping at +the target. If the target could not be found or was not given in the debug +info, @value{GDBN} will simply continue execution until it leaves the +trampoline code again, even if the trampoline has no line info associated +with it. When returning from a target function call and stepping back into +the trampoline, @value{GDBN} will again step through the trampoline towards +the call site. Additionally, even if stopped in a trampoline function with +source line information, issuing a @code{step} will prompt @value{GDBN} to +resume execution until leaving the trampoline region again. The @code{stepi} +command is not affected by the setting which is enabled by default. + +When issuing a @code{finish} command at the target of a trampoline function, if +@code{skip-trampoline-functions} is set, @value{GDBN} will ignore all the +trampoline frames and will reach the first non-trampoline frame to return to +the call site of the current function. + +Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by +this. @item set skip-trampoline-functions off Causes the @code{step} command to completely ignore any trampoline information diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 978c07f176d..bf022072df5 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1840,6 +1840,20 @@ finish_command (const char *arg, int from_tty) frame = get_prev_frame (get_selected_frame (_("No selected frame."))); if (frame == 0) error (_("\"finish\" not meaningful in the outermost frame.")); + + if (skip_trampoline_functions) + { + for (int i = 0; i < MAX_TRAMPOLINE_CHAIN_SIZE + && (frame != nullptr) + && in_trampoline_frame (frame); ++i) + frame = get_prev_frame (frame); + + if (frame == nullptr) + error (_("\"finish\" not meaningful in the outermost non-trampoline \ +frame. Consider running \"set skip-trampoline-functions off\", to stop in \ +trampoline frames for the \"finish\" command.")); + } + frame.prepare_reinflate (); clear_proceed_status (0); diff --git a/gdb/infrun.c b/gdb/infrun.c index 278393192a4..1d0c43ae166 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -165,7 +165,7 @@ static bool detach_fork = true; DW_AT_trampoline by the compiler. If false, GDB will ignore the attribute. */ -static bool skip_trampoline_functions = true; +bool skip_trampoline_functions = true; bool debug_infrun = false; static void @@ -9916,9 +9916,9 @@ Options are 'forward' or 'reverse'."), &skip_trampoline_functions, _("\ Set whether gdb attempts to hide trampolines marked in the debug info."), _("\ Show whether gdb attempts to hide trampolines marked in the debug info."), _("\ -If on, while stepping gdb will skip through functions and inlined functions\n\ -marked as trampolines by the compiler. If off, gdb will ignore such function\n\ -trampolines."), +If on, the step and finish commands will skip through functions and inlined\n\ +functions marked as trampolines by the compiler. If off, gdb will ignore\n\ +such function trampolines."), nullptr, show_skip_trampoline_functions, &setlist, &showlist); diff --git a/gdb/infrun.h b/gdb/infrun.h index 55dd0672895..07dabaa0fbb 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -106,6 +106,12 @@ extern bool non_stop; starting an inferior. */ extern bool disable_randomization; +/* If set (default) GDB will step through functions/inlined subroutines marked + DW_AT_trampoline by the compiler. If false, GDB will ignore the + attribute. */ + +extern bool skip_trampoline_functions; + /* Returns a unique identifier for the current stop. This can be used to tell whether a command has proceeded the inferior past the current location. */ diff --git a/gdb/stack.c b/gdb/stack.c index 0fd797836dc..19179862a3f 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -2077,6 +2077,14 @@ backtrace_command_1 (const frame_print_options &fp_opts, QUIT; fi.prepare_reinflate (); + if (in_trampoline_frame (fi)) + { + /* Trampoline frames are not printed so they are not counted in + the backtrace limit. */ + count++; + continue; + } + /* Don't use print_stack_frame; if an error() occurs it probably means further attempts to backtrace would fail (on the other hand, perhaps the code does or could be fixed to make sure diff --git a/gdb/symtab.c b/gdb/symtab.c index 1f59a5da54e..01b187948ac 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4082,6 +4082,18 @@ in_trampoline_function (CORE_ADDR pc) /* See symtab.h. */ +bool +in_trampoline_frame (frame_info_ptr fi) +{ + CORE_ADDR pc; + if (get_frame_pc_if_available (fi, &pc)) + return in_trampoline_function (pc); + + return false; +} + +/* See symtab.h. */ + CORE_ADDR find_function_trampoline_target (CORE_ADDR pc) { diff --git a/gdb/symtab.h b/gdb/symtab.h index 328400fea04..590c3a208d5 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -2260,6 +2260,11 @@ extern CORE_ADDR find_solib_trampoline_target (frame_info_ptr, CORE_ADDR); extern bool in_trampoline_function (CORE_ADDR pc); +/* Return whether or not the pc of current frame is within a block that belongs + to a function that is marked as a trampoline by the compiler. */ + +extern bool in_trampoline_frame (frame_info_ptr); + /* Find the target of a trampoline function marked via the DW_AT_trampoline attribute and return its address. Returns 0 if the pc is not contained in a trampoline function (inlined or not). If DW_AT_trampoline diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp new file mode 100644 index 00000000000..3bc4d1c0714 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp @@ -0,0 +1,69 @@ +# Copyright 2023 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 . + +# Test finish and backtrace commands for functions with trampoline +# calls. Also checks if trampoline frames are filtered while printing +# stack and finish command returns to real function. + +require allow_fortran_tests + +if {![test_compiler_info {ifx-*} f90]} { + untested "Test is only applicable for IFX where\ + compiler emits trampoline DIE in Dwarf" + return -1 +} + +standard_testfile ".f90" +load_lib fortran.exp + +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + {debug f90}]} { + return -1 +} + +if {![fortran_runto_main]} { + return -1 +} + +set inner_loc [gdb_get_line_number "second-breakpt"] +set middle_loc [gdb_get_line_number "first-breakpt"] +set outer_loc [gdb_get_line_number "main-outer-loc"] +set fill "\[^\r\n\]*" + +set inner_desc "second \\(x=20, y=9\\) at ${fill}$srcfile:$inner_loc" +set middle_desc "first \\(num1=16, num2=3\\) at ${fill}$srcfile:$middle_loc" +set outer_desc ".* at .*$srcfile:$outer_loc" + +# Set breakpoint inside the innermost function 'second'. +gdb_breakpoint "$srcfile:$inner_loc" +gdb_continue_to_breakpoint "innermost-body" ".*$srcfile:$inner_loc.*" + +# Limit the backtrace to 3 frames and ensure both frames for first +# and second function are shown only and trampoline frames are filtered. +gdb_test "backtrace 3" [multi_line \ + "#$decimal.* $inner_desc" \ + "#$decimal.* $middle_desc" \ + "#$decimal.* $outer_desc.*"] \ +"backtrace, test trampoline frames are filtered" + +# Finish the function calls. Normally we expect to see a "Value +# returned is ..." line. +set value_returned "(\r\nValue returned is $valnum_re = 180)" + +gdb_test "finish" [multi_line \ + "Run till exit from #0 $fill second \\(x=20, y=9\\) $fill" \ + "${fill}first \\(num1=16, num2=3\\)${fill}" \ + "${fill}${value_returned}"] \ + "finish the innermost frame" diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.f90 b/gdb/testsuite/gdb.fortran/func-trampoline.f90 new file mode 100644 index 00000000000..652733b44fd --- /dev/null +++ b/gdb/testsuite/gdb.fortran/func-trampoline.f90 @@ -0,0 +1,39 @@ +! Copyright 2023 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 . + +! Source code for func-trampoline.exp. + +integer(kind=4) function second(x, y) + integer(kind=4), intent(in) :: x + integer(kind=4), intent(in) :: y + + second = x * y ! second-breakpt +end function + +integer(kind=4) function first(num1, num2) + integer(kind=4), intent(in) :: num1 + integer(kind=4), intent(in) :: num2 + + first = second (num1 + 4, num2 * 3) ! first-breakpt +end function + +program func_trampoline + integer(kind=4) :: total + + total = first(16, 3) ! main-outer-loc + + write(*,*) "Result is ", total, "\n" + ! Expected: 180 +end program func_trampoline diff --git a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp index 6ab3f8adeba..5f9d40909aa 100644 --- a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp +++ b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp @@ -41,7 +41,7 @@ set have_index [exec_has_index_section $binfile] # value to pass to GDB's 'set language ...' command. proc run_tests { lang } { with_test_prefix "lang=${lang}" { - global binfile hex have_index + global binfile hex have_index decimal clean_restart ${binfile} @@ -63,6 +63,10 @@ proc run_tests { lang } { set e_arg "\['\"\]abcdef\['\"\]" set 1b_args "\[^\r\n\]+$e_arg\[^\r\n\]+" set 1g_args "obj=\[^\r\n\]+" + # Generic decimal number is checked in regex for Frame #8 and #9 to + # handle filtered trampoline frames. Since Frame#8 and Frame#10 are + # set to trampoline in DWARF by IntelĀ® Fortran Compiler (ifx), they + # are not shown by the backtrace command. set bt_stack \ [multi_line \ "#0\\s+breakpt \\(\\) at \[^\r\n\]+" \ @@ -73,8 +77,8 @@ proc run_tests { lang } { "#5\\s+$hex in mixed_func_1d \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ "#6\\s+$hex in mixed_func_1c \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ "#7\\s+$hex in mixed_func_1b \\($1b_args\\) at \[^\r\n\]+" \ - "#8\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \ - "#9\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ] + "#$decimal\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \ + "#$decimal\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ] set main_args "argc=1, argv=${hex}( \[^\r\n\]+)?" set bt_stack_kfail \ [multi_line \