From a2f972b330b1575f49ea7a02103085378e7937c7 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 24 Apr 2024 10:03:08 -0600 Subject: Add symbol, line, and location to DAP disassemble result The DAP spec allows a number of attributes on the resulting instructions that gdb currently does not emit. A user requested some of these, so this patch adds the 'symbol', 'line', and 'location' attributes. While the spec lets the implementation omit 'location' in some cases, it was simpler in the code to just always emit it, as then no extra tracking was needed. --- gdb/python/lib/gdb/dap/disassemble.py | 59 ++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) (limited to 'gdb/python') diff --git a/gdb/python/lib/gdb/dap/disassemble.py b/gdb/python/lib/gdb/dap/disassemble.py index 65bf3d4..d65790a 100644 --- a/gdb/python/lib/gdb/dap/disassemble.py +++ b/gdb/python/lib/gdb/dap/disassemble.py @@ -16,6 +16,50 @@ import gdb from .server import capability, request +from .sources import make_source + + +# This tracks labels associated with a disassembly request and helps +# with updating individual instructions. +class _BlockTracker: + def __init__(self): + # Map from PC to symbol names. A given PC is assumed to have + # just one label -- DAP wouldn't let us return multiple labels + # anyway. + self.labels = {} + # List of blocks that have already been handled. Note that + # blocks aren't hashable so a set is not used. + self.blocks = [] + + # Add a gdb.Block and its superblocks, ignoring the static and + # global block. BLOCK can also be None, which is ignored. + def add_block(self, block): + while block is not None: + if block.is_static or block.is_global or block in self.blocks: + return + self.blocks.append(block) + if block.function is not None: + self.labels[block.start] = block.function.name + for sym in block: + if sym.addr_class == gdb.SYMBOL_LOC_LABEL: + self.labels[int(sym.value())] = sym.name + block = block.superblock + + # Add PC to this tracker. Update RESULT as appropriate with + # information about the source and any label. + def add_pc(self, pc, result): + self.add_block(gdb.block_for_pc(pc)) + if pc in self.labels: + result["symbol"] = self.labels[pc] + sal = gdb.find_pc_line(pc) + if sal.symtab is not None: + if sal.line != 0: + result["line"] = sal.line + if sal.symtab.filename is not None: + # The spec says this can be omitted in some + # situations, but it's a little simpler to just always + # supply it. + result["location"] = make_source(sal.symtab.filename) @request("disassemble") @@ -35,17 +79,18 @@ def disassemble( except gdb.error: # Maybe there was no frame. arch = inf.architecture() + tracker = _BlockTracker() result = [] total_count = instructionOffset + instructionCount for elt in arch.disassemble(pc, count=total_count)[instructionOffset:]: mem = inf.read_memory(elt["addr"], elt["length"]) - result.append( - { - "address": hex(elt["addr"]), - "instruction": elt["asm"], - "instructionBytes": mem.hex(), - } - ) + insn = { + "address": hex(elt["addr"]), + "instruction": elt["asm"], + "instructionBytes": mem.hex(), + } + tracker.add_pc(elt["addr"], insn) + result.append(insn) return { "instructions": result, } -- cgit v1.1