1187767Sluigi/* Disassemble support for GDB.
2187767Sluigi
3187767Sluigi   Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4187767Sluigi
5187767Sluigi   This file is part of GDB.
6187767Sluigi
7187767Sluigi   This program is free software; you can redistribute it and/or modify
8187767Sluigi   it under the terms of the GNU General Public License as published by
9187767Sluigi   the Free Software Foundation; either version 2 of the License, or
10187767Sluigi   (at your option) any later version.
11187767Sluigi
12187767Sluigi   This program is distributed in the hope that it will be useful,
13187767Sluigi   but WITHOUT ANY WARRANTY; without even the implied warranty of
14187767Sluigi   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15187767Sluigi   GNU General Public License for more details.
16187767Sluigi
17187767Sluigi   You should have received a copy of the GNU General Public License
18187767Sluigi   along with this program; if not, write to the Free Software
19187767Sluigi   Foundation, Inc., 59 Temple Place - Suite 330,
20187767Sluigi   Boston, MA 02111-1307, USA.  */
21187767Sluigi
22187767Sluigi#include "defs.h"
23187767Sluigi#include "target.h"
24187767Sluigi#include "value.h"
25187767Sluigi#include "ui-out.h"
26187767Sluigi#include "gdb_string.h"
27187767Sluigi#include "disasm.h"
28187767Sluigi#include "gdbcore.h"
29187767Sluigi#include "dis-asm.h"
30187767Sluigi
31187767Sluigi/* Disassemble functions.
32187767Sluigi   FIXME: We should get rid of all the duplicate code in gdb that does
33187767Sluigi   the same thing: disassemble_command() and the gdbtk variation. */
34187767Sluigi
35187767Sluigi/* This Structure is used to store line number information.
36187767Sluigi   We need a different sort of line table from the normal one cuz we can't
37187767Sluigi   depend upon implicit line-end pc's for lines to do the
38204591Sluigi   reordering in this function.  */
39187767Sluigi
40187767Sluigistruct dis_line_entry
41187767Sluigi{
42187767Sluigi  int line;
43187767Sluigi  CORE_ADDR start_pc;
44187767Sluigi  CORE_ADDR end_pc;
45187767Sluigi};
46187767Sluigi
47187767Sluigi/* Like target_read_memory, but slightly different parameters.  */
48187767Sluigistatic int
49187767Sluigidis_asm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int len,
50187767Sluigi		     struct disassemble_info *info)
51187767Sluigi{
52187767Sluigi  return target_read_memory (memaddr, (char *) myaddr, len);
53187767Sluigi}
54187767Sluigi
55187767Sluigi/* Like memory_error with slightly different parameters.  */
56187767Sluigistatic void
57187767Sluigidis_asm_memory_error (int status, bfd_vma memaddr,
58187767Sluigi		      struct disassemble_info *info)
59187767Sluigi{
60187767Sluigi  memory_error (status, memaddr);
61187767Sluigi}
62187767Sluigi
63187767Sluigi/* Like print_address with slightly different parameters.  */
64187767Sluigistatic void
65187767Sluigidis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
66187767Sluigi{
67187767Sluigi  print_address (addr, info->stream);
68187767Sluigi}
69187767Sluigi
70187767Sluigistatic int
71187767Sluigicompare_lines (const void *mle1p, const void *mle2p)
72187767Sluigi{
73187767Sluigi  struct dis_line_entry *mle1, *mle2;
74270424Smelifaro  int val;
75270424Smelifaro
76187769Sluigi  mle1 = (struct dis_line_entry *) mle1p;
77187769Sluigi  mle2 = (struct dis_line_entry *) mle2p;
78187769Sluigi
79187769Sluigi  val = mle1->line - mle2->line;
80187769Sluigi
81187769Sluigi  if (val != 0)
82187769Sluigi    return val;
83187769Sluigi
84187769Sluigi  return mle1->start_pc - mle2->start_pc;
85187769Sluigi}
86298016Sae
87187769Sluigistatic int
88204591Sluigidump_insns (struct ui_out *uiout, struct disassemble_info * di,
89187769Sluigi	    CORE_ADDR low, CORE_ADDR high,
90204591Sluigi	    int how_many, struct ui_stream *stb)
91204591Sluigi{
92187769Sluigi  int num_displayed = 0;
93187769Sluigi  CORE_ADDR pc;
94187769Sluigi
95187769Sluigi  /* parts of the symbolic representation of the address */
96187769Sluigi  int unmapped;
97187769Sluigi  int offset;
98187769Sluigi  int line;
99187769Sluigi  struct cleanup *ui_out_chain;
100187769Sluigi
101187769Sluigi  for (pc = low; pc < high;)
102187769Sluigi    {
103187769Sluigi      char *filename = NULL;
104190633Spiso      char *name = NULL;
105223666Sae
106223666Sae      QUIT;
107187769Sluigi      if (how_many >= 0)
108187769Sluigi	{
109187769Sluigi	  if (num_displayed >= how_many)
110187769Sluigi	    break;
111187769Sluigi	  else
112187769Sluigi	    num_displayed++;
113187769Sluigi	}
114187769Sluigi      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
115187769Sluigi      ui_out_field_core_addr (uiout, "address", pc);
116187769Sluigi
117187769Sluigi      if (!build_address_symbolic (pc, 0, &name, &offset, &filename,
118187769Sluigi				   &line, &unmapped))
119187769Sluigi	{
120187769Sluigi	  /* We don't care now about line, filename and
121187769Sluigi	     unmapped. But we might in the future. */
122187769Sluigi	  ui_out_text (uiout, " <");
123187769Sluigi	  ui_out_field_string (uiout, "func-name", name);
124187769Sluigi	  ui_out_text (uiout, "+");
125187769Sluigi	  ui_out_field_int (uiout, "offset", offset);
126187769Sluigi	  ui_out_text (uiout, ">:\t");
127187769Sluigi	}
128187769Sluigi      else
129187769Sluigi	ui_out_text (uiout, ":\t");
130187769Sluigi
131187769Sluigi      if (filename != NULL)
132187769Sluigi	xfree (filename);
133205169Sluigi      if (name != NULL)
134187769Sluigi	xfree (name);
135187769Sluigi
136187769Sluigi      ui_file_rewind (stb->stream);
137187769Sluigi      pc += TARGET_PRINT_INSN (pc, di);
138187769Sluigi      ui_out_field_stream (uiout, "inst", stb);
139187769Sluigi      ui_file_rewind (stb->stream);
140187769Sluigi      do_cleanups (ui_out_chain);
141187769Sluigi      ui_out_text (uiout, "\n");
142187769Sluigi    }
143187769Sluigi  return num_displayed;
144187769Sluigi}
145187769Sluigi
146187769Sluigi/* The idea here is to present a source-O-centric view of a
147187769Sluigi   function to the user.  This means that things are presented
148187769Sluigi   in source order, with (possibly) out of order assembly
149187769Sluigi   immediately following.  */
150187769Sluigistatic void
151187769Sluigido_mixed_source_and_assembly (struct ui_out *uiout,
152187769Sluigi			      struct disassemble_info *di, int nlines,
153187769Sluigi			      struct linetable_entry *le,
154187769Sluigi			      CORE_ADDR low, CORE_ADDR high,
155187769Sluigi			      struct symtab *symtab,
156187769Sluigi			      int how_many, struct ui_stream *stb)
157187769Sluigi{
158187769Sluigi  int newlines = 0;
159187769Sluigi  struct dis_line_entry *mle;
160187769Sluigi  struct symtab_and_line sal;
161187769Sluigi  int i;
162187769Sluigi  int out_of_order = 0;
163204591Sluigi  int next_line = 0;
164204591Sluigi  CORE_ADDR pc;
165187769Sluigi  int num_displayed = 0;
166187769Sluigi  struct cleanup *ui_out_chain;
167204591Sluigi  struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
168194930Soleg  struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
169187769Sluigi
170187769Sluigi  mle = (struct dis_line_entry *) alloca (nlines
171266941Shiren					  * sizeof (struct dis_line_entry));
172187769Sluigi
173187769Sluigi  /* Copy linetable entries for this function into our data
174300779Struckman     structure, creating end_pc's and setting out_of_order as
175300779Struckman     appropriate.  */
176300779Struckman
177300779Struckman  /* First, skip all the preceding functions.  */
178300779Struckman
179300779Struckman  for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
180300779Struckman
181300779Struckman  /* Now, copy all entries before the end of this function.  */
182300779Struckman
183300779Struckman  for (; i < nlines - 1 && le[i].pc < high; i++)
184300779Struckman    {
185300779Struckman      if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
186300779Struckman	continue;		/* Ignore duplicates */
187300779Struckman
188300779Struckman      /* Skip any end-of-function markers.  */
189300779Struckman      if (le[i].line == 0)
190300779Struckman	continue;
191300779Struckman
192300779Struckman      mle[newlines].line = le[i].line;
193300779Struckman      if (le[i].line > le[i + 1].line)
194300779Struckman	out_of_order = 1;
195300779Struckman      mle[newlines].start_pc = le[i].pc;
196300779Struckman      mle[newlines].end_pc = le[i + 1].pc;
197300779Struckman      newlines++;
198300779Struckman    }
199204591Sluigi
200187769Sluigi  /* If we're on the last line, and it's part of the function,
201204591Sluigi     then we need to get the end pc in a special way.  */
202204591Sluigi
203204591Sluigi  if (i == nlines - 1 && le[i].pc < high)
204204591Sluigi    {
205204591Sluigi      mle[newlines].line = le[i].line;
206187769Sluigi      mle[newlines].start_pc = le[i].pc;
207187769Sluigi      sal = find_pc_line (le[i].pc, 0);
208187769Sluigi      mle[newlines].end_pc = sal.end;
209187769Sluigi      newlines++;
210187769Sluigi    }
211187769Sluigi
212223080Sae  /* Now, sort mle by line #s (and, then by addresses within
213187769Sluigi     lines). */
214187769Sluigi
215187769Sluigi  if (out_of_order)
216187769Sluigi    qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
217187769Sluigi
218220804Sglebius  /* Now, for each line entry, emit the specified lines (unless
219187769Sluigi     they have been emitted before), followed by the assembly code
220187769Sluigi     for that line.  */
221187769Sluigi
222187769Sluigi  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
223187769Sluigi
224187769Sluigi  for (i = 0; i < newlines; i++)
225187769Sluigi    {
226187769Sluigi      /* Print out everything from next_line to the current line.  */
227187769Sluigi      if (mle[i].line >= next_line)
228187769Sluigi	{
229187769Sluigi	  if (next_line != 0)
230187769Sluigi	    {
231187769Sluigi	      /* Just one line to print. */
232187769Sluigi	      if (next_line == mle[i].line)
233200567Sluigi		{
234215179Sluigi		  ui_out_tuple_chain
235248552Smelifaro		    = make_cleanup_ui_out_tuple_begin_end (uiout,
236272840Smelifaro							   "src_and_asm_line");
237272840Smelifaro		  print_source_lines (symtab, next_line, mle[i].line + 1, 0);
238272840Smelifaro		}
239272840Smelifaro	      else
240272840Smelifaro		{
241272840Smelifaro		  /* Several source lines w/o asm instructions associated. */
242272840Smelifaro		  for (; next_line < mle[i].line; next_line++)
243272840Smelifaro		    {
244272840Smelifaro		      struct cleanup *ui_out_list_chain_line;
245272840Smelifaro		      struct cleanup *ui_out_tuple_chain_line;
246272840Smelifaro
247272840Smelifaro		      ui_out_tuple_chain_line
248272840Smelifaro			= make_cleanup_ui_out_tuple_begin_end (uiout,
249272840Smelifaro							       "src_and_asm_line");
250272840Smelifaro		      print_source_lines (symtab, next_line, next_line + 1,
251272840Smelifaro					  0);
252272840Smelifaro		      ui_out_list_chain_line
253272840Smelifaro			= make_cleanup_ui_out_list_begin_end (uiout,
254272840Smelifaro							      "line_asm_insn");
255272840Smelifaro		      do_cleanups (ui_out_list_chain_line);
256290330Sae		      do_cleanups (ui_out_tuple_chain_line);
257187769Sluigi		    }
258272840Smelifaro		  /* Print the last line and leave list open for
259187767Sluigi		     asm instructions to be added. */
260187767Sluigi		  ui_out_tuple_chain
261187767Sluigi		    = make_cleanup_ui_out_tuple_begin_end (uiout,
262187767Sluigi							   "src_and_asm_line");
263204591Sluigi		  print_source_lines (symtab, next_line, mle[i].line + 1, 0);
264204591Sluigi		}
265187767Sluigi	    }
266270424Smelifaro	  else
267270424Smelifaro	    {
268270424Smelifaro	      ui_out_tuple_chain
269270424Smelifaro		= make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
270270424Smelifaro	      print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
271270424Smelifaro	    }
272270424Smelifaro
273187787Sluigi	  next_line = mle[i].line + 1;
274270424Smelifaro	  ui_out_list_chain
275270424Smelifaro	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
276270424Smelifaro	}
277270424Smelifaro
278270424Smelifaro      num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
279270424Smelifaro				   how_many, stb);
280187767Sluigi
281187767Sluigi      /* When we've reached the end of the mle array, or we've seen the last
282187767Sluigi         assembly range for this source line, close out the list/tuple.  */
283187767Sluigi      if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
284187770Sluigi	{
285187767Sluigi	  do_cleanups (ui_out_list_chain);
286187769Sluigi	  do_cleanups (ui_out_tuple_chain);
287272840Smelifaro	  ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
288187767Sluigi	  ui_out_list_chain = make_cleanup (null_cleanup, 0);
289187770Sluigi	  ui_out_text (uiout, "\n");
290298016Sae	}
291298016Sae      if (how_many >= 0 && num_displayed >= how_many)
292298016Sae	break;
293187770Sluigi    }
294272840Smelifaro  do_cleanups (ui_out_chain);
295272840Smelifaro}
296272840Smelifaro
297272840Smelifaro
298272840Smelifarostatic void
299187770Sluigido_assembly_only (struct ui_out *uiout, struct disassemble_info * di,
300272840Smelifaro		  CORE_ADDR low, CORE_ADDR high,
301187769Sluigi		  int how_many, struct ui_stream *stb)
302272840Smelifaro{
303272840Smelifaro  int num_displayed = 0;
304187769Sluigi  struct cleanup *ui_out_chain;
305187769Sluigi
306187769Sluigi  ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
307187770Sluigi
308187769Sluigi  num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
309187819Sluigi
310187819Sluigi  do_cleanups (ui_out_chain);
311187819Sluigi}
312187819Sluigi
313187819Sluigi/* Initialize the disassemble info struct ready for the specified
314187819Sluigi   stream.  */
315187819Sluigi
316187819Sluigistatic int
317187819Sluigifprintf_disasm (void *stream, const char *format, ...)
318187983Sluigi{
319187819Sluigi  va_list args;
320187819Sluigi  va_start (args, format);
321187819Sluigi  vfprintf_filtered (stream, format, args);
322187769Sluigi  va_end (args);
323187767Sluigi  /* Something non -ve.  */
324187767Sluigi  return 0;
325187767Sluigi}
326187767Sluigi
327187767Sluigistatic struct disassemble_info
328187767Sluigigdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
329187767Sluigi{
330187770Sluigi  struct disassemble_info di;
331204591Sluigi  init_disassemble_info (&di, file, fprintf_disasm);
332187767Sluigi  di.flavour = bfd_target_unknown_flavour;
333187767Sluigi  di.memory_error_func = dis_asm_memory_error;
334187767Sluigi  di.print_address_func = dis_asm_print_address;
335204591Sluigi  /* NOTE: cagney/2003-04-28: The original code, from the old Insight
336187767Sluigi     disassembler had a local optomization here.  By default it would
337204591Sluigi     access the executable file, instead of the target memory (there
338204591Sluigi     was a growing list of exceptions though).  Unfortunately, the
339187767Sluigi     heuristic was flawed.  Commands like "disassemble &variable"
340187767Sluigi     didn't work as they relied on the access going to the target.
341187767Sluigi     Further, it has been supperseeded by trust-read-only-sections
342272840Smelifaro     (although that should be superseeded by target_trust..._p()).  */
343298016Sae  di.read_memory_func = dis_asm_read_memory;
344187767Sluigi  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
345261797Sglebius  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
346187983Sluigi  di.endian = gdbarch_byte_order (gdbarch);
347187983Sluigi  return di;
348187983Sluigi}
349270424Smelifaro
350261797Sglebiusvoid
351261797Sglebiusgdb_disassembly (struct ui_out *uiout,
352261797Sglebius		char *file_string,
353187983Sluigi		int line_num,
354187770Sluigi		int mixed_source_and_assembly,
355204591Sluigi		int how_many, CORE_ADDR low, CORE_ADDR high)
356204591Sluigi{
357187769Sluigi  struct ui_stream *stb = ui_out_stream_new (uiout);
358187769Sluigi  struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb);
359187770Sluigi  struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream);
360297981Sae  /* To collect the instruction outputted from opcodes. */
361270424Smelifaro  struct symtab *symtab = NULL;
362270424Smelifaro  struct linetable_entry *le = NULL;
363270424Smelifaro  int nlines = -1;
364270424Smelifaro
365187770Sluigi  /* Assume symtab is valid for whole PC range */
366247712Smelifaro  symtab = find_pc_symtab (low);
367247712Smelifaro
368187770Sluigi  if (symtab != NULL && symtab->linetable != NULL)
369247712Smelifaro    {
370187770Sluigi      /* Convert the linetable to a bunch of my_line_entry's.  */
371247712Smelifaro      le = symtab->linetable->item;
372187819Sluigi      nlines = symtab->linetable->nitems;
373272840Smelifaro    }
374302979Sae
375302979Sae  if (!mixed_source_and_assembly || nlines <= 0
376302979Sae      || symtab == NULL || symtab->linetable == NULL)
377272840Smelifaro    do_assembly_only (uiout, &di, low, high, how_many, stb);
378272840Smelifaro
379298016Sae  else if (mixed_source_and_assembly)
380272840Smelifaro    do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
381272840Smelifaro				  high, symtab, how_many, stb);
382272840Smelifaro
383  do_cleanups (cleanups);
384  gdb_flush (gdb_stdout);
385}
386
387/* Print the instruction at address MEMADDR in debugged memory,
388   on STREAM.  Returns length of the instruction, in bytes.  */
389
390int
391gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream)
392{
393  struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stream);
394  return TARGET_PRINT_INSN (memaddr, &di);
395}
396