mi-cmd-disas.c revision 98944
1/* MI Command Set - disassemble commands.
2   Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
3   Contributed by Cygnus Solutions (a Red Hat company).
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.  */
21
22#include "defs.h"
23#include "target.h"
24#include "value.h"
25#include "mi-cmds.h"
26#include "mi-getopt.h"
27#include "ui-out.h"
28
29static int gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr, unsigned int len,
30				    disassemble_info * info);
31static int compare_lines (const PTR mle1p, const PTR mle2p);
32
33/* Disassemble functions. FIXME: these do not really belong here. We
34   should get rid of all the duplicate code in gdb that does the same
35   thing: disassemble_command() and the gdbtk variation. */
36
37/* This Structure is used in mi_cmd_disassemble.
38   We need a different sort of line table from the normal one cuz we can't
39   depend upon implicit line-end pc's for lines to do the
40   reordering in this function.  */
41
42struct dis_line_entry
43  {
44    int line;
45    CORE_ADDR start_pc;
46    CORE_ADDR end_pc;
47  };
48
49/* This variable determines where memory used for disassembly is read from. */
50int gdb_disassemble_from_exec = -1;
51
52/* This is the memory_read_func for gdb_disassemble when we are
53   disassembling from the exec file. */
54static int
55gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr,
56			 unsigned int len, disassemble_info * info)
57{
58  extern struct target_ops exec_ops;
59  int res;
60
61  errno = 0;
62  res = xfer_memory (memaddr, myaddr, len, 0, 0, &exec_ops);
63
64  if (res == len)
65    return 0;
66  else if (errno == 0)
67    return EIO;
68  else
69    return errno;
70}
71
72static int
73compare_lines (const PTR mle1p, const PTR mle2p)
74{
75  struct dis_line_entry *mle1, *mle2;
76  int val;
77
78  mle1 = (struct dis_line_entry *) mle1p;
79  mle2 = (struct dis_line_entry *) mle2p;
80
81  val = mle1->line - mle2->line;
82
83  if (val != 0)
84    return val;
85
86  return mle1->start_pc - mle2->start_pc;
87}
88
89/* The arguments to be passed on the command line and parsed here are:
90
91   either:
92
93   START-ADDRESS: address to start the disassembly at.
94   END-ADDRESS: address to end the disassembly at.
95
96   or:
97
98   FILENAME: The name of the file where we want disassemble from.
99   LINE: The line around which we want to disassemble. It will
100   disassemble the function that contins that line.
101   HOW_MANY: Number of disassembly lines to display. In mixed mode, it
102   is the number of disassembly lines only, not counting the source
103   lines.
104
105   always required:
106
107   MODE: 0 or 1 for disassembly only, or mixed source and disassembly,
108   respectively. */
109
110enum mi_cmd_result
111mi_cmd_disassemble (char *command, char **argv, int argc)
112{
113  CORE_ADDR pc;
114  CORE_ADDR start;
115
116  int mixed_source_and_assembly;
117  int num_displayed;
118  static disassemble_info di;
119  static int di_initialized;
120
121  struct symtab *s;
122
123  /* To collect the instruction outputted from opcodes. */
124  static struct ui_stream *stb = NULL;
125
126  /* parts of the symbolic representation of the address */
127  int line;
128  int offset;
129  int unmapped;
130  char *filename = NULL;
131  char *name = NULL;
132
133  /* Which options have we processed ... */
134  int file_seen = 0;
135  int line_seen = 0;
136  int num_seen = 0;
137  int start_seen = 0;
138  int end_seen = 0;
139
140  /* ... and their corresponding value. */
141  char *file_string = NULL;
142  int line_num = -1;
143  int how_many = -1;
144  CORE_ADDR low = 0;
145  CORE_ADDR high = 0;
146
147  /* Options processing stuff. */
148  int optind = 0;
149  char *optarg;
150  enum opt
151    {
152      FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT
153    };
154  static struct mi_opt opts[] =
155  {
156    {"f", FILE_OPT, 1},
157    {"l", LINE_OPT, 1},
158    {"n", NUM_OPT, 1},
159    {"s", START_OPT, 1},
160    {"e", END_OPT, 1},
161    0
162  };
163
164  /* Get the options with their arguments. Keep track of what we
165     encountered. */
166  while (1)
167    {
168      int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts,
169			   &optind, &optarg);
170      if (opt < 0)
171	break;
172      switch ((enum opt) opt)
173	{
174	case FILE_OPT:
175	  file_string = xstrdup (optarg);
176	  file_seen = 1;
177	  break;
178	case LINE_OPT:
179	  line_num = atoi (optarg);
180	  line_seen = 1;
181	  break;
182	case NUM_OPT:
183	  how_many = atoi (optarg);
184	  num_seen = 1;
185	  break;
186	case START_OPT:
187	  low = parse_and_eval_address (optarg);
188	  start_seen = 1;
189	  break;
190	case END_OPT:
191	  high = parse_and_eval_address (optarg);
192	  end_seen = 1;
193	  break;
194	}
195    }
196  argv += optind;
197  argc -= optind;
198
199  /* Allow only filename + linenum (with how_many which is not
200     required) OR start_addr + and_addr */
201
202  if (!((line_seen && file_seen && num_seen && !start_seen && !end_seen)
203	|| (line_seen && file_seen && !num_seen && !start_seen && !end_seen)
204      || (!line_seen && !file_seen && !num_seen && start_seen && end_seen)))
205    error ("mi_cmd_disassemble: Usage: ( [-f filename -l linenum [-n howmany]] | [-s startaddr -e endaddr]) [--] mixed_mode.");
206
207  if (argc != 1)
208    error ("mi_cmd_disassemble: Usage: [-f filename -l linenum [-n howmany]] [-s startaddr -e endaddr] [--] mixed_mode.");
209
210  mixed_source_and_assembly = atoi (argv[0]);
211  if ((mixed_source_and_assembly != 0) && (mixed_source_and_assembly != 1))
212    error ("mi_cmd_disassemble: Mixed_mode argument must be 0 or 1.");
213
214  /* We must get the function beginning and end where line_num is
215     contained. */
216
217  if (line_seen && file_seen)
218    {
219      s = lookup_symtab (file_string);
220      if (s == NULL)
221	error ("mi_cmd_disassemble: Invalid filename.");
222      if (!find_line_pc (s, line_num, &start))
223	error ("mi_cmd_disassemble: Invalid line number");
224      if (find_pc_partial_function (start, NULL, &low, &high) == 0)
225	error ("mi_cmd_disassemble: No function contains specified address");
226    }
227
228  if (!di_initialized)
229    {
230      /* We don't add a cleanup for this, because the allocation of
231         the stream is done once only for each gdb run, and we need to
232         keep it around until the end. Hopefully there won't be any
233         errors in the init code below, that make this function bail
234         out. */
235      stb = ui_out_stream_new (uiout);
236      INIT_DISASSEMBLE_INFO_NO_ARCH (di, stb->stream,
237				     (fprintf_ftype) fprintf_unfiltered);
238      di.flavour = bfd_target_unknown_flavour;
239      di.memory_error_func = dis_asm_memory_error;
240      di.print_address_func = dis_asm_print_address;
241      di_initialized = 1;
242    }
243
244  di.mach = TARGET_PRINT_INSN_INFO->mach;
245  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
246    di.endian = BFD_ENDIAN_BIG;
247  else
248    di.endian = BFD_ENDIAN_LITTLE;
249
250  /* If gdb_disassemble_from_exec == -1, then we use the following heuristic to
251     determine whether or not to do disassembly from target memory or from the
252     exec file:
253
254     If we're debugging a local process, read target memory, instead of the
255     exec file.  This makes disassembly of functions in shared libs work
256     correctly.  Also, read target memory if we are debugging native threads.
257
258     Else, we're debugging a remote process, and should disassemble from the
259     exec file for speed.  However, this is no good if the target modifies its
260     code (for relocation, or whatever).
261   */
262
263  if (gdb_disassemble_from_exec == -1)
264    {
265      if (strcmp (target_shortname, "child") == 0
266	  || strcmp (target_shortname, "procfs") == 0
267	  || strcmp (target_shortname, "vxprocess") == 0
268	  || strstr (target_shortname, "-threads") != NULL)
269	gdb_disassemble_from_exec = 0;	/* It's a child process, read inferior mem */
270      else
271	gdb_disassemble_from_exec = 1;	/* It's remote, read the exec file */
272    }
273
274  if (gdb_disassemble_from_exec)
275    di.read_memory_func = gdb_dis_asm_read_memory;
276  else
277    di.read_memory_func = dis_asm_read_memory;
278
279  /* If just doing straight assembly, all we need to do is disassemble
280     everything between low and high.  If doing mixed source/assembly,
281     we've got a totally different path to follow.  */
282
283  if (mixed_source_and_assembly)
284    {
285      /* Come here for mixed source/assembly */
286      /* The idea here is to present a source-O-centric view of a
287         function to the user.  This means that things are presented
288         in source order, with (possibly) out of order assembly
289         immediately following.  */
290      struct symtab *symtab;
291      struct linetable_entry *le;
292      int nlines;
293      int newlines;
294      struct dis_line_entry *mle;
295      struct symtab_and_line sal;
296      int i;
297      int out_of_order;
298      int next_line;
299
300      /* Assume symtab is valid for whole PC range */
301      symtab = find_pc_symtab (low);
302
303      if (!symtab || !symtab->linetable)
304	goto assembly_only;
305
306      /* First, convert the linetable to a bunch of my_line_entry's.  */
307
308      le = symtab->linetable->item;
309      nlines = symtab->linetable->nitems;
310
311      if (nlines <= 0)
312	goto assembly_only;
313
314      mle = (struct dis_line_entry *) alloca (nlines * sizeof (struct dis_line_entry));
315
316      out_of_order = 0;
317
318      /* Copy linetable entries for this function into our data
319         structure, creating end_pc's and setting out_of_order as
320         appropriate.  */
321
322      /* First, skip all the preceding functions.  */
323
324      for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
325
326      /* Now, copy all entries before the end of this function.  */
327
328      newlines = 0;
329      for (; i < nlines - 1 && le[i].pc < high; i++)
330	{
331	  if (le[i].line == le[i + 1].line
332	      && le[i].pc == le[i + 1].pc)
333	    continue;		/* Ignore duplicates */
334
335	  /* Skip any end-of-function markers.  */
336	  if (le[i].line == 0)
337	    continue;
338
339	  mle[newlines].line = le[i].line;
340	  if (le[i].line > le[i + 1].line)
341	    out_of_order = 1;
342	  mle[newlines].start_pc = le[i].pc;
343	  mle[newlines].end_pc = le[i + 1].pc;
344	  newlines++;
345	}
346
347      /* If we're on the last line, and it's part of the function,
348         then we need to get the end pc in a special way.  */
349
350      if (i == nlines - 1
351	  && le[i].pc < high)
352	{
353	  mle[newlines].line = le[i].line;
354	  mle[newlines].start_pc = le[i].pc;
355	  sal = find_pc_line (le[i].pc, 0);
356	  mle[newlines].end_pc = sal.end;
357	  newlines++;
358	}
359
360      /* Now, sort mle by line #s (and, then by addresses within
361         lines). */
362
363      if (out_of_order)
364	qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
365
366      /* Now, for each line entry, emit the specified lines (unless
367         they have been emitted before), followed by the assembly code
368         for that line.  */
369
370      next_line = 0;		/* Force out first line */
371      ui_out_list_begin (uiout, "asm_insns");
372      num_displayed = 0;
373      for (i = 0; i < newlines; i++)
374	{
375	  int close_list = 1;
376	  /* Print out everything from next_line to the current line.  */
377	  if (mle[i].line >= next_line)
378	    {
379	      if (next_line != 0)
380		{
381		  /* Just one line to print. */
382		  if (next_line == mle[i].line)
383		    {
384		      ui_out_tuple_begin (uiout, "src_and_asm_line");
385		      print_source_lines (symtab, next_line, mle[i].line + 1, 0);
386		    }
387		  else
388		    {
389		      /* Several source lines w/o asm instructions associated. */
390		      for (; next_line < mle[i].line; next_line++)
391			{
392			  ui_out_tuple_begin (uiout, "src_and_asm_line");
393			  print_source_lines (symtab, next_line, mle[i].line + 1, 0);
394			  ui_out_list_begin (uiout, "line_asm_insn");
395			  ui_out_list_end (uiout);
396			  ui_out_tuple_end (uiout);
397			}
398		      /* Print the last line and leave list open for
399		         asm instructions to be added. */
400		      ui_out_tuple_begin (uiout, "src_and_asm_line");
401		      print_source_lines (symtab, next_line, mle[i].line + 1, 0);
402		    }
403		}
404	      else
405		{
406		  ui_out_tuple_begin (uiout, "src_and_asm_line");
407		  print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
408		}
409
410	      next_line = mle[i].line + 1;
411	      ui_out_list_begin (uiout, "line_asm_insn");
412	      if (i + 1 < newlines && mle[i + 1].line <= mle[i].line)
413		close_list = 0;
414	    }
415	  for (pc = mle[i].start_pc; pc < mle[i].end_pc;)
416	    {
417	      QUIT;
418	      if (how_many >= 0)
419		{
420		  if (num_displayed >= how_many)
421		    break;
422		  else
423		    num_displayed++;
424		}
425	      ui_out_tuple_begin (uiout, NULL);
426	      ui_out_field_core_addr (uiout, "address", pc);
427
428	      if (!build_address_symbolic (pc, 0, &name, &offset, &filename, &line, &unmapped))
429		{
430		  /* We don't care now about line, filename and
431		     unmapped, but we might in the future. */
432		  ui_out_field_string (uiout, "func-name", name);
433		  ui_out_field_int (uiout, "offset", offset);
434		}
435	      if (filename != NULL)
436		xfree (filename);
437	      if (name != NULL)
438		xfree (name);
439
440	      ui_file_rewind (stb->stream);
441	      pc += (*tm_print_insn) (pc, &di);
442	      ui_out_field_stream (uiout, "inst", stb);
443	      ui_file_rewind (stb->stream);
444	      ui_out_tuple_end (uiout);
445	    }
446	  if (close_list)
447	    {
448	      ui_out_list_end (uiout);
449	      ui_out_tuple_end (uiout);
450	      close_list = 0;
451	    }
452	  if (how_many >= 0)
453	    if (num_displayed >= how_many)
454	      break;
455	}
456      ui_out_list_end (uiout);
457    }
458  else
459    {
460    assembly_only:
461      ui_out_list_begin (uiout, "asm_insns");
462      num_displayed = 0;
463      for (pc = low; pc < high;)
464	{
465	  QUIT;
466	  if (how_many >= 0)
467	    {
468	      if (num_displayed >= how_many)
469		break;
470	      else
471		num_displayed++;
472	    }
473	  ui_out_tuple_begin (uiout, NULL);
474	  ui_out_field_core_addr (uiout, "address", pc);
475
476	  if (!build_address_symbolic (pc, 0, &name, &offset, &filename, &line, &unmapped))
477	    {
478	      /* We don't care now about line, filename and
479	         unmapped. But we might in the future. */
480	      ui_out_field_string (uiout, "func-name", name);
481	      ui_out_field_int (uiout, "offset", offset);
482	    }
483	  if (filename != NULL)
484	    xfree (filename);
485	  if (name != NULL)
486	    xfree (name);
487
488	  ui_file_rewind (stb->stream);
489	  pc += (*tm_print_insn) (pc, &di);
490	  ui_out_field_stream (uiout, "inst", stb);
491	  ui_file_rewind (stb->stream);
492	  ui_out_tuple_end (uiout);
493	}
494      ui_out_list_end (uiout);
495    }
496  gdb_flush (gdb_stdout);
497
498  return MI_CMD_DONE;
499}
500