/* Disassemble support for GDB.
- Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2000-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcore.h"
#include "dis-asm.h"
#include "source.h"
+#include <algorithm>
/* Disassemble functions.
FIXME: We should get rid of all the duplicate code in gdb that does
return htab_find (table, &dle) != NULL;
}
-/* Like target_read_memory, but slightly different parameters. */
-static int
-dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
- struct disassemble_info *info)
+/* Wrapper of target_read_code. */
+
+int
+gdb_disassembler::dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr,
+ unsigned int len,
+ struct disassemble_info *info)
{
return target_read_code (memaddr, myaddr, len);
}
-/* Like memory_error with slightly different parameters. */
-static void
-dis_asm_memory_error (int err, bfd_vma memaddr,
- struct disassemble_info *info)
+/* Wrapper of memory_error. */
+
+void
+gdb_disassembler::dis_asm_memory_error (int err, bfd_vma memaddr,
+ struct disassemble_info *info)
{
- memory_error (TARGET_XFER_E_IO, memaddr);
+ gdb_disassembler *self
+ = static_cast<gdb_disassembler *>(info->application_data);
+
+ self->m_err_memaddr = memaddr;
}
-/* Like print_address with slightly different parameters. */
-static void
-dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
+/* Wrapper of print_address. */
+
+void
+gdb_disassembler::dis_asm_print_address (bfd_vma addr,
+ struct disassemble_info *info)
{
- struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+ gdb_disassembler *self
+ = static_cast<gdb_disassembler *>(info->application_data);
- print_address (gdbarch, addr, (struct ui_file *) info->stream);
+ print_address (self->arch (), addr, self->stream ());
}
static int
/* See disasm.h. */
int
-gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info * di,
- const struct disasm_insn *insn, int flags,
- struct ui_file *stb)
+gdb_disassembler::pretty_print_insn (struct ui_out *uiout,
+ const struct disasm_insn *insn,
+ int flags)
{
/* parts of the symbolic representation of the address */
int unmapped;
char *filename = NULL;
char *name = NULL;
CORE_ADDR pc;
+ struct ui_file *stb = stream ();
+ struct gdbarch *gdbarch = arch ();
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
pc = insn->addr;
if (insn->number != 0)
{
- ui_out_field_fmt (uiout, "insn-number", "%u", insn->number);
- ui_out_text (uiout, "\t");
+ uiout->field_fmt ("insn-number", "%u", insn->number);
+ uiout->text ("\t");
}
if ((flags & DISASSEMBLY_SPECULATIVE) != 0)
{
if (insn->is_speculative)
{
- ui_out_field_string (uiout, "is-speculative", "?");
+ uiout->field_string ("is-speculative", "?");
/* The speculative execution indication overwrites the first
character of the PC prefix.
We assume a PC prefix length of 3 characters. */
if ((flags & DISASSEMBLY_OMIT_PC) == 0)
- ui_out_text (uiout, pc_prefix (pc) + 1);
+ uiout->text (pc_prefix (pc) + 1);
else
- ui_out_text (uiout, " ");
+ uiout->text (" ");
}
else if ((flags & DISASSEMBLY_OMIT_PC) == 0)
- ui_out_text (uiout, pc_prefix (pc));
+ uiout->text (pc_prefix (pc));
else
- ui_out_text (uiout, " ");
+ uiout->text (" ");
}
else if ((flags & DISASSEMBLY_OMIT_PC) == 0)
- ui_out_text (uiout, pc_prefix (pc));
- ui_out_field_core_addr (uiout, "address", gdbarch, pc);
+ uiout->text (pc_prefix (pc));
+ uiout->field_core_addr ("address", gdbarch, pc);
if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename,
&line, &unmapped))
{
/* We don't care now about line, filename and unmapped. But we might in
the future. */
- ui_out_text (uiout, " <");
+ uiout->text (" <");
if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
- ui_out_field_string (uiout, "func-name", name);
- ui_out_text (uiout, "+");
- ui_out_field_int (uiout, "offset", offset);
- ui_out_text (uiout, ">:\t");
+ uiout->field_string ("func-name", name);
+ uiout->text ("+");
+ uiout->field_int ("offset", offset);
+ uiout->text (">:\t");
}
else
- ui_out_text (uiout, ":\t");
+ uiout->text (":\t");
if (filename != NULL)
xfree (filename);
struct cleanup *cleanups =
make_cleanup_ui_file_delete (opcode_stream);
- size = gdbarch_print_insn (gdbarch, pc, di);
+ size = print_insn (pc);
end_pc = pc + size;
for (;pc < end_pc; ++pc)
{
- err = (*di->read_memory_func) (pc, &data, 1, di);
+ err = m_di.read_memory_func (pc, &data, 1, &m_di);
if (err != 0)
- (*di->memory_error_func) (err, pc, di);
+ m_di.memory_error_func (err, pc, &m_di);
fprintf_filtered (opcode_stream, "%s%02x",
spacer, (unsigned) data);
spacer = " ";
}
- ui_out_field_stream (uiout, "opcodes", opcode_stream);
- ui_out_text (uiout, "\t");
+ uiout->field_stream ("opcodes", opcode_stream);
+ uiout->text ("\t");
do_cleanups (cleanups);
}
else
- size = gdbarch_print_insn (gdbarch, pc, di);
+ size = print_insn (pc);
- ui_out_field_stream (uiout, "inst", stb);
+ uiout->field_stream ("inst", stb);
ui_file_rewind (stb);
do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
+ uiout->text ("\n");
return size;
}
static int
-dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info * di,
+dump_insns (struct ui_out *uiout, gdb_disassembler *di,
CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags, struct ui_file *stb,
+ int how_many, int flags,
CORE_ADDR *end_pc)
{
struct disasm_insn insn;
{
int size;
- size = gdb_pretty_print_insn (gdbarch, uiout, di, &insn, flags, stb);
+ size = di->pretty_print_insn (uiout, &insn, flags);
if (size <= 0)
break;
static void
do_mixed_source_and_assembly_deprecated
- (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info *di, struct symtab *symtab,
+ (struct ui_out *uiout,
+ gdb_disassembler *di, struct symtab *symtab,
CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags, struct ui_file *stb)
+ int how_many, int flags)
{
int newlines = 0;
int nlines;
= make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
}
- num_displayed += dump_insns (gdbarch, uiout, di,
+ num_displayed += dump_insns (uiout, di,
mle[i].start_pc, mle[i].end_pc,
- how_many, flags, stb, NULL);
+ how_many, flags, NULL);
/* When we've reached the end of the mle array, or we've seen the last
assembly range for this source line, close out the list/tuple. */
do_cleanups (ui_out_tuple_chain);
ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
ui_out_list_chain = make_cleanup (null_cleanup, 0);
- ui_out_text (uiout, "\n");
+ uiout->text ("\n");
}
if (how_many >= 0 && num_displayed >= how_many)
break;
immediately following. */
static void
-do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info *di,
+do_mixed_source_and_assembly (struct gdbarch *gdbarch,
+ struct ui_out *uiout,
+ gdb_disassembler *di,
struct symtab *main_symtab,
CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags, struct ui_file *stb)
+ int how_many, int flags)
{
- int newlines = 0;
const struct linetable_entry *le, *first_le;
- struct symtab_and_line sal;
int i, nlines;
- int out_of_order = 0;
- int next_line = 0;
int num_displayed = 0;
print_source_lines_flags psl_flags = 0;
- struct cleanup *cleanups;
struct cleanup *ui_out_chain;
struct cleanup *ui_out_tuple_chain;
struct cleanup *ui_out_list_chain;
CORE_ADDR pc;
struct symtab *last_symtab;
int last_line;
- htab_t dis_line_table;
gdb_assert (main_symtab != NULL && SYMTAB_LINETABLE (main_symtab) != NULL);
but if that text is for code that will be disassembled later, then
we'll want to defer printing it until later with its associated code. */
- dis_line_table = allocate_dis_line_table ();
- cleanups = make_cleanup_htab_delete (dis_line_table);
+ htab_up dis_line_table (allocate_dis_line_table ());
pc = low;
pc += length;
if (sal.symtab != NULL)
- add_dis_line_entry (dis_line_table, sal.symtab, sal.line);
+ add_dis_line_entry (dis_line_table.get (), sal.symtab, sal.line);
}
/* Second pass: print the disassembly.
which is where we put file name and source line contents output.
Cleanup usage:
- cleanups:
- For things created at the beginning of this function and need to be
- kept until the end of this function.
ui_out_chain
Handles the outer "asm_insns" list.
ui_out_tuple_chain
while (pc < high)
{
- struct linetable_entry *le = NULL;
struct symtab_and_line sal;
CORE_ADDR end_pc;
int start_preceding_line_to_display = 0;
not associated with code that we'll print later. */
for (l = sal.line - 1; l > last_line; --l)
{
- if (line_has_code_p (dis_line_table, sal.symtab, l))
+ if (line_has_code_p (dis_line_table.get (),
+ sal.symtab, l))
break;
}
if (l < sal.line - 1)
{
/* Skip the newline if this is the first instruction. */
if (pc > low)
- ui_out_text (uiout, "\n");
+ uiout->text ("\n");
if (ui_out_tuple_chain != NULL)
{
gdb_assert (ui_out_list_chain != NULL);
output includes the source specs for each line. */
if (sal.symtab != NULL)
{
- ui_out_text (uiout,
- symtab_to_filename_for_display (sal.symtab));
+ uiout->text (symtab_to_filename_for_display (sal.symtab));
}
else
- ui_out_text (uiout, "unknown");
- ui_out_text (uiout, ":\n");
+ uiout->text ("unknown");
+ uiout->text (":\n");
}
if (start_preceding_line_to_display > 0)
{
if (sal.symtab != NULL)
print_source_lines (sal.symtab, sal.line, sal.line + 1, psl_flags);
else
- ui_out_text (uiout, _("--- no source info for this pc ---\n"));
+ uiout->text (_("--- no source info for this pc ---\n"));
ui_out_list_chain
= make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
}
}
if (sal.end != 0)
- end_pc = min (sal.end, high);
+ end_pc = std::min (sal.end, high);
else
end_pc = pc + 1;
- num_displayed += dump_insns (gdbarch, uiout, di, pc, end_pc,
- how_many, flags, stb, &end_pc);
+ num_displayed += dump_insns (uiout, di, pc, end_pc,
+ how_many, flags, &end_pc);
pc = end_pc;
if (how_many >= 0 && num_displayed >= how_many)
}
do_cleanups (ui_out_chain);
- do_cleanups (cleanups);
}
static void
-do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
- struct disassemble_info * di,
+do_assembly_only (struct ui_out *uiout,
+ gdb_disassembler *di,
CORE_ADDR low, CORE_ADDR high,
- int how_many, int flags, struct ui_file *stb)
+ int how_many, int flags)
{
- int num_displayed = 0;
struct cleanup *ui_out_chain;
ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
- num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many,
- flags, stb, NULL);
+ dump_insns (uiout, di, low, high, how_many, flags, NULL);
do_cleanups (ui_out_chain);
}
return 0;
}
-struct disassemble_info
-gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
+gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ di_read_memory_ftype read_memory_func)
+ : m_gdbarch (gdbarch),
+ m_err_memaddr (0)
{
- struct disassemble_info di;
-
- init_disassemble_info (&di, file, fprintf_disasm);
- di.flavour = bfd_target_unknown_flavour;
- di.memory_error_func = dis_asm_memory_error;
- di.print_address_func = dis_asm_print_address;
+ init_disassemble_info (&m_di, file, fprintf_disasm);
+ m_di.flavour = bfd_target_unknown_flavour;
+ m_di.memory_error_func = dis_asm_memory_error;
+ m_di.print_address_func = dis_asm_print_address;
/* NOTE: cagney/2003-04-28: The original code, from the old Insight
disassembler had a local optomization here. By default it would
access the executable file, instead of the target memory (there
didn't work as they relied on the access going to the target.
Further, it has been supperseeded by trust-read-only-sections
(although that should be superseeded by target_trust..._p()). */
- di.read_memory_func = dis_asm_read_memory;
- di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
- di.endian = gdbarch_byte_order (gdbarch);
- di.endian_code = gdbarch_byte_order_for_code (gdbarch);
- di.application_data = gdbarch;
- disassemble_init_for_target (&di);
- return di;
+ m_di.read_memory_func = read_memory_func;
+ m_di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+ m_di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+ m_di.endian = gdbarch_byte_order (gdbarch);
+ m_di.endian_code = gdbarch_byte_order_for_code (gdbarch);
+ m_di.application_data = this;
+ disassemble_init_for_target (&m_di);
+}
+
+int
+gdb_disassembler::print_insn (CORE_ADDR memaddr,
+ int *branch_delay_insns)
+{
+ m_err_memaddr = 0;
+
+ int length = gdbarch_print_insn (arch (), memaddr, &m_di);
+
+ if (length < 0)
+ memory_error (TARGET_XFER_E_IO, m_err_memaddr);
+
+ if (branch_delay_insns != NULL)
+ {
+ if (m_di.insn_info_valid)
+ *branch_delay_insns = m_di.branch_delay_insns;
+ else
+ *branch_delay_insns = 0;
+ }
+ return length;
}
void
gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
- char *file_string, int flags, int how_many,
+ int flags, int how_many,
CORE_ADDR low, CORE_ADDR high)
{
struct ui_file *stb = mem_fileopen ();
struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
- struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
+ gdb_disassembler di (gdbarch, stb);
struct symtab *symtab;
- struct linetable_entry *le = NULL;
int nlines = -1;
/* Assume symtab is valid for whole PC range. */
if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
|| nlines <= 0)
- do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
+ do_assembly_only (uiout, &di, low, high, how_many, flags);
else if (flags & DISASSEMBLY_SOURCE)
do_mixed_source_and_assembly (gdbarch, uiout, &di, symtab, low, high,
- how_many, flags, stb);
+ how_many, flags);
else if (flags & DISASSEMBLY_SOURCE_DEPRECATED)
- do_mixed_source_and_assembly_deprecated (gdbarch, uiout, &di, symtab,
- low, high, how_many, flags, stb);
+ do_mixed_source_and_assembly_deprecated (uiout, &di, symtab,
+ low, high, how_many, flags);
do_cleanups (cleanups);
gdb_flush (gdb_stdout);
gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
struct ui_file *stream, int *branch_delay_insns)
{
- struct disassemble_info di;
- int length;
- di = gdb_disassemble_info (gdbarch, stream);
- length = gdbarch_print_insn (gdbarch, memaddr, &di);
- if (branch_delay_insns)
- {
- if (di.insn_info_valid)
- *branch_delay_insns = di.branch_delay_insns;
- else
- *branch_delay_insns = 0;
- }
- return length;
-}
+ gdb_disassembler di (gdbarch, stream);
-static void
-do_ui_file_delete (void *arg)
-{
- ui_file_delete ((struct ui_file *) arg);
+ return di.print_insn (memaddr, branch_delay_insns);
}
/* Return the length in bytes of the instruction at address MEMADDR in
int
gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
{
- static struct ui_file *null_stream = NULL;
-
- /* Dummy file descriptor for the disassembler. */
- if (!null_stream)
- {
- null_stream = ui_file_new ();
- make_final_cleanup (do_ui_file_delete, null_stream);
- }
-
- return gdb_print_insn (gdbarch, addr, null_stream, NULL);
+ return gdb_print_insn (gdbarch, addr, null_stream (), NULL);
}
/* fprintf-function for gdb_buffered_insn_length. This function is a