X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fdisasm.c;h=833341a169107a588fe2759ac215ca776fadf7fd;hb=9a897d43f034544cd09292d0fb6fded7eb64ae8d;hp=03ff8d359e6870e6bbf8b22146553e527f7e4e02;hpb=187808b04f61df1c38fda0921e2d9eeb53e332ee;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/disasm.c b/gdb/disasm.c index 03ff8d359e..833341a169 100644 --- a/gdb/disasm.c +++ b/gdb/disasm.c @@ -1,6 +1,6 @@ /* Disassemble support for GDB. - Copyright (C) 2000-2017 Free Software Foundation, Inc. + Copyright (C) 2000-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -18,19 +18,27 @@ along with this program. If not, see . */ #include "defs.h" +#include "arch-utils.h" #include "target.h" #include "value.h" #include "ui-out.h" #include "disasm.h" #include "gdbcore.h" +#include "gdbcmd.h" #include "dis-asm.h" #include "source.h" +#include "safe-ctype.h" #include +#include "common/gdb_optional.h" /* Disassemble functions. FIXME: We should get rid of all the duplicate code in gdb that does the same thing: disassemble_command() and the gdbtk variation. */ +/* This variable is used to hold the prospective disassembler_options value + which is set by the "set disassembler_options" command. */ +static char *prospective_options = NULL; + /* This structure is used to store line number information for the deprecated /m option. We need a different sort of line table from the normal one cuz we can't @@ -182,109 +190,103 @@ compare_lines (const void *mle1p, const void *mle2p) /* See disasm.h. */ int -gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout, - const struct disasm_insn *insn, - int flags) +gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout, + const struct disasm_insn *insn, + gdb_disassembly_flags flags) { /* parts of the symbolic representation of the address */ int unmapped; int offset; int line; int size; - struct cleanup *ui_out_chain; char *filename = NULL; char *name = NULL; CORE_ADDR pc; - - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - pc = insn->addr; - - if (insn->number != 0) - { - uiout->field_fmt ("insn-number", "%u", insn->number); - uiout->text ("\t"); - } - - if ((flags & DISASSEMBLY_SPECULATIVE) != 0) - { - if (insn->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) - uiout->text (pc_prefix (pc) + 1); - else - uiout->text (" "); - } - else if ((flags & DISASSEMBLY_OMIT_PC) == 0) - uiout->text (pc_prefix (pc)); - else - uiout->text (" "); - } - else if ((flags & DISASSEMBLY_OMIT_PC) == 0) - 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. */ - uiout->text (" <"); - if ((flags & DISASSEMBLY_OMIT_FNAME) == 0) - uiout->field_string ("func-name", name); - uiout->text ("+"); - uiout->field_int ("offset", offset); - uiout->text (">:\t"); - } - else - uiout->text (":\t"); - - if (filename != NULL) - xfree (filename); - if (name != NULL) - xfree (name); - - struct ui_file *stb = mem_fileopen (); - make_cleanup_ui_file_delete (stb); - - if (flags & DISASSEMBLY_RAW_INSN) - { - CORE_ADDR end_pc; - bfd_byte data; - int err; - const char *spacer = ""; - - /* Build the opcodes using a temporary stream so we can - write them out in a single go for the MI. */ - struct ui_file *opcode_stream = mem_fileopen (); - struct cleanup *cleanups = - make_cleanup_ui_file_delete (opcode_stream); - - size = gdb_print_insn (gdbarch, pc, stb, NULL); - end_pc = pc + size; - - for (;pc < end_pc; ++pc) - { - read_code (pc, &data, 1); - fprintf_filtered (opcode_stream, "%s%02x", - spacer, (unsigned) data); - spacer = " "; - } - - uiout->field_stream ("opcodes", opcode_stream); - uiout->text ("\t"); - - do_cleanups (cleanups); - } - else - size = gdb_print_insn (gdbarch, pc, stb, NULL); - - uiout->field_stream ("inst", stb); - do_cleanups (ui_out_chain); + struct gdbarch *gdbarch = arch (); + + { + ui_out_emit_tuple tuple_emitter (uiout, NULL); + pc = insn->addr; + + if (insn->number != 0) + { + uiout->field_fmt ("insn-number", "%u", insn->number); + uiout->text ("\t"); + } + + if ((flags & DISASSEMBLY_SPECULATIVE) != 0) + { + if (insn->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) + uiout->text (pc_prefix (pc) + 1); + else + uiout->text (" "); + } + else if ((flags & DISASSEMBLY_OMIT_PC) == 0) + uiout->text (pc_prefix (pc)); + else + uiout->text (" "); + } + else if ((flags & DISASSEMBLY_OMIT_PC) == 0) + 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. */ + uiout->text (" <"); + if ((flags & DISASSEMBLY_OMIT_FNAME) == 0) + uiout->field_string ("func-name", name); + uiout->text ("+"); + uiout->field_int ("offset", offset); + uiout->text (">:\t"); + } + else + uiout->text (":\t"); + + if (filename != NULL) + xfree (filename); + if (name != NULL) + xfree (name); + + m_insn_stb.clear (); + + if (flags & DISASSEMBLY_RAW_INSN) + { + CORE_ADDR end_pc; + bfd_byte data; + const char *spacer = ""; + + /* Build the opcodes using a temporary stream so we can + write them out in a single go for the MI. */ + m_opcode_stb.clear (); + + size = m_di.print_insn (pc); + end_pc = pc + size; + + for (;pc < end_pc; ++pc) + { + read_code (pc, &data, 1); + m_opcode_stb.printf ("%s%02x", spacer, (unsigned) data); + spacer = " "; + } + + uiout->field_stream ("opcodes", m_opcode_stb); + uiout->text ("\t"); + } + else + size = m_di.print_insn (pc); + + uiout->field_stream ("inst", m_insn_stb); + } uiout->text ("\n"); return size; @@ -293,7 +295,7 @@ gdb_pretty_print_insn (struct gdbarch *gdbarch, struct ui_out *uiout, static int dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags, CORE_ADDR *end_pc) + int how_many, gdb_disassembly_flags flags, CORE_ADDR *end_pc) { struct disasm_insn insn; int num_displayed = 0; @@ -301,11 +303,13 @@ dump_insns (struct gdbarch *gdbarch, memset (&insn, 0, sizeof (insn)); insn.addr = low; + gdb_pretty_print_disassembler disasm (gdbarch); + while (insn.addr < high && (how_many < 0 || num_displayed < how_many)) { int size; - size = gdb_pretty_print_insn (gdbarch, uiout, &insn, flags); + size = disasm.pretty_print_insn (uiout, &insn, flags); if (size <= 0) break; @@ -334,7 +338,7 @@ do_mixed_source_and_assembly_deprecated (struct gdbarch *gdbarch, struct ui_out *uiout, struct symtab *symtab, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags) + int how_many, gdb_disassembly_flags flags) { int newlines = 0; int nlines; @@ -346,9 +350,6 @@ do_mixed_source_and_assembly_deprecated int next_line = 0; int num_displayed = 0; print_source_lines_flags psl_flags = 0; - struct cleanup *ui_out_chain; - struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0); - struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0); gdb_assert (symtab != NULL && SYMTAB_LINETABLE (symtab) != NULL); @@ -410,7 +411,10 @@ do_mixed_source_and_assembly_deprecated they have been emitted before), followed by the assembly code for that line. */ - ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns"); + ui_out_emit_list asm_insns_list (uiout, "asm_insns"); + + gdb::optional outer_tuple_emitter; + gdb::optional inner_list_emitter; for (i = 0; i < newlines; i++) { @@ -422,9 +426,7 @@ do_mixed_source_and_assembly_deprecated /* Just one line to print. */ if (next_line == mle[i].line) { - ui_out_tuple_chain - = make_cleanup_ui_out_tuple_begin_end (uiout, - "src_and_asm_line"); + outer_tuple_emitter.emplace (uiout, "src_and_asm_line"); print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); } else @@ -432,39 +434,27 @@ do_mixed_source_and_assembly_deprecated /* Several source lines w/o asm instructions associated. */ for (; next_line < mle[i].line; next_line++) { - struct cleanup *ui_out_list_chain_line; - struct cleanup *ui_out_tuple_chain_line; - - ui_out_tuple_chain_line - = make_cleanup_ui_out_tuple_begin_end (uiout, - "src_and_asm_line"); + ui_out_emit_tuple tuple_emitter (uiout, + "src_and_asm_line"); print_source_lines (symtab, next_line, next_line + 1, psl_flags); - ui_out_list_chain_line - = make_cleanup_ui_out_list_begin_end (uiout, - "line_asm_insn"); - do_cleanups (ui_out_list_chain_line); - do_cleanups (ui_out_tuple_chain_line); + ui_out_emit_list inner_list_emitter (uiout, + "line_asm_insn"); } /* Print the last line and leave list open for asm instructions to be added. */ - ui_out_tuple_chain - = make_cleanup_ui_out_tuple_begin_end (uiout, - "src_and_asm_line"); + outer_tuple_emitter.emplace (uiout, "src_and_asm_line"); print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags); } } else { - ui_out_tuple_chain - = make_cleanup_ui_out_tuple_begin_end (uiout, - "src_and_asm_line"); + outer_tuple_emitter.emplace (uiout, "src_and_asm_line"); print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags); } next_line = mle[i].line + 1; - ui_out_list_chain - = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn"); + inner_list_emitter.emplace (uiout, "line_asm_insn"); } num_displayed += dump_insns (gdbarch, uiout, @@ -475,16 +465,13 @@ do_mixed_source_and_assembly_deprecated assembly range for this source line, close out the list/tuple. */ if (i == (newlines - 1) || mle[i + 1].line > mle[i].line) { - do_cleanups (ui_out_list_chain); - do_cleanups (ui_out_tuple_chain); - ui_out_tuple_chain = make_cleanup (null_cleanup, 0); - ui_out_list_chain = make_cleanup (null_cleanup, 0); + inner_list_emitter.reset (); + outer_tuple_emitter.reset (); uiout->text ("\n"); } if (how_many >= 0 && num_displayed >= how_many) break; } - do_cleanups (ui_out_chain); } /* The idea here is to present a source-O-centric view of a @@ -497,15 +484,12 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, struct symtab *main_symtab, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags) + int how_many, gdb_disassembly_flags flags) { const struct linetable_entry *le, *first_le; int i, nlines; int num_displayed = 0; print_source_lines_flags psl_flags = 0; - 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; @@ -566,21 +550,21 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, CLI output works on top of this because MI ignores ui_out_text output, which is where we put file name and source line contents output. - Cleanup usage: - ui_out_chain + Emitter usage: + asm_insns_emitter Handles the outer "asm_insns" list. - ui_out_tuple_chain + tuple_emitter The tuples for each group of consecutive disassemblies. - ui_out_list_chain + list_emitter List of consecutive source lines or disassembled insns. */ if (flags & DISASSEMBLY_FILENAME) psl_flags |= PRINT_SOURCE_LINES_FILENAME; - ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns"); + ui_out_emit_list asm_insns_emitter (uiout, "asm_insns"); - ui_out_tuple_chain = NULL; - ui_out_list_chain = NULL; + gdb::optional tuple_emitter; + gdb::optional list_emitter; last_symtab = NULL; last_line = 0; @@ -649,11 +633,11 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, /* Skip the newline if this is the first instruction. */ if (pc > low) uiout->text ("\n"); - if (ui_out_tuple_chain != NULL) + if (tuple_emitter.has_value ()) { - gdb_assert (ui_out_list_chain != NULL); - do_cleanups (ui_out_list_chain); - do_cleanups (ui_out_tuple_chain); + gdb_assert (list_emitter.has_value ()); + list_emitter.reset (); + tuple_emitter.reset (); } if (sal.symtab != last_symtab && !(flags & DISASSEMBLY_FILENAME)) @@ -675,41 +659,31 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, We need to preserve the structure of the output, so output a bunch of line tuples with no asm entries. */ int l; - struct cleanup *ui_out_list_chain_line; - struct cleanup *ui_out_tuple_chain_line; gdb_assert (sal.symtab != NULL); for (l = start_preceding_line_to_display; l < end_preceding_line_to_display; ++l) { - ui_out_tuple_chain_line - = make_cleanup_ui_out_tuple_begin_end (uiout, - "src_and_asm_line"); + ui_out_emit_tuple tuple_emitter (uiout, "src_and_asm_line"); print_source_lines (sal.symtab, l, l + 1, psl_flags); - ui_out_list_chain_line - = make_cleanup_ui_out_list_begin_end (uiout, - "line_asm_insn"); - do_cleanups (ui_out_list_chain_line); - do_cleanups (ui_out_tuple_chain_line); + ui_out_emit_list chain_line_emitter (uiout, "line_asm_insn"); } } - ui_out_tuple_chain - = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line"); + tuple_emitter.emplace (uiout, "src_and_asm_line"); if (sal.symtab != NULL) print_source_lines (sal.symtab, sal.line, sal.line + 1, psl_flags); else uiout->text (_("--- no source info for this pc ---\n")); - ui_out_list_chain - = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn"); + list_emitter.emplace (uiout, "line_asm_insn"); } else { /* Here we're appending instructions to an existing line. By construction the very first insn will have a symtab and follow the new_source_line path above. */ - gdb_assert (ui_out_tuple_chain != NULL); - gdb_assert (ui_out_list_chain != NULL); + gdb_assert (tuple_emitter.has_value ()); + gdb_assert (list_emitter.has_value ()); } if (sal.end != 0) @@ -726,22 +700,16 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, last_symtab = sal.symtab; last_line = sal.line; } - - do_cleanups (ui_out_chain); } static void do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout, CORE_ADDR low, CORE_ADDR high, - int how_many, int flags) + int how_many, gdb_disassembly_flags flags) { - struct cleanup *ui_out_chain; - - ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns"); + ui_out_emit_list list_emitter (uiout, "asm_insns"); dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL); - - do_cleanups (ui_out_chain); } /* Initialize the disassemble info struct ready for the specified @@ -783,6 +751,7 @@ gdb_disassembler::gdb_disassembler (struct gdbarch *gdbarch, m_di.endian = gdbarch_byte_order (gdbarch); m_di.endian_code = gdbarch_byte_order_for_code (gdbarch); m_di.application_data = this; + m_di.disassembler_options = get_disassembler_options (gdbarch); disassemble_init_for_target (&m_di); } @@ -809,7 +778,7 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr, void gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, - int flags, int how_many, + gdb_disassembly_flags flags, int how_many, CORE_ADDR low, CORE_ADDR high) { struct symtab *symtab; @@ -856,7 +825,7 @@ gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr, int gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr) { - 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 @@ -891,6 +860,7 @@ gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch, di->endian = gdbarch_byte_order (gdbarch); di->endian_code = gdbarch_byte_order_for_code (gdbarch); + di->disassembler_options = get_disassembler_options (gdbarch); disassemble_init_for_target (di); } @@ -907,3 +877,170 @@ gdb_buffered_insn_length (struct gdbarch *gdbarch, return gdbarch_print_insn (gdbarch, addr, &di); } + +char * +get_disassembler_options (struct gdbarch *gdbarch) +{ + char **disassembler_options = gdbarch_disassembler_options (gdbarch); + if (disassembler_options == NULL) + return NULL; + return *disassembler_options; +} + +void +set_disassembler_options (char *prospective_options) +{ + struct gdbarch *gdbarch = get_current_arch (); + char **disassembler_options = gdbarch_disassembler_options (gdbarch); + const disasm_options_t *valid_options; + char *options = remove_whitespace_and_extra_commas (prospective_options); + const char *opt; + + /* Allow all architectures, even ones that do not support 'set disassembler', + to reset their disassembler options to NULL. */ + if (options == NULL) + { + if (disassembler_options != NULL) + { + free (*disassembler_options); + *disassembler_options = NULL; + } + return; + } + + valid_options = gdbarch_valid_disassembler_options (gdbarch); + if (valid_options == NULL) + { + fprintf_filtered (gdb_stdlog, _("\ +'set disassembler-options ...' is not supported on this architecture.\n")); + return; + } + + /* Verify we have valid disassembler options. */ + FOR_EACH_DISASSEMBLER_OPTION (opt, options) + { + size_t i; + for (i = 0; valid_options->name[i] != NULL; i++) + if (disassembler_options_cmp (opt, valid_options->name[i]) == 0) + break; + if (valid_options->name[i] == NULL) + { + fprintf_filtered (gdb_stdlog, + _("Invalid disassembler option value: '%s'.\n"), + opt); + return; + } + } + + free (*disassembler_options); + *disassembler_options = xstrdup (options); +} + +static void +set_disassembler_options_sfunc (const char *args, int from_tty, + struct cmd_list_element *c) +{ + set_disassembler_options (prospective_options); +} + +static void +show_disassembler_options_sfunc (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + struct gdbarch *gdbarch = get_current_arch (); + const disasm_options_t *valid_options; + + const char *options = get_disassembler_options (gdbarch); + if (options == NULL) + options = ""; + + fprintf_filtered (file, _("The current disassembler options are '%s'\n"), + options); + + valid_options = gdbarch_valid_disassembler_options (gdbarch); + + if (valid_options == NULL) + return; + + fprintf_filtered (file, _("\n\ +The following disassembler options are supported for use with the\n\ +'set disassembler-options