public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3] gdb/DAP Fix disassemble bug
@ 2023-06-27 16:38 Simon Farre
  2023-07-11 20:06 ` Tom Tromey
  0 siblings, 1 reply; 3+ messages in thread
From: Simon Farre @ 2023-06-27 16:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Farre

v3.

This adds the ability to "disassemble backwards" by retrieving "known
sources of truth" by using the gdb.Block data type, Block.start is always a
valid position in executable code, no? If not, then gdb.Block and all
code that relates to gdb.Block and it's underlying type, must also be
invalid, so I assume here that Block.start is always "good", as it were.

It would probably be nice to have a test for this if we don't already,
but from my dog fooding experience with Midas+VSCode+GDB-DAP, it *seems* to be
correct. But looks can be deceiving, I guess.

v1.
Fixes disassembleRequest

The field instructionOffset can be negative. Previous patch made it so
that sometimes the request got calculated to 0 instructions, when it
meant to retrieve disasm for -50 to 0 (current position).
---
 gdb/python/lib/gdb/dap/disassemble.py | 44 +++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/gdb/python/lib/gdb/dap/disassemble.py b/gdb/python/lib/gdb/dap/disassemble.py
index bc091eb2c89..ce016067b98 100644
--- a/gdb/python/lib/gdb/dap/disassemble.py
+++ b/gdb/python/lib/gdb/dap/disassemble.py
@@ -18,6 +18,39 @@ import gdb
 from .server import request, capability
 from .startup import send_gdb_with_response, in_gdb_thread
 
+# Disassemble "backwards"
+def disasm_backwards(arch: gdb.Architecture, end_pc: int, offset: int, count: int):
+    ins_at_pc = arch.disassemble(start_pc=end_pc)[0]
+    offset = abs(offset)
+    # We take an arbitrary jump backwards
+    # Guessing that an instruction averages at 8 bytes
+    start = end_pc - 8 * offset
+    instructions = []
+    while len(instructions) < (offset + 1):
+        block = gdb.current_progspace().block_for_pc(start)
+        # Fail fast; if we can't find a block backwards
+        # fill all with "invalid values"
+        if block is None:
+            tmp = []
+            for i in range(0, offset - len(instructions)):
+                tmp.append({"addr": 0, "asm": "unknown"})
+            instructions = tmp + instructions
+        else:
+            ins = arch.disassemble(start_pc=block.start, end_pc=end_pc)
+            instructions = ins + instructions
+        start = start - 8 * (offset - len(instructions))
+        end_pc = block.start
+
+    # Disassembled instructions count is >= OFFSET+1
+    diff = len(instructions) - offset
+    result = instructions[diff : diff + count]
+    # DAP seem to not want the actual instruction *at* end_pc
+    # when disassembling backwards
+    if result[-1]["addr"] == ins_at_pc["addr"]:
+        result.pop()
+        result = [instructions[diff - 1]] + result
+    return result[:count]
+
 
 @in_gdb_thread
 def _disassemble(pc, skip_insns, count):
@@ -27,8 +60,15 @@ def _disassemble(pc, skip_insns, count):
         # Maybe there was no frame.
         arch = gdb.selected_inferior().architecture()
     result = []
-    total_count = skip_insns + count
-    for elt in arch.disassemble(pc, count=total_count)[skip_insns:]:
+    if skip_insns < 0:
+        ins = disasm_backwards(arch, pc, skip_insns, count)
+        skip_insns = 0
+        count = count - len(ins)
+        result = [
+            {"address": hex(elt["addr"]), "instruction": elt["asm"]} for elt in ins
+        ]
+
+    for elt in arch.disassemble(pc, count=count + skip_insns)[skip_insns:]:
         result.append(
             {
                 "address": hex(elt["addr"]),
-- 
2.41.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-07-12  9:17 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-27 16:38 [PATCH v3] gdb/DAP Fix disassemble bug Simon Farre
2023-07-11 20:06 ` Tom Tromey
2023-07-12  9:17   ` Simon Farre

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).