| /* 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" |
| #include "ui-out.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 const 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 |