public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@adacore.com>
To: Tom de Vries <tdevries@suse.de>
Cc: Tom Tromey <tromey@adacore.com>,
	 Tom Tromey via Gdb-patches <gdb-patches@sourceware.org>
Subject: Re: [PATCH] Fix DAP stackTrace through frames without debuginfo
Date: Thu, 09 Mar 2023 11:45:06 -0700	[thread overview]
Message-ID: <87356dojbh.fsf@tromey.com> (raw)
In-Reply-To: <1c5fbdb3-4307-eba8-9976-673a11655bee@suse.de> (Tom de Vries's message of "Thu, 9 Mar 2023 17:10:02 +0100")

Tom> Sure.  Still a FAIL, but a different error.  Log attached.

Ok, I finally figured it out (I think) and it's a latent bug in
frames.py.  I have no idea how/why this ever worked.

Tom

commit 7190893e3563f7353a6ebbf130e7aa6a145c18a1
Author: Tom Tromey <tromey@adacore.com>
Date:   Thu Mar 9 07:47:29 2023 -0700

    Implement hash function for gdb.Frame
    
    Tom de Vries pointed out that one DAP test failed on Python 3.6
    because gdb.Frame is not hashable.  This error was mildly confusing,
    because I think the real issue was this:
    
    -    pair = (gdb.selected_thread().global_num, frame.level)
    
    Here, 'frame.level' is a bound method, not just a simple value.
    
    This patch adds a hash function to gdb.Frame, then fixes frames.py to
    use it directly.

diff --git a/gdb/frame-id.h b/gdb/frame-id.h
index 8ddf7d11408..53abbe203bf 100644
--- a/gdb/frame-id.h
+++ b/gdb/frame-id.h
@@ -112,6 +112,9 @@ struct frame_id
   /* Return a string representation of this frame id.  */
   std::string to_string () const;
 
+  /* A hash function for this frame_id.  */
+  hashval_t hash () const;
+
   /* Returns true when this frame_id and R identify the same
      frame.  */
   bool operator== (const frame_id &r) const;
diff --git a/gdb/frame.c b/gdb/frame.c
index 9b867b6cd9c..478bd881b63 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -228,26 +228,12 @@ frame_addr_hash (const void *ap)
 {
   const frame_info *frame = (const frame_info *) ap;
   const struct frame_id f_id = frame->this_id.value;
-  hashval_t hash = 0;
 
   gdb_assert (f_id.stack_status != FID_STACK_INVALID
 	      || f_id.code_addr_p
 	      || f_id.special_addr_p);
 
-  if (f_id.stack_status == FID_STACK_VALID)
-    hash = iterative_hash (&f_id.stack_addr,
-			   sizeof (f_id.stack_addr), hash);
-  if (f_id.code_addr_p)
-    hash = iterative_hash (&f_id.code_addr,
-			   sizeof (f_id.code_addr), hash);
-  if (f_id.special_addr_p)
-    hash = iterative_hash (&f_id.special_addr,
-			   sizeof (f_id.special_addr), hash);
-
-  char user_created_p = f_id.user_created_p;
-  hash = iterative_hash (&user_created_p, sizeof (user_created_p), hash);
-
-  return hash;
+  return f_id.hash ();
 }
 
 /* Internal equality function for the hash table.  This function
@@ -796,6 +782,29 @@ frame_id_artificial_p (frame_id l)
   return l.artificial_depth != 0;
 }
 
+/* See frame-id.h.  */
+
+hashval_t
+frame_id::hash () const
+{
+  hashval_t hash = 0;
+
+  if (stack_status == FID_STACK_VALID)
+    hash = iterative_hash (&stack_addr,
+			   sizeof (stack_addr), hash);
+  if (code_addr_p)
+    hash = iterative_hash (&code_addr,
+			   sizeof (code_addr), hash);
+  if (special_addr_p)
+    hash = iterative_hash (&special_addr,
+			   sizeof (special_addr), hash);
+
+  char user_created_p = user_created_p;
+  hash = iterative_hash (&user_created_p, sizeof (user_created_p), hash);
+
+  return hash;
+}
+
 bool
 frame_id::operator== (const frame_id &r) const
 {
diff --git a/gdb/python/lib/gdb/dap/frames.py b/gdb/python/lib/gdb/dap/frames.py
index 337bbedae0f..4b554f3d920 100644
--- a/gdb/python/lib/gdb/dap/frames.py
+++ b/gdb/python/lib/gdb/dap/frames.py
@@ -18,8 +18,8 @@ import gdb
 from .startup import in_gdb_thread
 
 
-# Map from frame (thread,level) pair to frame ID numbers.  Note we
-# can't use the frame itself here as it is not hashable.
+# Map from frame pair to the frame ID number that is passed back to
+# the client.
 _frame_ids = {}
 
 # Map from frame ID number back to frames.
@@ -42,12 +42,11 @@ gdb.events.cont.connect(_clear_frame_ids)
 def frame_id(frame):
     """Return the frame identifier for FRAME."""
     global _frame_ids, _id_to_frame
-    pair = (gdb.selected_thread().global_num, frame.level)
-    if pair not in _frame_ids:
+    if frame not in _frame_ids:
         id = len(_frame_ids)
-        _frame_ids[pair] = id
+        _frame_ids[frame] = id
         _id_to_frame[id] = frame
-    return _frame_ids[pair]
+    return _frame_ids[frame]
 
 
 @in_gdb_thread
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index ecd55d2e568..099f39ac44e 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -687,6 +687,23 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
+/* Implement the hash method.  */
+
+static Py_hash_t
+frapy_hash (PyObject *self)
+{
+  frame_object *self_frame = (frame_object *) self;
+
+  hashval_t hash = self_frame->frame_id.hash ();
+  hash <<= 1;
+  hash |= self_frame->frame_id_is_next;
+
+  Py_hash_t result = (Py_hash_t) hash;
+  if (result == -1)
+    result = 0;
+  return result;
+}
+
 /* Implements the equality comparison for Frame objects.
    All other comparison operators will throw a TypeError Python exception,
    as they aren't valid for frames.  */
@@ -816,7 +833,7 @@ PyTypeObject frame_object_type = {
   0,				  /* tp_as_number */
   0,				  /* tp_as_sequence */
   0,				  /* tp_as_mapping */
-  0,				  /* tp_hash  */
+  frapy_hash,			  /* tp_hash  */
   0,				  /* tp_call */
   frapy_str,			  /* tp_str */
   0,				  /* tp_getattro */

  reply	other threads:[~2023-03-09 18:45 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-15 19:48 Tom Tromey
2023-03-06 15:17 ` Tom Tromey
2023-03-09  8:38   ` Tom de Vries
2023-03-09 14:24     ` Tom Tromey
2023-03-09 14:52     ` Tom Tromey
2023-03-09 16:10       ` Tom de Vries
2023-03-09 18:45         ` Tom Tromey [this message]
2023-03-09 20:35           ` Tom de Vries
2023-03-13 18:46             ` Tom Tromey
2023-03-14 13:08             ` Tom Tromey
2023-03-14 13:28               ` Tom de Vries
2023-03-14 14:03                 ` Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87356dojbh.fsf@tromey.com \
    --to=tromey@adacore.com \
    --cc=gdb-patches@sourceware.org \
    --cc=tdevries@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).