diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/dwarf2/frame-tailcall.c | 37 | ||||
-rw-r--r-- | gdb/findvar.c | 8 | ||||
-rw-r--r-- | gdb/frame.c | 8 | ||||
-rw-r--r-- | gdb/frame.h | 4 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-unwind-inline.c | 37 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-unwind-inline.exp | 49 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-unwind-inline.py | 71 |
9 files changed, 185 insertions, 48 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 98096bf..c86d7e4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,15 @@ 2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com> + PR python/22748 + * dwarf2/frame-tailcall.c (dwarf2_tailcall_sniffer_first): Remove + special handling for inline frames. + * findvar.c (value_of_register_lazy): Skip inline frames when + creating lazy register values. + * frame.c (frame_id_computed_p): Delete definition. + * frame.h (frame_id_computed_p): Delete declaration. + +2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com> + * NEWS: Mention additions to Python API. * python/py-arch.c (archpy_register_groups): New function. (arch_object_methods): Add 'register_groups' method. diff --git a/gdb/dwarf2/frame-tailcall.c b/gdb/dwarf2/frame-tailcall.c index 16dba2b..2d219f1 100644 --- a/gdb/dwarf2/frame-tailcall.c +++ b/gdb/dwarf2/frame-tailcall.c @@ -384,43 +384,8 @@ dwarf2_tailcall_sniffer_first (struct frame_info *this_frame, prev_gdbarch = frame_unwind_arch (this_frame); - /* The dwarf2 tailcall sniffer runs early, at the end of populating the - dwarf2 frame cache for the current frame. If there exists inline - frames inner (next) to the current frame, there is a good possibility - of that inline frame not having a computed frame id yet. - - This is because computing such a frame id requires us to walk through - the frame chain until we find the first normal frame after the inline - frame and then compute the normal frame's id first. - - Some architectures' compilers generate enough register location - information for a dwarf unwinder to fetch PC without relying on inner - frames (x86_64 for example). In this case the PC is retrieved - according to dwarf rules. - - But others generate less strict dwarf data for which assumptions are - made (like interpreting DWARF2_FRAME_REG_UNSPECIFIED as - DWARF2_FRAME_REG_SAME_VALUE). For such cases, GDB may attempt to - create lazy values for registers, and those lazy values must be - created with a valid frame id, but we potentially have no valid id. - - So, to avoid breakage, if we see a dangerous situation with inline - frames without a computed id, use safer functions to retrieve the - current frame's PC. Otherwise use the provided dwarf rules. */ - frame_info *next_frame = get_next_frame (this_frame); - /* Simulate frame_unwind_pc without setting this_frame->prev_pc.p. */ - if (next_frame != nullptr && get_frame_type (next_frame) == INLINE_FRAME - && !frame_id_computed_p (next_frame)) - { - /* The next frame is an inline frame and its frame id has not been - computed yet. */ - get_frame_register (this_frame, gdbarch_pc_regnum (prev_gdbarch), - (gdb_byte *) &prev_pc); - prev_pc = gdbarch_addr_bits_remove (prev_gdbarch, prev_pc); - } - else - prev_pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); + prev_pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); /* call_site_find_chain can throw an exception. */ chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc); diff --git a/gdb/findvar.c b/gdb/findvar.c index c7cd31c..7e9dab5 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -292,6 +292,14 @@ value_of_register_lazy (struct frame_info *frame, int regnum) next_frame = get_next_frame_sentinel_okay (frame); + /* In some cases NEXT_FRAME may not have a valid frame-id yet. This can + happen if we end up trying to unwind a register as part of the frame + sniffer. The only time that we get here without a valid frame-id is + if NEXT_FRAME is an inline frame. If this is the case then we can + avoid getting into trouble here by skipping past the inline frames. */ + while (get_frame_type (next_frame) == INLINE_FRAME) + next_frame = get_next_frame_sentinel_okay (next_frame); + /* We should have a valid next frame. */ gdb_assert (frame_id_p (get_frame_id (next_frame))); diff --git a/gdb/frame.c b/gdb/frame.c index ff27b9f..ac1016b 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -687,14 +687,6 @@ frame_id_build_wild (CORE_ADDR stack_addr) return id; } -bool -frame_id_computed_p (struct frame_info *frame) -{ - gdb_assert (frame != nullptr); - - return frame->this_id.p != 0; -} - int frame_id_p (struct frame_id l) { diff --git a/gdb/frame.h b/gdb/frame.h index e835d49..cfc1502 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -236,10 +236,6 @@ extern struct frame_id as the special identifier address are set to indicate wild cards. */ extern struct frame_id frame_id_build_wild (CORE_ADDR stack_addr); -/* Returns true if FRAME's id has been computed. - Returns false otherwise. */ -extern bool frame_id_computed_p (struct frame_info *frame); - /* Returns non-zero when L is a valid frame (a valid frame has a non-zero .base). The outermost frame is valid even without an ID. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 63fb5e6..8eae1ab 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,14 @@ 2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com> + PR python/22748 + * gdb.opt/inline-frame-tailcall.c: New file. + * gdb.opt/inline-frame-tailcall.exp: New file. + * gdb.python/py-unwind-inline.c: New file. + * gdb.python/py-unwind-inline.exp: New file. + * gdb.python/py-unwind-inline.py: New file. + +2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com> + * gdb.python/py-arch-reg-groups.exp: New file. 2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com> diff --git a/gdb/testsuite/gdb.python/py-unwind-inline.c b/gdb/testsuite/gdb.python/py-unwind-inline.c new file mode 100644 index 0000000..0cfe06d --- /dev/null +++ b/gdb/testsuite/gdb.python/py-unwind-inline.c @@ -0,0 +1,37 @@ +/* Copyright 2019-2020 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/>. */ + +volatile int global_var; + +int __attribute__ ((noinline)) +bar () +{ + return global_var; +} + +static inline int __attribute__ ((always_inline)) +foo () +{ + return bar (); +} + +int +main () +{ + int ans; + global_var = 0; + ans = foo (); + return ans; +} diff --git a/gdb/testsuite/gdb.python/py-unwind-inline.exp b/gdb/testsuite/gdb.python/py-unwind-inline.exp new file mode 100644 index 0000000..f7c65f6 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-unwind-inline.exp @@ -0,0 +1,49 @@ +# Copyright (C) 2020 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/>. + +# This script tests GDB's handling of using a Python unwinder in the +# presence of inlined frames. + +load_lib gdb-python.exp + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + debug] } { + return -1 +} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +# The following tests require execution. +if ![runto_main] then { + fail "can't run to main" + return 0 +} + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +gdb_breakpoint "foo" + +gdb_test "source ${pyfile}" "Python script imported" \ + "import python scripts" + +gdb_continue_to_breakpoint "foo" + +gdb_test_sequence "backtrace" "backtrace with dummy unwinder" { + "\\r\\n#0 foo \\(\\)" + "\\r\\n#1 main \\(\\)" +} diff --git a/gdb/testsuite/gdb.python/py-unwind-inline.py b/gdb/testsuite/gdb.python/py-unwind-inline.py new file mode 100644 index 0000000..7206a0b --- /dev/null +++ b/gdb/testsuite/gdb.python/py-unwind-inline.py @@ -0,0 +1,71 @@ +# Copyright (C) 2020 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/>. + +# A dummy stack unwinder used for testing the Python unwinders when we +# have inline frames. This unwinder will never claim any frames, +# instead, all it does it try to read all registers possible target +# registers as part of the frame sniffing process.. + +import gdb +from gdb.unwinder import Unwinder + +apb_global = None + +class dummy_unwinder (Unwinder): + """ A dummy unwinder that looks at a bunch of registers as part of + the unwinding process.""" + + class frame_id (object): + """ Basic frame id.""" + + def __init__ (self, sp, pc): + """ Create the frame id.""" + self.sp = sp + self.pc = pc + + def __init__ (self): + """Create the unwinder.""" + Unwinder.__init__ (self, "dummy stack unwinder") + self.void_ptr_t = gdb.lookup_type("void").pointer() + self.regs = None + + def get_regs (self, pending_frame): + """Return a list of register names that should be read. Only + gathers the list once, then caches the result.""" + if (self.regs != None): + return self.regs + + # Collect the names of all registers to read. + self.regs = list (pending_frame.architecture () + .register_names ()) + + return self.regs + + def __call__ (self, pending_frame): + """Actually performs the unwind, or at least sniffs this frame + to see if the unwinder should claim it, which is never does.""" + try: + for r in (self.get_regs (pending_frame)): + v = pending_frame.read_register (r).cast (self.void_ptr_t) + except: + print ("Dummy unwinder, exception") + raise + + return None + +# Register the ComRV stack unwinder. +gdb.unwinder.register_unwinder (None, dummy_unwinder (), True) + +print ("Python script imported") |