1130803Smarcel/* Disassemble support for GDB.
2130803Smarcel
3130803Smarcel   Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.  */
21130803Smarcel
22130803Smarcel#include "defs.h"
23130803Smarcel#include "target.h"
24130803Smarcel#include "value.h"
25130803Smarcel#include "ui-out.h"
26130803Smarcel#include "gdb_string.h"
27130803Smarcel#include "disasm.h"
28130803Smarcel#include "gdbcore.h"
29130803Smarcel#include "dis-asm.h"
30130803Smarcel
31130803Smarcel/* Disassemble functions.
32130803Smarcel   FIXME: We should get rid of all the duplicate code in gdb that does
33130803Smarcel   the same thing: disassemble_command() and the gdbtk variation. */
34130803Smarcel
35130803Smarcel/* This Structure is used to store line number information.
36130803Smarcel   We need a different sort of line table from the normal one cuz we can't
37130803Smarcel   depend upon implicit line-end pc's for lines to do the
38130803Smarcel   reordering in this function.  */
39130803Smarcel
40130803Smarcelstruct dis_line_entry
41130803Smarcel{
42130803Smarcel  int line;
43130803Smarcel  CORE_ADDR start_pc;
44130803Smarcel  CORE_ADDR end_pc;
45130803Smarcel};
46130803Smarcel
47130803Smarcel/* Like target_read_memory, but slightly different parameters.  */
48130803Smarcelstatic int
49130803Smarceldis_asm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int len,
50130803Smarcel		     struct disassemble_info *info)
51130803Smarcel{
52130803Smarcel  return target_read_memory (memaddr, (char *) myaddr, len);
53130803Smarcel}
54130803Smarcel
55130803Smarcel/* Like memory_error with slightly different parameters.  */
56130803Smarcelstatic void
57130803Smarceldis_asm_memory_error (int status, bfd_vma memaddr,
58130803Smarcel		      struct disassemble_info *info)
59130803Smarcel{
60130803Smarcel  memory_error (status, memaddr);
61130803Smarcel}
62130803Smarcel
63130803Smarcel/* Like print_address with slightly different parameters.  */
64130803Smarcelstatic void
65130803Smarceldis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
66130803Smarcel{
67130803Smarcel  print_address (addr, info->stream);
68130803Smarcel}
69130803Smarcel
70130803Smarcelstatic int
71130803Smarcelcompare_lines (const void *mle1p, const void *mle2p)
72130803Smarcel{
73130803Smarcel  struct dis_line_entry *mle1, *mle2;
74130803Smarcel  int val;
75130803Smarcel
76130803Smarcel  mle1 = (struct dis_line_entry *) mle1p;
77130803Smarcel  mle2 = (struct dis_line_entry *) mle2p;
78130803Smarcel
79130803Smarcel  val = mle1->line - mle2->line;
80130803Smarcel
81130803Smarcel  if (val != 0)
82130803Smarcel    return val;
83130803Smarcel
84130803Smarcel  return mle1->start_pc - mle2->start_pc;
85130803Smarcel}
86130803Smarcel
87130803Smarcelstatic int
88130803Smarceldump_insns (struct ui_out *uiout, struct disassemble_info * di,
89130803Smarcel	    CORE_ADDR low, CORE_ADDR high,
90130803Smarcel	    int how_many, struct ui_stream *stb)
91130803Smarcel{
92130803Smarcel  int num_displayed = 0;
93130803Smarcel  CORE_ADDR pc;
94130803Smarcel
95130803Smarcel  /* parts of the symbolic representation of the address */
96130803Smarcel  int unmapped;
97130803Smarcel  int offset;
98130803Smarcel  int line;
99130803Smarcel  struct cleanup *ui_out_chain;
100130803Smarcel
101130803Smarcel  for (pc = low; pc < high;)
102130803Smarcel    {
103130803Smarcel      char *filename = NULL;
104130803Smarcel      char *name = NULL;
105130803Smarcel
106130803Smarcel      QUIT;
107130803Smarcel      if (how_many >= 0)
108130803Smarcel	{
109130803Smarcel	  if (num_displayed >= how_many)
110130803Smarcel	    break;
111130803Smarcel	  else
112130803Smarcel	    num_displayed++;
113130803Smarcel	}
114130803Smarcel      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
115130803Smarcel      ui_out_field_core_addr (uiout, "address", pc);
116130803Smarcel
117130803Smarcel      if (!build_address_symbolic (pc, 0, &name, &offset, &filename,
118130803Smarcel				   &line, &unmapped))
119130803Smarcel	{
120130803Smarcel	  /* We don't care now about line, filename and
121130803Smarcel	     unmapped. But we might in the future. */
122130803Smarcel	  ui_out_text (uiout, " <");
123130803Smarcel	  ui_out_field_string (uiout, "func-name", name);
124130803Smarcel	  ui_out_text (uiout, "+");
125130803Smarcel	  ui_out_field_int (uiout, "offset", offset);
126130803Smarcel	  ui_out_text (uiout, ">:\t");
127130803Smarcel	}
128130803Smarcel      else
129130803Smarcel	ui_out_text (uiout, ":\t");
130130803Smarcel
131130803Smarcel      if (filename != NULL)
132130803Smarcel	xfree (filename);
133130803Smarcel      if (name != NULL)
134130803Smarcel	xfree (name);
135130803Smarcel
136130803Smarcel      ui_file_rewind (stb->stream);
137130803Smarcel      pc += TARGET_PRINT_INSN (pc, di);
138130803Smarcel      ui_out_field_stream (uiout, "inst", stb);
139130803Smarcel      ui_file_rewind (stb->stream);
140130803Smarcel      do_cleanups (ui_out_chain);
141130803Smarcel      ui_out_text (uiout, "\n");
142130803Smarcel    }
143130803Smarcel  return num_displayed;
144130803Smarcel}
145130803Smarcel
146130803Smarcel/* The idea here is to present a source-O-centric view of a
147130803Smarcel   function to the user.  This means that things are presented
148130803Smarcel   in source order, with (possibly) out of order assembly
149130803Smarcel   immediately following.  */
150130803Smarcelstatic void
151130803Smarceldo_mixed_source_and_assembly (struct ui_out *uiout,
152130803Smarcel			      struct disassemble_info *di, int nlines,
153130803Smarcel			      struct linetable_entry *le,
154130803Smarcel			      CORE_ADDR low, CORE_ADDR high,
155130803Smarcel			      struct symtab *symtab,
156130803Smarcel			      int how_many, struct ui_stream *stb)
157130803Smarcel{
158130803Smarcel  int newlines = 0;
159130803Smarcel  struct dis_line_entry *mle;
160130803Smarcel  struct symtab_and_line sal;
161130803Smarcel  int i;
162130803Smarcel  int out_of_order = 0;
163130803Smarcel  int next_line = 0;
164130803Smarcel  CORE_ADDR pc;
165130803Smarcel  int num_displayed = 0;
166130803Smarcel  struct cleanup *ui_out_chain;
167130803Smarcel  struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
168130803Smarcel  struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
169130803Smarcel
170130803Smarcel  mle = (struct dis_line_entry *) alloca (nlines
171130803Smarcel					  * sizeof (struct dis_line_entry));
172130803Smarcel
173130803Smarcel  /* Copy linetable entries for this function into our data
174130803Smarcel     structure, creating end_pc's and setting out_of_order as
175130803Smarcel     appropriate.  */
176130803Smarcel
177130803Smarcel  /* First, skip all the preceding functions.  */
178130803Smarcel
179130803Smarcel  for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
180130803Smarcel
181130803Smarcel  /* Now, copy all entries before the end of this function.  */
182130803Smarcel
183130803Smarcel  for (; i < nlines - 1 && le[i].pc < high; i++)
184130803Smarcel    {
185130803Smarcel      if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
186130803Smarcel	continue;		/* Ignore duplicates */
187130803Smarcel
188130803Smarcel      /* Skip any end-of-function markers.  */
189130803Smarcel      if (le[i].line == 0)
190130803Smarcel	continue;
191130803Smarcel
192130803Smarcel      mle[newlines].line = le[i].line;
193130803Smarcel      if (le[i].line > le[i + 1].line)
194130803Smarcel	out_of_order = 1;
195130803Smarcel      mle[newlines].start_pc = le[i].pc;
196130803Smarcel      mle[newlines].end_pc = le[i + 1].pc;
197130803Smarcel      newlines++;
198130803Smarcel    }
199130803Smarcel
200130803Smarcel  /* If we're on the last line, and it's part of the function,
201130803Smarcel     then we need to get the end pc in a special way.  */
202130803Smarcel
203130803Smarcel  if (i == nlines - 1 && le[i].pc < high)
204130803Smarcel    {
205130803Smarcel      mle[newlines].line = le[i].line;
206130803Smarcel      mle[newlines].start_pc = le[i].pc;
207130803Smarcel      sal = find_pc_line (le[i].pc, 0);
208130803Smarcel      mle[newlines].end_pc = sal.end;
209130803Smarcel      newlines++;
210130803Smarcel    }
211130803Smarcel
212130803Smarcel  /* Now, sort mle by line #s (and, then by addresses within
213130803Smarcel     lines). */
214130803Smarcel
215130803Smarcel  if (out_of_order)
216130803Smarcel    qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
217130803Smarcel
218130803Smarcel  /* Now, for each line entry, emit the specified lines (unless
219130803Smarcel     they have been emitted before), followed by the assembly code
220130803Smarcel     for that line.  */
221130803Smarcel
222130803Smarcel  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
223130803Smarcel
224130803Smarcel  for (i = 0; i < newlines; i++)
225130803Smarcel    {
226130803Smarcel      /* Print out everything from next_line to the current line.  */
227130803Smarcel      if (mle[i].line >= next_line)
228130803Smarcel	{
229130803Smarcel	  if (next_line != 0)
230130803Smarcel	    {
231130803Smarcel	      /* Just one line to print. */
232130803Smarcel	      if (next_line == mle[i].line)
233130803Smarcel		{
234130803Smarcel		  ui_out_tuple_chain
235130803Smarcel		    = make_cleanup_ui_out_tuple_begin_end (uiout,
236130803Smarcel							   "src_and_asm_line");
237130803Smarcel		  print_source_lines (symtab, next_line, mle[i].line + 1, 0);
238130803Smarcel		}
239130803Smarcel	      else
240130803Smarcel		{
241130803Smarcel		  /* Several source lines w/o asm instructions associated. */
242130803Smarcel		  for (; next_line < mle[i].line; next_line++)
243130803Smarcel		    {
244130803Smarcel		      struct cleanup *ui_out_list_chain_line;
245130803Smarcel		      struct cleanup *ui_out_tuple_chain_line;
246130803Smarcel
247130803Smarcel		      ui_out_tuple_chain_line
248130803Smarcel			= make_cleanup_ui_out_tuple_begin_end (uiout,
249130803Smarcel							       "src_and_asm_line");
250130803Smarcel		      print_source_lines (symtab, next_line, next_line + 1,
251130803Smarcel					  0);
252130803Smarcel		      ui_out_list_chain_line
253130803Smarcel			= make_cleanup_ui_out_list_begin_end (uiout,
254130803Smarcel							      "line_asm_insn");
255130803Smarcel		      do_cleanups (ui_out_list_chain_line);
256130803Smarcel		      do_cleanups (ui_out_tuple_chain_line);
257130803Smarcel		    }
258130803Smarcel		  /* Print the last line and leave list open for
259130803Smarcel		     asm instructions to be added. */
260130803Smarcel		  ui_out_tuple_chain
261130803Smarcel		    = make_cleanup_ui_out_tuple_begin_end (uiout,
262130803Smarcel							   "src_and_asm_line");
263130803Smarcel		  print_source_lines (symtab, next_line, mle[i].line + 1, 0);
264130803Smarcel		}
265130803Smarcel	    }
266130803Smarcel	  else
267130803Smarcel	    {
268130803Smarcel	      ui_out_tuple_chain
269130803Smarcel		= make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
270130803Smarcel	      print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
271130803Smarcel	    }
272130803Smarcel
273130803Smarcel	  next_line = mle[i].line + 1;
274130803Smarcel	  ui_out_list_chain
275130803Smarcel	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
276130803Smarcel	}
277130803Smarcel
278130803Smarcel      num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
279130803Smarcel				   how_many, stb);
280130803Smarcel
281130803Smarcel      /* When we've reached the end of the mle array, or we've seen the last
282130803Smarcel         assembly range for this source line, close out the list/tuple.  */
283130803Smarcel      if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
284130803Smarcel	{
285130803Smarcel	  do_cleanups (ui_out_list_chain);
286130803Smarcel	  do_cleanups (ui_out_tuple_chain);
287130803Smarcel	  ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
288130803Smarcel	  ui_out_list_chain = make_cleanup (null_cleanup, 0);
289130803Smarcel	  ui_out_text (uiout, "\n");
290130803Smarcel	}
291130803Smarcel      if (how_many >= 0 && num_displayed >= how_many)
292130803Smarcel	break;
293130803Smarcel    }
294130803Smarcel  do_cleanups (ui_out_chain);
295130803Smarcel}
296130803Smarcel
297130803Smarcel
298130803Smarcelstatic void
299130803Smarceldo_assembly_only (struct ui_out *uiout, struct disassemble_info * di,
300130803Smarcel		  CORE_ADDR low, CORE_ADDR high,
301130803Smarcel		  int how_many, struct ui_stream *stb)
302130803Smarcel{
303130803Smarcel  int num_displayed = 0;
304130803Smarcel  struct cleanup *ui_out_chain;
305130803Smarcel
306130803Smarcel  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
307130803Smarcel
308130803Smarcel  num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
309130803Smarcel
310130803Smarcel  do_cleanups (ui_out_chain);
311130803Smarcel}
312130803Smarcel
313130803Smarcel/* Initialize the disassemble info struct ready for the specified
314130803Smarcel   stream.  */
315130803Smarcel
316130803Smarcelstatic int
317130803Smarcelfprintf_disasm (void *stream, const char *format, ...)
318130803Smarcel{
319130803Smarcel  va_list args;
320130803Smarcel  va_start (args, format);
321130803Smarcel  vfprintf_filtered (stream, format, args);
322130803Smarcel  va_end (args);
323130803Smarcel  /* Something non -ve.  */
324130803Smarcel  return 0;
325130803Smarcel}
326130803Smarcel
327130803Smarcelstatic struct disassemble_info
328130803Smarcelgdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
329130803Smarcel{
330130803Smarcel  struct disassemble_info di;
331130803Smarcel  init_disassemble_info (&di, file, fprintf_disasm);
332130803Smarcel  di.flavour = bfd_target_unknown_flavour;
333130803Smarcel  di.memory_error_func = dis_asm_memory_error;
334130803Smarcel  di.print_address_func = dis_asm_print_address;
335130803Smarcel  /* NOTE: cagney/2003-04-28: The original code, from the old Insight
336130803Smarcel     disassembler had a local optomization here.  By default it would
337130803Smarcel     access the executable file, instead of the target memory (there
338130803Smarcel     was a growing list of exceptions though).  Unfortunately, the
339130803Smarcel     heuristic was flawed.  Commands like "disassemble &variable"
340130803Smarcel     didn't work as they relied on the access going to the target.
341130803Smarcel     Further, it has been supperseeded by trust-read-only-sections
342130803Smarcel     (although that should be superseeded by target_trust..._p()).  */
343130803Smarcel  di.read_memory_func = dis_asm_read_memory;
344130803Smarcel  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
345130803Smarcel  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
346130803Smarcel  di.endian = gdbarch_byte_order (gdbarch);
347130803Smarcel  return di;
348130803Smarcel}
349130803Smarcel
350130803Smarcelvoid
351130803Smarcelgdb_disassembly (struct ui_out *uiout,
352130803Smarcel		char *file_string,
353130803Smarcel		int line_num,
354130803Smarcel		int mixed_source_and_assembly,
355130803Smarcel		int how_many, CORE_ADDR low, CORE_ADDR high)
356130803Smarcel{
357130803Smarcel  struct ui_stream *stb = ui_out_stream_new (uiout);
358130803Smarcel  struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb);
359130803Smarcel  struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream);
360130803Smarcel  /* To collect the instruction outputted from opcodes. */
361130803Smarcel  struct symtab *symtab = NULL;
362130803Smarcel  struct linetable_entry *le = NULL;
363130803Smarcel  int nlines = -1;
364130803Smarcel
365130803Smarcel  /* Assume symtab is valid for whole PC range */
366130803Smarcel  symtab = find_pc_symtab (low);
367130803Smarcel
368130803Smarcel  if (symtab != NULL && symtab->linetable != NULL)
369130803Smarcel    {
370130803Smarcel      /* Convert the linetable to a bunch of my_line_entry's.  */
371130803Smarcel      le = symtab->linetable->item;
372130803Smarcel      nlines = symtab->linetable->nitems;
373130803Smarcel    }
374130803Smarcel
375130803Smarcel  if (!mixed_source_and_assembly || nlines <= 0
376130803Smarcel      || symtab == NULL || symtab->linetable == NULL)
377130803Smarcel    do_assembly_only (uiout, &di, low, high, how_many, stb);
378130803Smarcel
379130803Smarcel  else if (mixed_source_and_assembly)
380130803Smarcel    do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
381130803Smarcel				  high, symtab, how_many, stb);
382130803Smarcel
383130803Smarcel  do_cleanups (cleanups);
384130803Smarcel  gdb_flush (gdb_stdout);
385130803Smarcel}
386130803Smarcel
387130803Smarcel/* Print the instruction at address MEMADDR in debugged memory,
388130803Smarcel   on STREAM.  Returns length of the instruction, in bytes.  */
389130803Smarcel
390130803Smarcelint
391130803Smarcelgdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream)
392130803Smarcel{
393130803Smarcel  struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stream);
394130803Smarcel  return TARGET_PRINT_INSN (memaddr, &di);
395130803Smarcel}
396