diff --git a/gdb/NEWS b/gdb/NEWS
index ed0f86e79ec..0d9049ff134 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -110,6 +110,26 @@ show always-read-ctf
      without the particular unwinder, depending on how 'enabled' was
      changed.
 
+  ** New methods added to the gdb.PendingFrame class.  These methods
+     have the same behaviour as the corresponding methods on
+     gdb.Frame.  The new methods are:
+
+     - gdb.PendingFrame.name(): Return the name for the frame's
+       function, or None.
+     - gdb.PendingFrame.is_valid(): Return True if the pending frame
+       object is valid.
+     - gdb.PendingFrame.pc(): Return the $pc register value for this
+       frame.
+     - gdb.PendingFrame.language(): Return a string containing the
+       language for this frame, or None.
+     - gdb.PendingFrame.find_sal(): Return a gdb.Symtab_and_line
+       object for the current location within the pending frame, or
+       None.
+     - gdb.PendingFrame.block(): Return a gdb.Block for the current
+       pending frame, or None.
+     - gdb.PendingFrame.function(): Return a gdb.Symbol for the
+       current pending frame, or None.
+
 *** Changes in GDB 13
 
 * MI version 1 is deprecated, and will be removed in GDB 14.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index c36130210ba..1c4239841af 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -2830,6 +2830,46 @@
 @xref{Frames, ,Stack Frames}.
 @end defun
 
+@defun PendingFrame.name ()
+Returns the function name of this pending frame, or @code{None} if it
+can't be obtained.
+@end defun
+
+@defun PendingFrame.is_valid ()
+Returns true if the @code{gdb.PendingFrame} object is valid, false if
+not.  A pending frame object becomes invalid when the call to the
+unwinder, for which the pending frame was created, returns.
+
+All @code{gdb.PendingFrame} methods, except this one, will raise an
+exception if the pending frame object is invalid at the time the
+method is called.
+@end defun
+
+@defun PendingFrame.pc ()
+Returns the pending frame's resume address.
+@end defun
+
+@defun PendingFrame.block ()
+Return the pending frame's code block (@pxref{Blocks In Python}).  If
+the frame does not have a block -- for example, if there is no
+debugging information for the code in question -- then this will raise
+a @code{RuntimeError} exception.
+@end defun
+
+@defun PendingFrame.function ()
+Return the symbol for the function corresponding to this pending frame.
+@xref{Symbols In Python}.
+@end defun
+
+@defun PendingFrame.find_sal ()
+Return the pending frame's symtab and line object (@pxref{Symbol
+Tables In Python}).
+@end defun
+
+@defun PendingFrame.language ()
+Return a string, the source language for this pending frame.
+@end defun
+
 @subheading Unwinder Output: UnwindInfo
 
 Use @code{PendingFrame.create_unwind_info} method described above to
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 12b14616363..5ed3ff37e64 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -28,6 +28,10 @@
 #include "regcache.h"
 #include "valprint.h"
 #include "user-regs.h"
+#include "stack.h"
+#include "charset.h"
+#include "block.h"
+
 
 /* Debugging of Python unwinders.  */
 
@@ -412,6 +416,200 @@ pending_framepy_read_register (PyObject *self, PyObject *args)
   return result;
 }
 
+/* Implement PendingFrame.is_valid().  Return True if this pending frame
+   object is still valid.  */
+
+static PyObject *
+pending_framepy_is_valid (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  if (pending_frame->frame_info == nullptr)
+    Py_RETURN_FALSE;
+
+  Py_RETURN_TRUE;
+}
+
+/* Implement PendingFrame.name().  Return a string that is the name of the
+   function for this frame, or None if the name can't be found.  */
+
+static PyObject *
+pending_framepy_name (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  gdb::unique_xmalloc_ptr<char> name;
+
+  try
+    {
+      enum language lang;
+      frame_info_ptr frame = pending_frame->frame_info;
+
+      name = find_frame_funname (frame, &lang, nullptr);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  if (name != nullptr)
+    return PyUnicode_Decode (name.get (), strlen (name.get ()),
+			     host_charset (), nullptr);
+
+  Py_RETURN_NONE;
+}
+
+/* Implement gdb.PendingFrame.pc().  Returns an integer containing the
+   frame's current $pc value.  */
+
+static PyObject *
+pending_framepy_pc (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  CORE_ADDR pc = 0;
+
+  try
+    {
+      pc = get_frame_pc (pending_frame->frame_info);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  return gdb_py_object_from_ulongest (pc).release ();
+}
+
+/* Implement gdb.PendingFrame.language().  Return the name of the language
+   for this frame.  */
+
+static PyObject *
+pending_framepy_language (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  try
+    {
+      frame_info_ptr fi = pending_frame->frame_info;
+
+      enum language lang = get_frame_language (fi);
+      const language_defn *lang_def = language_def (lang);
+
+      return host_string_to_python_string (lang_def->name ()).release ();
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  Py_RETURN_NONE;
+}
+
+/* Implement PendingFrame.find_sal().  Return the PendingFrame's symtab and
+   line.  */
+
+static PyObject *
+pending_framepy_find_sal (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  PyObject *sal_obj = nullptr;
+
+  try
+    {
+      frame_info_ptr frame = pending_frame->frame_info;
+
+      symtab_and_line sal = find_frame_sal (frame);
+      sal_obj = symtab_and_line_to_sal_object (sal);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  return sal_obj;
+}
+
+/* Implement PendingFrame.block().  Return a gdb.Block for the pending
+   frame's code, or raise  RuntimeError if the block can't be found.  */
+
+static PyObject *
+pending_framepy_block (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  frame_info_ptr frame = pending_frame->frame_info;
+  const struct block *block = nullptr, *fn_block;
+
+  try
+    {
+      block = get_frame_block (frame, nullptr);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  for (fn_block = block;
+       fn_block != nullptr && fn_block->function () == nullptr;
+       fn_block = fn_block->superblock ())
+    ;
+
+  if (block == nullptr
+      || fn_block == nullptr
+      || fn_block->function () == nullptr)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("Cannot locate block for frame."));
+      return nullptr;
+    }
+
+  return block_to_block_object (block, fn_block->function ()->objfile ());
+}
+
+/* Implement gdb.PendingFrame.function().  Return a gdb.Symbol
+   representing the function of this frame, or None if no suitable symbol
+   can be found.  */
+
+static PyObject *
+pending_framepy_function (PyObject *self, PyObject *args)
+{
+  pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+  PENDING_FRAMEPY_REQUIRE_VALID (pending_frame);
+
+  struct symbol *sym = nullptr;
+
+  try
+    {
+      enum language funlang;
+      frame_info_ptr frame = pending_frame->frame_info;
+
+      gdb::unique_xmalloc_ptr<char> funname
+	= find_frame_funname (frame, &funlang, &sym);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  if (sym != nullptr)
+    return symbol_to_symbol_object (sym);
+
+  Py_RETURN_NONE;
+}
+
 /* Implementation of
    PendingFrame.create_unwind_info (self, frameId) -> UnwindInfo.  */
 
@@ -737,6 +935,29 @@ static PyMethodDef pending_frame_object_methods[] =
     pending_framepy_architecture, METH_NOARGS,
     "architecture () -> gdb.Architecture\n"
     "The architecture for this PendingFrame." },
+  { "name",
+    pending_framepy_name, METH_NOARGS,
+    "name() -> String.\n\
+Return the function name of the frame, or None if it can't be determined." },
+  { "is_valid",
+    pending_framepy_is_valid, METH_NOARGS,
+    "is_valid () -> Boolean.\n\
+Return true if this PendingFrame is valid, false if not." },
+  { "pc",
+    pending_framepy_pc, METH_NOARGS,
+    "pc () -> Long.\n\
+Return the frame's resume address." },
+  { "language", pending_framepy_language, METH_NOARGS,
+    "The language of this frame." },
+  { "find_sal", pending_framepy_find_sal, METH_NOARGS,
+    "find_sal () -> gdb.Symtab_and_line.\n\
+Return the frame's symtab and line." },
+  { "block", pending_framepy_block, METH_NOARGS,
+    "block () -> gdb.Block.\n\
+Return the frame's code block." },
+  { "function", pending_framepy_function, METH_NOARGS,
+    "function () -> gdb.Symbol.\n\
+Returns the symbol for the function corresponding to this frame." },
   { "level", pending_framepy_level, METH_NOARGS,
     "The stack level of this frame." },
   {NULL}  /* Sentinel */
diff --git a/gdb/testsuite/gdb.python/py-unwind.exp b/gdb/testsuite/gdb.python/py-unwind.exp
index 3e214ee0f45..f670da5a7cd 100644
--- a/gdb/testsuite/gdb.python/py-unwind.exp
+++ b/gdb/testsuite/gdb.python/py-unwind.exp
@@ -149,15 +149,46 @@ gdb_test_no_output "python obj = simple_unwinder(\"simple\")"
 gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj)"
 check_for_broken_backtrace "backtrace to capture a PendingFrame object"
 
+# Check the captured PendingFrame is not valid.
+gdb_test "python print(captured_pending_frame.is_valid())" "False"
+
 # Call methods on the captured gdb.PendingFrame and check we see the
 # expected error.
 gdb_test_no_output "python pf = captured_pending_frame"
 foreach cmd {"pf.read_register(\"pc\")" \
 		 "pf.create_unwind_info(None)" \
 		 "pf.architecture()" \
-		 "pf.level()"} {
+		 "pf.level()" \
+		 "pf.name()" \
+		 "pf.pc()" \
+		 "pf.language()" \
+		 "pf.find_sal()" \
+		 "pf.block()" \
+		 "pf.function()" } {
     gdb_test "python $cmd" \
 	[multi_line \
 	     "ValueError: gdb\\.PendingFrame is invalid\\." \
 	     "Error while executing Python code\\."]
 }
+
+# Turn on the useful unwinder so we have the full backtrace again, and
+# disable the simple unwinder -- because we can!
+gdb_test "enable unwinder global \"test unwinder\"" \
+    "1 unwinder enabled" \
+    "re-enable 'test unwinder' so we can check PendingFrame methods"
+gdb_test "disable unwinder global \"simple\"" \
+    "1 unwinder disabled"
+check_for_fixed_backtrace \
+    "check backtrace before testing PendingFrame methods"
+
+# Gather information about every frame.
+gdb_test_no_output "python capture_all_frame_information()"
+gdb_test_no_output "python gdb.newest_frame().select()"
+gdb_test_no_output "python pspace = gdb.selected_inferior().progspace"
+gdb_test_no_output "python obj = validating_unwinder()"
+gdb_test_no_output "python gdb.unwinder.register_unwinder(pspace, obj)"
+
+check_for_fixed_backtrace \
+    "check backtrace to validate all information"
+
+gdb_test_no_output "python check_all_frame_information_matched()"
diff --git a/gdb/testsuite/gdb.python/py-unwind.py b/gdb/testsuite/gdb.python/py-unwind.py
index b30e843e7e5..8e3c1f398bc 100644
--- a/gdb/testsuite/gdb.python/py-unwind.py
+++ b/gdb/testsuite/gdb.python/py-unwind.py
@@ -144,9 +144,113 @@ class simple_unwinder(Unwinder):
     def __call__(self, pending_frame):
         global captured_pending_frame
 
+        assert pending_frame.is_valid()
+
         if captured_pending_frame is None:
             captured_pending_frame = pending_frame
         return None
 
 
+# Return a dictionary of information about FRAME.
+def capture_frame_information(frame):
+    name = frame.name()
+    level = frame.level()
+    language = frame.language()
+    function = frame.function()
+    architecture = frame.architecture()
+    pc = frame.pc()
+    sal = frame.find_sal()
+    try:
+        block = frame.block()
+        assert isinstance(block, gdb.Block)
+    except RuntimeError as rte:
+        assert str(rte) == "Cannot locate block for frame."
+        block = "RuntimeError: " + str(rte)
+
+    return {
+        "name": name,
+        "level": level,
+        "language": language,
+        "function": function,
+        "architecture": architecture,
+        "pc": pc,
+        "sal": sal,
+        "block": block,
+    }
+
+
+# List of information about each frame.  The index into this list is
+# the frame level.  This is populated by
+# capture_all_frame_information.
+all_frame_information = []
+
+# Fill in the global ALL_FRAME_INFORMATION list.
+def capture_all_frame_information():
+    global all_frame_information
+
+    all_frame_information = []
+
+    gdb.newest_frame().select()
+    frame = gdb.selected_frame()
+    count = 0
+
+    while frame is not None:
+        frame.select()
+        info = capture_frame_information(frame)
+        level = info["level"]
+        info["matched"] = False
+
+        while len(all_frame_information) <= level:
+            all_frame_information.append(None)
+
+        assert all_frame_information[level] is None
+        all_frame_information[level] = info
+
+        if frame.name == "main" or count > 10:
+            break
+
+        count += 1
+        frame = frame.older()
+
+
+# Assert that every entry in the global ALL_FRAME_INFORMATION list was
+# matched by the validating_unwinder.
+def check_all_frame_information_matched():
+    global all_frame_information
+    for entry in all_frame_information:
+        assert entry["matched"]
+
+
+# An unwinder that doesn't match any frames.  What it does do is
+# lookup information from the PendingFrame object and compare it
+# against information stored in the global ALL_FRAME_INFORMATION list.
+class validating_unwinder(Unwinder):
+    def __init__(self):
+        super().__init__("validating_unwinder")
+
+    def __call__(self, pending_frame):
+        info = capture_frame_information(pending_frame)
+        level = info["level"]
+
+        global all_frame_information
+        old_info = all_frame_information[level]
+
+        assert old_info is not None
+        assert not old_info["matched"]
+
+        for key, value in info.items():
+            assert key in old_info, f"{key} not in old_info"
+            assert type(value) == type(old_info[key])
+            if isinstance(value, gdb.Block):
+                assert value.start == old_info[key].start
+                assert value.end == old_info[key].end
+                assert value.is_static == old_info[key].is_static
+                assert value.is_global == old_info[key].is_global
+            else:
+                assert str(value) == str(old_info[key])
+
+        old_info["matched"] = True
+        return None
+
+
 print("Python script imported")
