/* Disassemble support for GDB.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GDB.
/* 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. */
+ the same thing: disassemble_command() and the gdbtk variation. */
/* This Structure is used to store line number information.
We need a different sort of line table from the normal one cuz we can't
dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
{
struct gdbarch *gdbarch = info->application_data;
+
print_address (gdbarch, addr, info->stream);
}
mle1 = (struct dis_line_entry *) mle1p;
mle2 = (struct dis_line_entry *) mle2p;
- val = mle1->line - mle2->line;
-
- if (val != 0)
- return val;
-
- return mle1->start_pc - mle2->start_pc;
+ /* End of sequence markers have a line number of 0 but don't want to
+ be sorted to the head of the list, instead sort by PC. */
+ if (mle1->line == 0 || mle2->line == 0)
+ {
+ val = mle1->start_pc - mle2->start_pc;
+ if (val == 0)
+ val = mle1->line - mle2->line;
+ }
+ else
+ {
+ val = mle1->line - mle2->line;
+ if (val == 0)
+ val = mle1->start_pc - mle2->start_pc;
+ }
+ return val;
}
static int
&line, &unmapped))
{
/* We don't care now about line, filename and
- unmapped. But we might in the future. */
+ unmapped. But we might in the future. */
ui_out_text (uiout, " <");
if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
ui_out_field_string (uiout, "func-name", name);
CORE_ADDR old_pc = pc;
bfd_byte data;
int status;
+ 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_stream *opcode_stream = ui_out_stream_new (uiout);
+ struct cleanup *cleanups =
+ make_cleanup_ui_out_stream_delete (opcode_stream);
+
pc += gdbarch_print_insn (gdbarch, pc, di);
for (;old_pc < pc; old_pc++)
{
status = (*di->read_memory_func) (old_pc, &data, 1, di);
if (status != 0)
(*di->memory_error_func) (status, old_pc, di);
- ui_out_message (uiout, 0, " %02x", (unsigned)data);
+ fprintf_filtered (opcode_stream->stream, "%s%02x",
+ spacer, (unsigned) data);
+ spacer = " ";
}
+ ui_out_field_stream (uiout, "opcodes", opcode_stream);
ui_out_text (uiout, "\t");
+
+ do_cleanups (cleanups);
}
else
pc += gdbarch_print_insn (gdbarch, pc, di);
function to the user. This means that things are presented
in source order, with (possibly) out of order assembly
immediately following. */
+
static void
do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
struct disassemble_info *di, int nlines,
int i;
int out_of_order = 0;
int next_line = 0;
- CORE_ADDR pc;
int num_displayed = 0;
struct cleanup *ui_out_chain;
struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
for (; i < nlines - 1 && le[i].pc < high; i++)
{
if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
- continue; /* Ignore duplicates */
+ continue; /* Ignore duplicates. */
/* Skip any end-of-function markers. */
if (le[i].line == 0)
}
/* Now, sort mle by line #s (and, then by addresses within
- lines). */
+ lines). */
if (out_of_order)
qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
{
if (next_line != 0)
{
- /* Just one line to print. */
+ /* Just one line to print. */
if (next_line == mle[i].line)
{
ui_out_tuple_chain
}
else
{
- /* Several source lines w/o asm instructions associated. */
+ /* Several source lines w/o asm instructions associated. */
for (; next_line < mle[i].line; next_line++)
{
struct cleanup *ui_out_list_chain_line;
do_cleanups (ui_out_tuple_chain_line);
}
/* Print the last line and leave list open for
- asm instructions to be added. */
+ asm instructions to be added. */
ui_out_tuple_chain
= make_cleanup_ui_out_tuple_begin_end (uiout,
"src_and_asm_line");
else
{
ui_out_tuple_chain
- = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
+ = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "src_and_asm_line");
print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
}
/* Initialize the disassemble info struct ready for the specified
stream. */
-static int ATTR_FORMAT (printf, 2, 3)
+static int ATTRIBUTE_PRINTF (2, 3)
fprintf_disasm (void *stream, const char *format, ...)
{
va_list args;
+
va_start (args, format);
vfprintf_filtered (stream, format, args);
va_end (args);
gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
{
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;
struct ui_stream *stb = ui_out_stream_new (uiout);
struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb);
struct disassemble_info di = gdb_disassemble_info (gdbarch, stb->stream);
- /* To collect the instruction outputted from opcodes. */
+ /* To collect the instruction outputted from opcodes. */
struct symtab *symtab = NULL;
struct linetable_entry *le = NULL;
int nlines = -1;
- /* Assume symtab is valid for whole PC range */
+ /* Assume symtab is valid for whole PC range. */
symtab = find_pc_symtab (low);
if (symtab != NULL && symtab->linetable != NULL)
}
return length;
}
+
+static void
+do_ui_file_delete (void *arg)
+{
+ ui_file_delete (arg);
+}
+
+/* Return the length in bytes of the instruction at address MEMADDR in
+ debugged memory. */
+
+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);
+}
+
+/* fprintf-function for gdb_buffered_insn_length. This function is a
+ nop, we don't want to print anything, we just want to compute the
+ length of the insn. */
+
+static int ATTRIBUTE_PRINTF (2, 3)
+gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...)
+{
+ return 0;
+}
+
+/* Initialize a struct disassemble_info for gdb_buffered_insn_length. */
+
+static void
+gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
+ struct disassemble_info *di,
+ const gdb_byte *insn, int max_len,
+ CORE_ADDR addr)
+{
+ init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf);
+
+ /* init_disassemble_info installs buffer_read_memory, etc.
+ so we don't need to do that here.
+ The cast is necessary until disassemble_info is const-ified. */
+ di->buffer = (gdb_byte *) insn;
+ di->buffer_length = max_len;
+ di->buffer_vma = addr;
+
+ 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);
+
+ disassemble_init_for_target (di);
+}
+
+/* Return the length in bytes of INSN. MAX_LEN is the size of the
+ buffer containing INSN. */
+
+int
+gdb_buffered_insn_length (struct gdbarch *gdbarch,
+ const gdb_byte *insn, int max_len, CORE_ADDR addr)
+{
+ struct disassemble_info di;
+
+ gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
+
+ return gdbarch_print_insn (gdbarch, addr, &di);
+}