aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/dwarf2/frame-tailcall.c37
-rw-r--r--gdb/findvar.c8
-rw-r--r--gdb/frame.c8
-rw-r--r--gdb/frame.h4
-rw-r--r--gdb/testsuite/ChangeLog9
-rw-r--r--gdb/testsuite/gdb.python/py-unwind-inline.c37
-rw-r--r--gdb/testsuite/gdb.python/py-unwind-inline.exp49
-rw-r--r--gdb/testsuite/gdb.python/py-unwind-inline.py71
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")