gdb: refactor the non-printing disassemblers

This commit started from an observation I made while working on some
other disassembler patches, that is, that the function
gdb_buffered_insn_length, is broken ... sort of.

I noticed that the gdb_buffered_insn_length function doesn't set up
the application data field if the disassemble_info structure.

Further, I noticed that some architectures, for example, ARM, require
that the application_data field be set, see gdb_print_insn_arm in
arm-tdep.c.

And so, if we ever use gdb_buffered_insn_length for ARM, then GDB will
likely crash.  Which is why I said only "sort of" broken.  Right now
we don't use gdb_buffered_insn_length with ARM, so maybe it isn't
broken yet?

Anyway to prove to myself that there was a problem here I extended the
disassembler self tests in disasm-selftests.c to include a test of
gdb_buffered_insn_length.  As I run the test for all architectures, I
do indeed see GDB crash for ARM.

To fix this we need gdb_buffered_insn_length to create a disassembler
that inherits from gdb_disassemble_info, but we also need this new
disassembler to not print anything.

And so, I introduce a new gdb_non_printing_disassembler class, this is
a disassembler that doesn't print anything to the output stream.

I then observed that both ARC and S12Z also create non-printing
disassemblers, but these are slightly different.  While the
disassembler in gdb_non_printing_disassembler reads the instruction
from a buffer, the ARC and S12Z disassemblers read from target memory
using target_read_code.

And so, I further split gdb_non_printing_disassembler into two
sub-classes, gdb_non_printing_memory_disassembler and
gdb_non_printing_buffer_disassembler.

The new selftests now pass, but otherwise, there should be no user
visible changes after this commit.
This commit is contained in:
Andrew Burgess
2022-04-04 15:48:19 +01:00
parent 15e15b2d9c
commit 8b39b1e7ab
7 changed files with 174 additions and 139 deletions

View File

@@ -136,6 +136,56 @@ protected:
ATTRIBUTE_PRINTF(3,4);
};
/* A basic disassembler that doesn't actually print anything. */
struct gdb_non_printing_disassembler : public gdb_disassemble_info
{
gdb_non_printing_disassembler (struct gdbarch *gdbarch,
read_memory_ftype read_memory_func)
: gdb_disassemble_info (gdbarch, nullptr /* stream */,
read_memory_func,
nullptr /* memory_error_func */,
nullptr /* print_address_func */,
null_fprintf_func,
null_fprintf_styled_func)
{ /* Nothing. */ }
private:
/* Callback used as the disassemble_info's fprintf_func callback, this
doesn't write anything to STREAM, but just returns 0. */
static int null_fprintf_func (void *stream, const char *format, ...)
ATTRIBUTE_PRINTF(2,3);
/* Callback used as the disassemble_info's fprintf_styled_func callback,
, this doesn't write anything to STREAM, but just returns 0. */
static int null_fprintf_styled_func (void *stream,
enum disassembler_style style,
const char *format, ...)
ATTRIBUTE_PRINTF(3,4);
};
/* A non-printing disassemble_info management class. The disassemble_info
setup by this class will not print anything to the output stream (there
is no output stream), and the instruction to be disassembled will be
read from target memory. */
struct gdb_non_printing_memory_disassembler
: public gdb_non_printing_disassembler
{
/* Constructor. GDBARCH is the architecture to disassemble for. */
gdb_non_printing_memory_disassembler (struct gdbarch *gdbarch)
:gdb_non_printing_disassembler (gdbarch, dis_asm_read_memory)
{ /* Nothing. */ }
private:
/* Implements the read_memory_func disassemble_info callback. */
static int dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
unsigned int len,
struct disassemble_info *info);
};
/* A dissassembler class that provides 'print_insn', a method for
disassembling a single instruction to the output stream. */
@@ -278,10 +328,4 @@ extern char *get_disassembler_options (struct gdbarch *gdbarch);
extern void set_disassembler_options (const char *options);
/* Setup DINFO with its output function and output stream setup so that
nothing is printed while disassembling. */
extern void init_disassemble_info_for_no_printing
(struct disassemble_info *dinfo);
#endif