|  | /* Disassemble support for GDB. | 
|  | Copyright (C) 2002-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #ifndef DISASM_H | 
|  | #define DISASM_H | 
|  |  | 
|  | #include "dis-asm.h" | 
|  | #include "disasm-flags.h" | 
|  |  | 
|  | struct gdbarch; | 
|  | struct ui_out; | 
|  | struct ui_file; | 
|  |  | 
|  | /* A wrapper around a disassemble_info and a gdbarch.  This is the core | 
|  | set of data that all disassembler sub-classes will need.  This class | 
|  | doesn't actually implement the disassembling process, that is something | 
|  | that sub-classes will do, with each sub-class doing things slightly | 
|  | differently. | 
|  |  | 
|  | The constructor of this class is protected, you should not create | 
|  | instances of this class directly, instead create an instance of an | 
|  | appropriate sub-class.  */ | 
|  |  | 
|  | struct gdb_disassemble_info | 
|  | { | 
|  | DISABLE_COPY_AND_ASSIGN (gdb_disassemble_info); | 
|  |  | 
|  | /* Return the gdbarch we are disassembling for.  */ | 
|  | struct gdbarch *arch () | 
|  | { return m_gdbarch; } | 
|  |  | 
|  | /* Return a pointer to the disassemble_info, this will be needed for | 
|  | passing into the libopcodes disassembler.  */ | 
|  | struct disassemble_info *disasm_info () | 
|  | { return &m_di; } | 
|  |  | 
|  | protected: | 
|  |  | 
|  | /* Types for the function callbacks within m_di.  The actual function | 
|  | signatures here are taken from include/dis-asm.h.  */ | 
|  | using read_memory_ftype | 
|  | = int (*) (bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *) | 
|  | noexcept; | 
|  | using memory_error_ftype | 
|  | = void (*) (int, bfd_vma, struct disassemble_info *) noexcept; | 
|  | using print_address_ftype | 
|  | = void (*) (bfd_vma, struct disassemble_info *) noexcept; | 
|  | using fprintf_ftype | 
|  | = int (*) (void *, const char *, ...) noexcept; | 
|  | using fprintf_styled_ftype | 
|  | = int (*) (void *, enum disassembler_style, const char *, ...) noexcept; | 
|  |  | 
|  | /* Constructor, many fields in m_di are initialized from GDBARCH.  The | 
|  | remaining arguments are function callbacks that are written into m_di. | 
|  | Of these function callbacks FPRINTF_FUNC and FPRINTF_STYLED_FUNC must | 
|  | not be nullptr.  If READ_MEMORY_FUNC, MEMORY_ERROR_FUNC, or | 
|  | PRINT_ADDRESS_FUNC are nullptr, then that field within m_di is left | 
|  | with its default value (see the libopcodes function | 
|  | init_disassemble_info for the defaults).  */ | 
|  | gdb_disassemble_info (struct gdbarch *gdbarch, | 
|  | read_memory_ftype read_memory_func, | 
|  | memory_error_ftype memory_error_func, | 
|  | print_address_ftype print_address_func, | 
|  | fprintf_ftype fprintf_func, | 
|  | fprintf_styled_ftype fprintf_styled_func); | 
|  |  | 
|  | /* Destructor.  */ | 
|  | virtual ~gdb_disassemble_info (); | 
|  |  | 
|  | /* Stores data required for disassembling instructions in | 
|  | opcodes.  */ | 
|  | struct disassemble_info m_di; | 
|  |  | 
|  | private: | 
|  | /* The architecture we are disassembling for.  */ | 
|  | struct gdbarch *m_gdbarch; | 
|  |  | 
|  | /* If we own the string in `m_di.disassembler_options', we do so | 
|  | using this field.  */ | 
|  | std::string m_disassembler_options_holder; | 
|  | }; | 
|  |  | 
|  | /* A wrapper around gdb_disassemble_info.  This class adds default | 
|  | print functions that are supplied to the disassemble_info within the | 
|  | parent class.  These default print functions write to the stream, which | 
|  | is also contained in the parent class. | 
|  |  | 
|  | As with the parent class, the constructor for this class is protected, | 
|  | you should not create instances of this class, but create an | 
|  | appropriate sub-class instead.  */ | 
|  |  | 
|  | struct gdb_printing_disassembler : public gdb_disassemble_info | 
|  | { | 
|  | DISABLE_COPY_AND_ASSIGN (gdb_printing_disassembler); | 
|  |  | 
|  | /* The stream that disassembler output is being written too.  */ | 
|  | struct ui_file *stream () | 
|  | { return m_stream; } | 
|  |  | 
|  | protected: | 
|  |  | 
|  | /* Constructor.  All the arguments are just passed to the parent class. | 
|  | We also add the two print functions to the arguments passed to the | 
|  | parent.  See gdb_disassemble_info for a description of how the | 
|  | arguments are handled.  */ | 
|  | gdb_printing_disassembler (struct gdbarch *gdbarch, | 
|  | struct ui_file *stream, | 
|  | read_memory_ftype read_memory_func, | 
|  | memory_error_ftype memory_error_func, | 
|  | print_address_ftype print_address_func) | 
|  | : gdb_disassemble_info (gdbarch, read_memory_func, | 
|  | memory_error_func, print_address_func, | 
|  | fprintf_func, fprintf_styled_func), | 
|  | m_stream (stream) | 
|  | { | 
|  | gdb_assert (stream != nullptr); | 
|  | } | 
|  |  | 
|  | /* Callback used as the disassemble_info's fprintf_func callback.  The | 
|  | DIS_INFO pointer is a pointer to a gdb_printing_disassembler object. | 
|  | Content is written to the m_stream extracted from DIS_INFO.  */ | 
|  | static int fprintf_func (void *dis_info, const char *format, ...) noexcept | 
|  | ATTRIBUTE_PRINTF (2, 3); | 
|  |  | 
|  | /* Callback used as the disassemble_info's fprintf_styled_func callback. | 
|  | The DIS_INFO pointer is a pointer to a gdb_printing_disassembler | 
|  | object.  Content is written to the m_stream extracted from DIS_INFO.  */ | 
|  | static int fprintf_styled_func (void *dis_info, | 
|  | enum disassembler_style style, | 
|  | const char *format, ...) noexcept | 
|  | ATTRIBUTE_PRINTF(3,4); | 
|  |  | 
|  | /* Return true if the disassembler is considered inside a comment, false | 
|  | otherwise.  */ | 
|  | bool in_comment_p () const | 
|  | { return m_in_comment; } | 
|  |  | 
|  | /* Set whether the disassembler should be considered as within comment | 
|  | text or not.  */ | 
|  | void set_in_comment (bool c) | 
|  | { m_in_comment = c; } | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* When libopcodes calls the fprintf_func and fprintf_styled_func | 
|  | callbacks, a 'void *' argument is passed.  We arrange, through our | 
|  | call to init_disassemble_info that this argument will be a pointer to | 
|  | a gdb_disassemble_info sub-class, specifically, a | 
|  | gdb_printing_disassembler pointer.  This helper function casts | 
|  | DIS_INFO to the correct type (with some asserts), and then returns the | 
|  | m_stream member variable.  */ | 
|  | static ui_file *stream_from_gdb_disassemble_info (void *dis_info); | 
|  |  | 
|  | /* The stream to which output should be sent.  */ | 
|  | struct ui_file *m_stream; | 
|  |  | 
|  | /* Are we inside a comment?  This will be set true if the disassembler | 
|  | uses styled output and emits a start of comment character.  It is up | 
|  | to the code that uses this disassembler class to reset this flag back | 
|  | to false at a suitable time (e.g. at the end of every line).  */ | 
|  | bool m_in_comment = false; | 
|  | }; | 
|  |  | 
|  | /* 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, | 
|  | 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, ...) noexcept | 
|  | 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, ...) noexcept | 
|  | ATTRIBUTE_PRINTF(3,4); | 
|  | }; | 
|  |  | 
|  | /* This is a helper class, for use as an additional base-class, by some of | 
|  | the disassembler classes below.  This class just defines a static method | 
|  | for reading from target memory, which can then be used by the various | 
|  | disassembler sub-classes.  */ | 
|  |  | 
|  | struct gdb_disassembler_memory_reader | 
|  | { | 
|  | /* 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) noexcept; | 
|  | }; | 
|  |  | 
|  | /* 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, | 
|  | private gdb_disassembler_memory_reader | 
|  | { | 
|  | /* 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.  */ } | 
|  | }; | 
|  |  | 
|  | /* A disassembler class that provides 'print_insn', a method for | 
|  | disassembling a single instruction to the output stream.  */ | 
|  |  | 
|  | struct gdb_disassembler : public gdb_printing_disassembler, | 
|  | private gdb_disassembler_memory_reader | 
|  | { | 
|  | gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file) | 
|  | : gdb_disassembler (gdbarch, file, dis_asm_read_memory) | 
|  | { /* Nothing.  */ } | 
|  |  | 
|  | DISABLE_COPY_AND_ASSIGN (gdb_disassembler); | 
|  |  | 
|  | /* Disassemble a single instruction at MEMADDR to the ui_file* that was | 
|  | passed to the constructor.  If a memory error occurs while | 
|  | disassembling this instruction then an error will be thrown.  */ | 
|  | int print_insn (CORE_ADDR memaddr, int *branch_delay_insns = NULL); | 
|  |  | 
|  | protected: | 
|  | gdb_disassembler (struct gdbarch *gdbarch, struct ui_file *file, | 
|  | read_memory_ftype func); | 
|  |  | 
|  | private: | 
|  | /* This member variable is given a value by calling dis_asm_memory_error. | 
|  | If after calling into the libopcodes disassembler we get back a | 
|  | negative value (which indicates an error), then, if this variable has | 
|  | a value, we report a memory error to the user, otherwise, we report a | 
|  | non-memory error.  */ | 
|  | std::optional<CORE_ADDR> m_err_memaddr; | 
|  |  | 
|  | /* The stream to which disassembler output will be written.  */ | 
|  | ui_file *m_dest; | 
|  |  | 
|  | /* Disassembler output is built up into this buffer.  Whether this | 
|  | string_file is created with styling support or not depends on the | 
|  | value of use_ext_lang_colorization_p, as well as whether disassembler | 
|  | styling in general is turned on, and also, whether *m_dest supports | 
|  | styling or not.  */ | 
|  | string_file m_buffer; | 
|  |  | 
|  | /* When true, m_buffer will be created without styling support, | 
|  | otherwise, m_buffer will be created with styling support. | 
|  |  | 
|  | This field will initially be true, but will be set to false if | 
|  | ext_lang_colorize_disasm fails to add styling at any time. | 
|  |  | 
|  | If the extension language is going to add the styling then m_buffer | 
|  | should be created without styling support, the extension language will | 
|  | then add styling at the end of the disassembly process. | 
|  |  | 
|  | If the extension language is not going to add the styling, then we | 
|  | create m_buffer with styling support, and GDB will add minimal styling | 
|  | (currently just to addresses and symbols) as it goes.  */ | 
|  | static bool use_ext_lang_colorization_p; | 
|  |  | 
|  | static void dis_asm_memory_error (int err, bfd_vma memaddr, | 
|  | struct disassemble_info *info) noexcept; | 
|  | static void dis_asm_print_address (bfd_vma addr, | 
|  | struct disassemble_info *info) noexcept; | 
|  |  | 
|  | /* Return true if we should use the extension language to apply | 
|  | disassembler styling.  This requires disassembler styling to be on | 
|  | (i.e. 'set style disassembler enabled on'), the output stream needs to | 
|  | support styling, and libopcode styling needs to be either off, or not | 
|  | supported for the current architecture (libopcodes is used in | 
|  | preference to the extension language method).  */ | 
|  | bool use_ext_lang_for_styling () const; | 
|  |  | 
|  | /* Return true if we should use libopcodes to apply disassembler styling. | 
|  | This requires disassembler styling to be on (i.e. 'set style | 
|  | disassembler enabled on'), the output stream needs to support styling, | 
|  | and libopcodes styling needs to be supported for the current | 
|  | architecture, and not disabled by the user.  */ | 
|  | bool use_libopcodes_for_styling () const; | 
|  | }; | 
|  |  | 
|  | /* An instruction to be disassembled.  */ | 
|  |  | 
|  | struct disasm_insn | 
|  | { | 
|  | /* The address of the memory containing the instruction.  */ | 
|  | CORE_ADDR addr; | 
|  |  | 
|  | /* An optional instruction number.  If non-zero, it is printed first.  */ | 
|  | unsigned int number; | 
|  |  | 
|  | /* True if the instruction was executed speculatively.  */ | 
|  | unsigned int is_speculative:1; | 
|  | }; | 
|  |  | 
|  | extern void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, | 
|  | gdb_disassembly_flags flags, int how_many, | 
|  | CORE_ADDR low, CORE_ADDR high); | 
|  |  | 
|  | /* Print the instruction at address MEMADDR in debugged memory, | 
|  | on STREAM.  Returns the length of the instruction, in bytes, | 
|  | and, if requested, the number of branch delay slot instructions.  */ | 
|  |  | 
|  | extern int gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr, | 
|  | struct ui_file *stream, int *branch_delay_insns); | 
|  |  | 
|  | /* Class used to pretty-print instructions.  */ | 
|  |  | 
|  | class gdb_pretty_print_disassembler | 
|  | { | 
|  | public: | 
|  | explicit gdb_pretty_print_disassembler (struct gdbarch *gdbarch, | 
|  | struct ui_out *uiout) | 
|  | : m_uiout (uiout), | 
|  | m_insn_stb (uiout->can_emit_style_escape ()), | 
|  | m_di (gdbarch, &m_insn_stb) | 
|  | {} | 
|  |  | 
|  | /* Prints the instruction INSN into the saved ui_out and returns the | 
|  | length of the printed instruction in bytes.  */ | 
|  | int pretty_print_insn (const struct disasm_insn *insn, | 
|  | gdb_disassembly_flags flags); | 
|  |  | 
|  | private: | 
|  | /* Returns the architecture used for disassembling.  */ | 
|  | struct gdbarch *arch () { return m_di.arch (); } | 
|  |  | 
|  | /* The ui_out that is used by pretty_print_insn.  */ | 
|  | struct ui_out *m_uiout; | 
|  |  | 
|  | /* The buffer used to build the instruction string.  The | 
|  | disassembler is initialized with this stream.  */ | 
|  | string_file m_insn_stb; | 
|  |  | 
|  | /* The disassembler used for instruction printing.  */ | 
|  | gdb_disassembler m_di; | 
|  |  | 
|  | /* The buffer used to build the raw opcodes string.  */ | 
|  | string_file m_opcode_stb; | 
|  |  | 
|  | /* The buffer used to hold the opcode bytes (if required).  */ | 
|  | gdb::byte_vector m_opcode_data; | 
|  | }; | 
|  |  | 
|  | /* Return the length in bytes of the instruction at address MEMADDR in | 
|  | debugged memory.  */ | 
|  |  | 
|  | extern int gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR memaddr); | 
|  |  | 
|  | /* Return the length in bytes of INSN, originally at MEMADDR.  MAX_LEN | 
|  | is the size of the buffer containing INSN.  */ | 
|  |  | 
|  | extern int gdb_buffered_insn_length (struct gdbarch *gdbarch, | 
|  | const gdb_byte *insn, int max_len, | 
|  | CORE_ADDR memaddr); | 
|  |  | 
|  | /* Returns GDBARCH's disassembler options.  */ | 
|  |  | 
|  | extern char *get_disassembler_options (struct gdbarch *gdbarch); | 
|  |  | 
|  | /* Sets the active gdbarch's disassembler options to OPTIONS.  */ | 
|  |  | 
|  | extern void set_disassembler_options (const char *options); | 
|  |  | 
|  | #endif |