#include "defs.h"
#include "target.h"
#include "value.h"
#include "mi-cmds.h"
#include "mi-getopt.h"
#include "ui-out.h"
static int gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr, unsigned int len,
disassemble_info * info);
static int compare_lines (const PTR mle1p, const PTR mle2p);
struct dis_line_entry
{
int line;
CORE_ADDR start_pc;
CORE_ADDR end_pc;
};
int gdb_disassemble_from_exec = -1;
static int
gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr,
unsigned int len, disassemble_info * info)
{
extern struct target_ops exec_ops;
int res;
errno = 0;
res = xfer_memory (memaddr, myaddr, len, 0, &exec_ops);
if (res == len)
return 0;
else if (errno == 0)
return EIO;
else
return errno;
}
static int
compare_lines (const PTR mle1p, const PTR mle2p)
{
struct dis_line_entry *mle1, *mle2;
int val;
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;
}
enum mi_cmd_result
mi_cmd_disassemble (char *command, char **argv, int argc)
{
CORE_ADDR pc;
CORE_ADDR start;
CORE_ADDR low = 0;
CORE_ADDR high = 0;
int how_many = -1;
int mixed_source_and_assembly;
int num_displayed;
int line_num;
char *file_string;
static disassemble_info di;
static int di_initialized;
struct symtab *s;
static struct ui_stream *stb = NULL;
int line;
int offset;
int unmapped;
char *filename = NULL;
char *name = NULL;
int file_seen = 0;
int line_seen = 0;
int num_seen = 0;
int start_seen = 0;
int end_seen = 0;
int optind = 0;
char *optarg;
enum opt
{
FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT
};
static struct mi_opt opts[] =
{
{"f", FILE_OPT, 1},
{"l", LINE_OPT, 1},
{"n", NUM_OPT, 1},
{"s", START_OPT, 1},
{"e", END_OPT, 1},
0
};
while (1)
{
int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case FILE_OPT:
file_string = xstrdup (optarg);
file_seen = 1;
break;
case LINE_OPT:
line_num = atoi (optarg);
line_seen = 1;
break;
case NUM_OPT:
how_many = atoi (optarg);
num_seen = 1;
break;
case START_OPT:
low = parse_and_eval_address (optarg);
start_seen = 1;
break;
case END_OPT:
high = parse_and_eval_address (optarg);
end_seen = 1;
break;
}
}
argv += optind;
argc -= optind;
if (!((line_seen && file_seen && num_seen && !start_seen && !end_seen)
|| (line_seen && file_seen && !num_seen && !start_seen && !end_seen)
|| (!line_seen && !file_seen && !num_seen && start_seen && end_seen)))
error ("mi_cmd_disassemble: Usage: ( [-f filename -l linenum [-n howmany]] | [-s startaddr -e endaddr]) [--] mixed_mode.");
if (argc != 1)
error ("mi_cmd_disassemble: Usage: [-f filename -l linenum [-n howmany]] [-s startaddr -e endaddr] [--] mixed_mode.");
mixed_source_and_assembly = atoi (argv[0]);
if ((mixed_source_and_assembly != 0) && (mixed_source_and_assembly != 1))
error ("mi_cmd_disassemble: Mixed_mode argument must be 0 or 1.");
if (line_seen && file_seen)
{
s = lookup_symtab (file_string);
if (s == NULL)
error ("mi_cmd_disassemble: Invalid filename.");
if (!find_line_pc (s, line_num, &start))
error ("mi_cmd_disassemble: Invalid line number");
if (find_pc_partial_function (start, NULL, &low, &high) == 0)
error ("mi_cmd_disassemble: No function contains specified address");
}
if (!di_initialized)
{
stb = ui_out_stream_new (uiout);
INIT_DISASSEMBLE_INFO_NO_ARCH (di, stb->stream,
(fprintf_ftype) fprintf_unfiltered);
di.flavour = bfd_target_unknown_flavour;
di.memory_error_func = dis_asm_memory_error;
di.print_address_func = dis_asm_print_address;
di_initialized = 1;
}
di.mach = TARGET_PRINT_INSN_INFO->mach;
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
di.endian = BFD_ENDIAN_BIG;
else
di.endian = BFD_ENDIAN_LITTLE;
if (gdb_disassemble_from_exec == -1)
{
if (strcmp (target_shortname, "child") == 0
|| strcmp (target_shortname, "procfs") == 0
|| strcmp (target_shortname, "vxprocess") == 0
|| strstr (target_shortname, "-threads") != NULL)
gdb_disassemble_from_exec = 0;
else
gdb_disassemble_from_exec = 1;
}
if (gdb_disassemble_from_exec)
di.read_memory_func = gdb_dis_asm_read_memory;
else
di.read_memory_func = dis_asm_read_memory;
if (mixed_source_and_assembly)
{
struct symtab *symtab;
struct linetable_entry *le;
int nlines;
int newlines;
struct dis_line_entry *mle;
struct symtab_and_line sal;
int i;
int out_of_order;
int next_line;
symtab = find_pc_symtab (low);
if (!symtab || !symtab->linetable)
goto assembly_only;
le = symtab->linetable->item;
nlines = symtab->linetable->nitems;
if (nlines <= 0)
goto assembly_only;
mle = (struct dis_line_entry *) alloca (nlines * sizeof (struct dis_line_entry));
out_of_order = 0;
for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
newlines = 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;
mle[newlines].line = le[i].line;
if (le[i].line > le[i + 1].line)
out_of_order = 1;
mle[newlines].start_pc = le[i].pc;
mle[newlines].end_pc = le[i + 1].pc;
newlines++;
}
if (i == nlines - 1
&& le[i].pc < high)
{
mle[newlines].line = le[i].line;
mle[newlines].start_pc = le[i].pc;
sal = find_pc_line (le[i].pc, 0);
mle[newlines].end_pc = sal.end;
newlines++;
}
if (out_of_order)
qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
next_line = 0;
ui_out_list_begin (uiout, "asm_insns");
num_displayed = 0;
for (i = 0; i < newlines; i++)
{
int close_list = 1;
if (mle[i].line >= next_line)
{
if (next_line != 0)
{
if (next_line == mle[i].line)
{
ui_out_list_begin (uiout, "src_and_asm_line");
print_source_lines (symtab, next_line, mle[i].line + 1, 0);
}
else
{
for (; next_line < mle[i].line; next_line++)
{
ui_out_list_begin (uiout, "src_and_asm_line");
print_source_lines (symtab, next_line, mle[i].line + 1, 0);
ui_out_list_begin (uiout, "line_asm_insn");
ui_out_list_end (uiout);
ui_out_list_end (uiout);
}
ui_out_list_begin (uiout, "src_and_asm_line");
print_source_lines (symtab, next_line, mle[i].line + 1, 0);
}
}
else
{
ui_out_list_begin (uiout, "src_and_asm_line");
print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
}
next_line = mle[i].line + 1;
ui_out_list_begin (uiout, "line_asm_insn");
if (i + 1 < newlines && mle[i + 1].line <= mle[i].line)
close_list = 0;
}
for (pc = mle[i].start_pc; pc < mle[i].end_pc;)
{
QUIT;
if (how_many >= 0)
{
if (num_displayed >= how_many)
break;
else
num_displayed++;
}
ui_out_list_begin (uiout, NULL);
ui_out_field_core_addr (uiout, "address", pc);
if (!build_address_symbolic (pc, 0, &name, &offset, &filename, &line, &unmapped))
{
ui_out_field_string (uiout, "func-name", name);
ui_out_field_int (uiout, "offset", offset);
}
if (filename != NULL)
free (filename);
if (name != NULL)
free (name);
ui_file_rewind (stb->stream);
pc += (*tm_print_insn) (pc, &di);
ui_out_field_stream (uiout, "inst", stb);
ui_file_rewind (stb->stream);
ui_out_list_end (uiout);
}
if (close_list)
{
ui_out_list_end (uiout);
ui_out_list_end (uiout);
close_list = 0;
}
if (how_many >= 0)
if (num_displayed >= how_many)
break;
}
ui_out_list_end (uiout);
}
else
{
assembly_only:
ui_out_list_begin (uiout, "asm_insns");
num_displayed = 0;
for (pc = low; pc < high;)
{
QUIT;
if (how_many >= 0)
{
if (num_displayed >= how_many)
break;
else
num_displayed++;
}
ui_out_list_begin (uiout, NULL);
ui_out_field_core_addr (uiout, "address", pc);
if (!build_address_symbolic (pc, 0, &name, &offset, &filename, &line, &unmapped))
{
ui_out_field_string (uiout, "func-name", name);
ui_out_field_int (uiout, "offset", offset);
}
if (filename != NULL)
free (filename);
if (name != NULL)
free (name);
ui_file_rewind (stb->stream);
pc += (*tm_print_insn) (pc, &di);
ui_out_field_stream (uiout, "inst", stb);
ui_file_rewind (stb->stream);
ui_out_list_end (uiout);
}
ui_out_list_end (uiout);
}
gdb_flush (gdb_stdout);
return MI_CMD_DONE;
}