xref: /dflybsd-src/contrib/gdb-7/gdb/disasm.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Disassemble support for GDB.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2000-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "target.h"
225796c8dcSSimon Schubert #include "value.h"
235796c8dcSSimon Schubert #include "ui-out.h"
245796c8dcSSimon Schubert #include "gdb_string.h"
255796c8dcSSimon Schubert #include "disasm.h"
265796c8dcSSimon Schubert #include "gdbcore.h"
275796c8dcSSimon Schubert #include "dis-asm.h"
285796c8dcSSimon Schubert 
295796c8dcSSimon Schubert /* Disassemble functions.
305796c8dcSSimon Schubert    FIXME: We should get rid of all the duplicate code in gdb that does
315796c8dcSSimon Schubert    the same thing: disassemble_command() and the gdbtk variation.  */
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert /* This Structure is used to store line number information.
345796c8dcSSimon Schubert    We need a different sort of line table from the normal one cuz we can't
355796c8dcSSimon Schubert    depend upon implicit line-end pc's for lines to do the
365796c8dcSSimon Schubert    reordering in this function.  */
375796c8dcSSimon Schubert 
385796c8dcSSimon Schubert struct dis_line_entry
395796c8dcSSimon Schubert {
405796c8dcSSimon Schubert   int line;
415796c8dcSSimon Schubert   CORE_ADDR start_pc;
425796c8dcSSimon Schubert   CORE_ADDR end_pc;
435796c8dcSSimon Schubert };
445796c8dcSSimon Schubert 
455796c8dcSSimon Schubert /* Like target_read_memory, but slightly different parameters.  */
465796c8dcSSimon Schubert static int
dis_asm_read_memory(bfd_vma memaddr,gdb_byte * myaddr,unsigned int len,struct disassemble_info * info)475796c8dcSSimon Schubert dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
485796c8dcSSimon Schubert 		     struct disassemble_info *info)
495796c8dcSSimon Schubert {
505796c8dcSSimon Schubert   return target_read_memory (memaddr, myaddr, len);
515796c8dcSSimon Schubert }
525796c8dcSSimon Schubert 
535796c8dcSSimon Schubert /* Like memory_error with slightly different parameters.  */
545796c8dcSSimon Schubert static void
dis_asm_memory_error(int status,bfd_vma memaddr,struct disassemble_info * info)555796c8dcSSimon Schubert dis_asm_memory_error (int status, bfd_vma memaddr,
565796c8dcSSimon Schubert 		      struct disassemble_info *info)
575796c8dcSSimon Schubert {
585796c8dcSSimon Schubert   memory_error (status, memaddr);
595796c8dcSSimon Schubert }
605796c8dcSSimon Schubert 
615796c8dcSSimon Schubert /* Like print_address with slightly different parameters.  */
625796c8dcSSimon Schubert static void
dis_asm_print_address(bfd_vma addr,struct disassemble_info * info)635796c8dcSSimon Schubert dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
645796c8dcSSimon Schubert {
655796c8dcSSimon Schubert   struct gdbarch *gdbarch = info->application_data;
66cf7f2e2dSJohn Marino 
675796c8dcSSimon Schubert   print_address (gdbarch, addr, info->stream);
685796c8dcSSimon Schubert }
695796c8dcSSimon Schubert 
705796c8dcSSimon Schubert static int
compare_lines(const void * mle1p,const void * mle2p)715796c8dcSSimon Schubert compare_lines (const void *mle1p, const void *mle2p)
725796c8dcSSimon Schubert {
735796c8dcSSimon Schubert   struct dis_line_entry *mle1, *mle2;
745796c8dcSSimon Schubert   int val;
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert   mle1 = (struct dis_line_entry *) mle1p;
775796c8dcSSimon Schubert   mle2 = (struct dis_line_entry *) mle2p;
785796c8dcSSimon Schubert 
79c50c785cSJohn Marino   /* End of sequence markers have a line number of 0 but don't want to
80c50c785cSJohn Marino      be sorted to the head of the list, instead sort by PC.  */
81c50c785cSJohn Marino   if (mle1->line == 0 || mle2->line == 0)
82c50c785cSJohn Marino     {
83c50c785cSJohn Marino       val = mle1->start_pc - mle2->start_pc;
84c50c785cSJohn Marino       if (val == 0)
855796c8dcSSimon Schubert         val = mle1->line - mle2->line;
86c50c785cSJohn Marino     }
87c50c785cSJohn Marino   else
88c50c785cSJohn Marino     {
89c50c785cSJohn Marino       val = mle1->line - mle2->line;
90c50c785cSJohn Marino       if (val == 0)
91c50c785cSJohn Marino         val = mle1->start_pc - mle2->start_pc;
92c50c785cSJohn Marino     }
935796c8dcSSimon Schubert   return val;
945796c8dcSSimon Schubert }
955796c8dcSSimon Schubert 
965796c8dcSSimon Schubert static int
dump_insns(struct gdbarch * gdbarch,struct ui_out * uiout,struct disassemble_info * di,CORE_ADDR low,CORE_ADDR high,int how_many,int flags,struct ui_file * stb)975796c8dcSSimon Schubert dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
985796c8dcSSimon Schubert 	    struct disassemble_info * di,
995796c8dcSSimon Schubert 	    CORE_ADDR low, CORE_ADDR high,
100*ef5ccd6cSJohn Marino 	    int how_many, int flags, struct ui_file *stb)
1015796c8dcSSimon Schubert {
1025796c8dcSSimon Schubert   int num_displayed = 0;
1035796c8dcSSimon Schubert   CORE_ADDR pc;
1045796c8dcSSimon Schubert 
1055796c8dcSSimon Schubert   /* parts of the symbolic representation of the address */
1065796c8dcSSimon Schubert   int unmapped;
1075796c8dcSSimon Schubert   int offset;
1085796c8dcSSimon Schubert   int line;
1095796c8dcSSimon Schubert   struct cleanup *ui_out_chain;
1105796c8dcSSimon Schubert 
1115796c8dcSSimon Schubert   for (pc = low; pc < high;)
1125796c8dcSSimon Schubert     {
1135796c8dcSSimon Schubert       char *filename = NULL;
1145796c8dcSSimon Schubert       char *name = NULL;
1155796c8dcSSimon Schubert 
1165796c8dcSSimon Schubert       QUIT;
1175796c8dcSSimon Schubert       if (how_many >= 0)
1185796c8dcSSimon Schubert 	{
1195796c8dcSSimon Schubert 	  if (num_displayed >= how_many)
1205796c8dcSSimon Schubert 	    break;
1215796c8dcSSimon Schubert 	  else
1225796c8dcSSimon Schubert 	    num_displayed++;
1235796c8dcSSimon Schubert 	}
1245796c8dcSSimon Schubert       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
125*ef5ccd6cSJohn Marino 
126*ef5ccd6cSJohn Marino       if ((flags & DISASSEMBLY_OMIT_PC) == 0)
127cf7f2e2dSJohn Marino 	ui_out_text (uiout, pc_prefix (pc));
1285796c8dcSSimon Schubert       ui_out_field_core_addr (uiout, "address", gdbarch, pc);
1295796c8dcSSimon Schubert 
130cf7f2e2dSJohn Marino       if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename,
1315796c8dcSSimon Schubert 				   &line, &unmapped))
1325796c8dcSSimon Schubert 	{
1335796c8dcSSimon Schubert 	  /* We don't care now about line, filename and
1345796c8dcSSimon Schubert 	     unmapped. But we might in the future.  */
1355796c8dcSSimon Schubert 	  ui_out_text (uiout, " <");
136cf7f2e2dSJohn Marino 	  if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
1375796c8dcSSimon Schubert 	    ui_out_field_string (uiout, "func-name", name);
1385796c8dcSSimon Schubert 	  ui_out_text (uiout, "+");
1395796c8dcSSimon Schubert 	  ui_out_field_int (uiout, "offset", offset);
1405796c8dcSSimon Schubert 	  ui_out_text (uiout, ">:\t");
1415796c8dcSSimon Schubert 	}
1425796c8dcSSimon Schubert       else
1435796c8dcSSimon Schubert 	ui_out_text (uiout, ":\t");
1445796c8dcSSimon Schubert 
1455796c8dcSSimon Schubert       if (filename != NULL)
1465796c8dcSSimon Schubert 	xfree (filename);
1475796c8dcSSimon Schubert       if (name != NULL)
1485796c8dcSSimon Schubert 	xfree (name);
1495796c8dcSSimon Schubert 
150*ef5ccd6cSJohn Marino       ui_file_rewind (stb);
1515796c8dcSSimon Schubert       if (flags & DISASSEMBLY_RAW_INSN)
1525796c8dcSSimon Schubert         {
1535796c8dcSSimon Schubert           CORE_ADDR old_pc = pc;
1545796c8dcSSimon Schubert           bfd_byte data;
1555796c8dcSSimon Schubert           int status;
156c50c785cSJohn Marino           const char *spacer = "";
157c50c785cSJohn Marino 
158c50c785cSJohn Marino           /* Build the opcodes using a temporary stream so we can
159c50c785cSJohn Marino              write them out in a single go for the MI.  */
160*ef5ccd6cSJohn Marino           struct ui_file *opcode_stream = mem_fileopen ();
161c50c785cSJohn Marino           struct cleanup *cleanups =
162*ef5ccd6cSJohn Marino             make_cleanup_ui_file_delete (opcode_stream);
163cf7f2e2dSJohn Marino 
1645796c8dcSSimon Schubert           pc += gdbarch_print_insn (gdbarch, pc, di);
1655796c8dcSSimon Schubert           for (;old_pc < pc; old_pc++)
1665796c8dcSSimon Schubert             {
1675796c8dcSSimon Schubert               status = (*di->read_memory_func) (old_pc, &data, 1, di);
1685796c8dcSSimon Schubert               if (status != 0)
1695796c8dcSSimon Schubert                 (*di->memory_error_func) (status, old_pc, di);
170*ef5ccd6cSJohn Marino               fprintf_filtered (opcode_stream, "%s%02x",
171c50c785cSJohn Marino                                 spacer, (unsigned) data);
172c50c785cSJohn Marino               spacer = " ";
1735796c8dcSSimon Schubert             }
174c50c785cSJohn Marino           ui_out_field_stream (uiout, "opcodes", opcode_stream);
1755796c8dcSSimon Schubert           ui_out_text (uiout, "\t");
176c50c785cSJohn Marino 
177c50c785cSJohn Marino           do_cleanups (cleanups);
1785796c8dcSSimon Schubert         }
1795796c8dcSSimon Schubert       else
1805796c8dcSSimon Schubert         pc += gdbarch_print_insn (gdbarch, pc, di);
1815796c8dcSSimon Schubert       ui_out_field_stream (uiout, "inst", stb);
182*ef5ccd6cSJohn Marino       ui_file_rewind (stb);
1835796c8dcSSimon Schubert       do_cleanups (ui_out_chain);
1845796c8dcSSimon Schubert       ui_out_text (uiout, "\n");
1855796c8dcSSimon Schubert     }
1865796c8dcSSimon Schubert   return num_displayed;
1875796c8dcSSimon Schubert }
1885796c8dcSSimon Schubert 
1895796c8dcSSimon Schubert /* The idea here is to present a source-O-centric view of a
1905796c8dcSSimon Schubert    function to the user.  This means that things are presented
1915796c8dcSSimon Schubert    in source order, with (possibly) out of order assembly
1925796c8dcSSimon Schubert    immediately following.  */
193c50c785cSJohn Marino 
1945796c8dcSSimon Schubert static void
do_mixed_source_and_assembly(struct gdbarch * gdbarch,struct ui_out * uiout,struct disassemble_info * di,int nlines,struct linetable_entry * le,CORE_ADDR low,CORE_ADDR high,struct symtab * symtab,int how_many,int flags,struct ui_file * stb)1955796c8dcSSimon Schubert do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
1965796c8dcSSimon Schubert 			      struct disassemble_info *di, int nlines,
1975796c8dcSSimon Schubert 			      struct linetable_entry *le,
1985796c8dcSSimon Schubert 			      CORE_ADDR low, CORE_ADDR high,
1995796c8dcSSimon Schubert 			      struct symtab *symtab,
200*ef5ccd6cSJohn Marino 			      int how_many, int flags, struct ui_file *stb)
2015796c8dcSSimon Schubert {
2025796c8dcSSimon Schubert   int newlines = 0;
2035796c8dcSSimon Schubert   struct dis_line_entry *mle;
2045796c8dcSSimon Schubert   struct symtab_and_line sal;
2055796c8dcSSimon Schubert   int i;
2065796c8dcSSimon Schubert   int out_of_order = 0;
2075796c8dcSSimon Schubert   int next_line = 0;
2085796c8dcSSimon Schubert   int num_displayed = 0;
209*ef5ccd6cSJohn Marino   enum print_source_lines_flags psl_flags = 0;
2105796c8dcSSimon Schubert   struct cleanup *ui_out_chain;
2115796c8dcSSimon Schubert   struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
2125796c8dcSSimon Schubert   struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
2135796c8dcSSimon Schubert 
214*ef5ccd6cSJohn Marino   if (flags & DISASSEMBLY_FILENAME)
215*ef5ccd6cSJohn Marino     psl_flags |= PRINT_SOURCE_LINES_FILENAME;
216*ef5ccd6cSJohn Marino 
2175796c8dcSSimon Schubert   mle = (struct dis_line_entry *) alloca (nlines
2185796c8dcSSimon Schubert 					  * sizeof (struct dis_line_entry));
2195796c8dcSSimon Schubert 
2205796c8dcSSimon Schubert   /* Copy linetable entries for this function into our data
2215796c8dcSSimon Schubert      structure, creating end_pc's and setting out_of_order as
2225796c8dcSSimon Schubert      appropriate.  */
2235796c8dcSSimon Schubert 
2245796c8dcSSimon Schubert   /* First, skip all the preceding functions.  */
2255796c8dcSSimon Schubert 
2265796c8dcSSimon Schubert   for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
2275796c8dcSSimon Schubert 
2285796c8dcSSimon Schubert   /* Now, copy all entries before the end of this function.  */
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert   for (; i < nlines - 1 && le[i].pc < high; i++)
2315796c8dcSSimon Schubert     {
2325796c8dcSSimon Schubert       if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
233c50c785cSJohn Marino 	continue;		/* Ignore duplicates.  */
2345796c8dcSSimon Schubert 
2355796c8dcSSimon Schubert       /* Skip any end-of-function markers.  */
2365796c8dcSSimon Schubert       if (le[i].line == 0)
2375796c8dcSSimon Schubert 	continue;
2385796c8dcSSimon Schubert 
2395796c8dcSSimon Schubert       mle[newlines].line = le[i].line;
2405796c8dcSSimon Schubert       if (le[i].line > le[i + 1].line)
2415796c8dcSSimon Schubert 	out_of_order = 1;
2425796c8dcSSimon Schubert       mle[newlines].start_pc = le[i].pc;
2435796c8dcSSimon Schubert       mle[newlines].end_pc = le[i + 1].pc;
2445796c8dcSSimon Schubert       newlines++;
2455796c8dcSSimon Schubert     }
2465796c8dcSSimon Schubert 
2475796c8dcSSimon Schubert   /* If we're on the last line, and it's part of the function,
2485796c8dcSSimon Schubert      then we need to get the end pc in a special way.  */
2495796c8dcSSimon Schubert 
2505796c8dcSSimon Schubert   if (i == nlines - 1 && le[i].pc < high)
2515796c8dcSSimon Schubert     {
2525796c8dcSSimon Schubert       mle[newlines].line = le[i].line;
2535796c8dcSSimon Schubert       mle[newlines].start_pc = le[i].pc;
2545796c8dcSSimon Schubert       sal = find_pc_line (le[i].pc, 0);
2555796c8dcSSimon Schubert       mle[newlines].end_pc = sal.end;
2565796c8dcSSimon Schubert       newlines++;
2575796c8dcSSimon Schubert     }
2585796c8dcSSimon Schubert 
2595796c8dcSSimon Schubert   /* Now, sort mle by line #s (and, then by addresses within
2605796c8dcSSimon Schubert      lines).  */
2615796c8dcSSimon Schubert 
2625796c8dcSSimon Schubert   if (out_of_order)
2635796c8dcSSimon Schubert     qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
2645796c8dcSSimon Schubert 
2655796c8dcSSimon Schubert   /* Now, for each line entry, emit the specified lines (unless
2665796c8dcSSimon Schubert      they have been emitted before), followed by the assembly code
2675796c8dcSSimon Schubert      for that line.  */
2685796c8dcSSimon Schubert 
2695796c8dcSSimon Schubert   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
2705796c8dcSSimon Schubert 
2715796c8dcSSimon Schubert   for (i = 0; i < newlines; i++)
2725796c8dcSSimon Schubert     {
2735796c8dcSSimon Schubert       /* Print out everything from next_line to the current line.  */
2745796c8dcSSimon Schubert       if (mle[i].line >= next_line)
2755796c8dcSSimon Schubert 	{
2765796c8dcSSimon Schubert 	  if (next_line != 0)
2775796c8dcSSimon Schubert 	    {
2785796c8dcSSimon Schubert 	      /* Just one line to print.  */
2795796c8dcSSimon Schubert 	      if (next_line == mle[i].line)
2805796c8dcSSimon Schubert 		{
2815796c8dcSSimon Schubert 		  ui_out_tuple_chain
2825796c8dcSSimon Schubert 		    = make_cleanup_ui_out_tuple_begin_end (uiout,
2835796c8dcSSimon Schubert 							   "src_and_asm_line");
284*ef5ccd6cSJohn Marino 		  print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
2855796c8dcSSimon Schubert 		}
2865796c8dcSSimon Schubert 	      else
2875796c8dcSSimon Schubert 		{
2885796c8dcSSimon Schubert 		  /* Several source lines w/o asm instructions associated.  */
2895796c8dcSSimon Schubert 		  for (; next_line < mle[i].line; next_line++)
2905796c8dcSSimon Schubert 		    {
2915796c8dcSSimon Schubert 		      struct cleanup *ui_out_list_chain_line;
2925796c8dcSSimon Schubert 		      struct cleanup *ui_out_tuple_chain_line;
2935796c8dcSSimon Schubert 
2945796c8dcSSimon Schubert 		      ui_out_tuple_chain_line
2955796c8dcSSimon Schubert 			= make_cleanup_ui_out_tuple_begin_end (uiout,
2965796c8dcSSimon Schubert 							       "src_and_asm_line");
2975796c8dcSSimon Schubert 		      print_source_lines (symtab, next_line, next_line + 1,
298*ef5ccd6cSJohn Marino 					  psl_flags);
2995796c8dcSSimon Schubert 		      ui_out_list_chain_line
3005796c8dcSSimon Schubert 			= make_cleanup_ui_out_list_begin_end (uiout,
3015796c8dcSSimon Schubert 							      "line_asm_insn");
3025796c8dcSSimon Schubert 		      do_cleanups (ui_out_list_chain_line);
3035796c8dcSSimon Schubert 		      do_cleanups (ui_out_tuple_chain_line);
3045796c8dcSSimon Schubert 		    }
3055796c8dcSSimon Schubert 		  /* Print the last line and leave list open for
3065796c8dcSSimon Schubert 		     asm instructions to be added.  */
3075796c8dcSSimon Schubert 		  ui_out_tuple_chain
3085796c8dcSSimon Schubert 		    = make_cleanup_ui_out_tuple_begin_end (uiout,
3095796c8dcSSimon Schubert 							   "src_and_asm_line");
310*ef5ccd6cSJohn Marino 		  print_source_lines (symtab, next_line, mle[i].line + 1, psl_flags);
3115796c8dcSSimon Schubert 		}
3125796c8dcSSimon Schubert 	    }
3135796c8dcSSimon Schubert 	  else
3145796c8dcSSimon Schubert 	    {
3155796c8dcSSimon Schubert 	      ui_out_tuple_chain
316c50c785cSJohn Marino 		= make_cleanup_ui_out_tuple_begin_end (uiout,
317c50c785cSJohn Marino 						       "src_and_asm_line");
318*ef5ccd6cSJohn Marino 	      print_source_lines (symtab, mle[i].line, mle[i].line + 1, psl_flags);
3195796c8dcSSimon Schubert 	    }
3205796c8dcSSimon Schubert 
3215796c8dcSSimon Schubert 	  next_line = mle[i].line + 1;
3225796c8dcSSimon Schubert 	  ui_out_list_chain
3235796c8dcSSimon Schubert 	    = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
3245796c8dcSSimon Schubert 	}
3255796c8dcSSimon Schubert 
3265796c8dcSSimon Schubert       num_displayed += dump_insns (gdbarch, uiout, di,
3275796c8dcSSimon Schubert 				   mle[i].start_pc, mle[i].end_pc,
3285796c8dcSSimon Schubert 				   how_many, flags, stb);
3295796c8dcSSimon Schubert 
3305796c8dcSSimon Schubert       /* When we've reached the end of the mle array, or we've seen the last
3315796c8dcSSimon Schubert          assembly range for this source line, close out the list/tuple.  */
3325796c8dcSSimon Schubert       if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
3335796c8dcSSimon Schubert 	{
3345796c8dcSSimon Schubert 	  do_cleanups (ui_out_list_chain);
3355796c8dcSSimon Schubert 	  do_cleanups (ui_out_tuple_chain);
3365796c8dcSSimon Schubert 	  ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
3375796c8dcSSimon Schubert 	  ui_out_list_chain = make_cleanup (null_cleanup, 0);
3385796c8dcSSimon Schubert 	  ui_out_text (uiout, "\n");
3395796c8dcSSimon Schubert 	}
3405796c8dcSSimon Schubert       if (how_many >= 0 && num_displayed >= how_many)
3415796c8dcSSimon Schubert 	break;
3425796c8dcSSimon Schubert     }
3435796c8dcSSimon Schubert   do_cleanups (ui_out_chain);
3445796c8dcSSimon Schubert }
3455796c8dcSSimon Schubert 
3465796c8dcSSimon Schubert 
3475796c8dcSSimon Schubert static void
do_assembly_only(struct gdbarch * gdbarch,struct ui_out * uiout,struct disassemble_info * di,CORE_ADDR low,CORE_ADDR high,int how_many,int flags,struct ui_file * stb)3485796c8dcSSimon Schubert do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
3495796c8dcSSimon Schubert 		  struct disassemble_info * di,
3505796c8dcSSimon Schubert 		  CORE_ADDR low, CORE_ADDR high,
351*ef5ccd6cSJohn Marino 		  int how_many, int flags, struct ui_file *stb)
3525796c8dcSSimon Schubert {
3535796c8dcSSimon Schubert   int num_displayed = 0;
3545796c8dcSSimon Schubert   struct cleanup *ui_out_chain;
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
3575796c8dcSSimon Schubert 
3585796c8dcSSimon Schubert   num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many,
3595796c8dcSSimon Schubert                               flags, stb);
3605796c8dcSSimon Schubert 
3615796c8dcSSimon Schubert   do_cleanups (ui_out_chain);
3625796c8dcSSimon Schubert }
3635796c8dcSSimon Schubert 
3645796c8dcSSimon Schubert /* Initialize the disassemble info struct ready for the specified
3655796c8dcSSimon Schubert    stream.  */
3665796c8dcSSimon Schubert 
367cf7f2e2dSJohn Marino static int ATTRIBUTE_PRINTF (2, 3)
fprintf_disasm(void * stream,const char * format,...)3685796c8dcSSimon Schubert fprintf_disasm (void *stream, const char *format, ...)
3695796c8dcSSimon Schubert {
3705796c8dcSSimon Schubert   va_list args;
371cf7f2e2dSJohn Marino 
3725796c8dcSSimon Schubert   va_start (args, format);
3735796c8dcSSimon Schubert   vfprintf_filtered (stream, format, args);
3745796c8dcSSimon Schubert   va_end (args);
3755796c8dcSSimon Schubert   /* Something non -ve.  */
3765796c8dcSSimon Schubert   return 0;
3775796c8dcSSimon Schubert }
3785796c8dcSSimon Schubert 
3795796c8dcSSimon Schubert static struct disassemble_info
gdb_disassemble_info(struct gdbarch * gdbarch,struct ui_file * file)3805796c8dcSSimon Schubert gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
3815796c8dcSSimon Schubert {
3825796c8dcSSimon Schubert   struct disassemble_info di;
383cf7f2e2dSJohn Marino 
3845796c8dcSSimon Schubert   init_disassemble_info (&di, file, fprintf_disasm);
3855796c8dcSSimon Schubert   di.flavour = bfd_target_unknown_flavour;
3865796c8dcSSimon Schubert   di.memory_error_func = dis_asm_memory_error;
3875796c8dcSSimon Schubert   di.print_address_func = dis_asm_print_address;
3885796c8dcSSimon Schubert   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
3895796c8dcSSimon Schubert      disassembler had a local optomization here.  By default it would
3905796c8dcSSimon Schubert      access the executable file, instead of the target memory (there
3915796c8dcSSimon Schubert      was a growing list of exceptions though).  Unfortunately, the
3925796c8dcSSimon Schubert      heuristic was flawed.  Commands like "disassemble &variable"
3935796c8dcSSimon Schubert      didn't work as they relied on the access going to the target.
3945796c8dcSSimon Schubert      Further, it has been supperseeded by trust-read-only-sections
3955796c8dcSSimon Schubert      (although that should be superseeded by target_trust..._p()).  */
3965796c8dcSSimon Schubert   di.read_memory_func = dis_asm_read_memory;
3975796c8dcSSimon Schubert   di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
3985796c8dcSSimon Schubert   di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
3995796c8dcSSimon Schubert   di.endian = gdbarch_byte_order (gdbarch);
4005796c8dcSSimon Schubert   di.endian_code = gdbarch_byte_order_for_code (gdbarch);
4015796c8dcSSimon Schubert   di.application_data = gdbarch;
4025796c8dcSSimon Schubert   disassemble_init_for_target (&di);
4035796c8dcSSimon Schubert   return di;
4045796c8dcSSimon Schubert }
4055796c8dcSSimon Schubert 
4065796c8dcSSimon Schubert void
gdb_disassembly(struct gdbarch * gdbarch,struct ui_out * uiout,char * file_string,int flags,int how_many,CORE_ADDR low,CORE_ADDR high)4075796c8dcSSimon Schubert gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
408cf7f2e2dSJohn Marino 		 char *file_string, int flags, int how_many,
409cf7f2e2dSJohn Marino 		 CORE_ADDR low, CORE_ADDR high)
4105796c8dcSSimon Schubert {
411*ef5ccd6cSJohn Marino   struct ui_file *stb = mem_fileopen ();
412*ef5ccd6cSJohn Marino   struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
413*ef5ccd6cSJohn Marino   struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
4145796c8dcSSimon Schubert   /* To collect the instruction outputted from opcodes.  */
4155796c8dcSSimon Schubert   struct symtab *symtab = NULL;
4165796c8dcSSimon Schubert   struct linetable_entry *le = NULL;
4175796c8dcSSimon Schubert   int nlines = -1;
4185796c8dcSSimon Schubert 
419c50c785cSJohn Marino   /* Assume symtab is valid for whole PC range.  */
4205796c8dcSSimon Schubert   symtab = find_pc_symtab (low);
4215796c8dcSSimon Schubert 
4225796c8dcSSimon Schubert   if (symtab != NULL && symtab->linetable != NULL)
4235796c8dcSSimon Schubert     {
4245796c8dcSSimon Schubert       /* Convert the linetable to a bunch of my_line_entry's.  */
4255796c8dcSSimon Schubert       le = symtab->linetable->item;
4265796c8dcSSimon Schubert       nlines = symtab->linetable->nitems;
4275796c8dcSSimon Schubert     }
4285796c8dcSSimon Schubert 
4295796c8dcSSimon Schubert   if (!(flags & DISASSEMBLY_SOURCE) || nlines <= 0
4305796c8dcSSimon Schubert       || symtab == NULL || symtab->linetable == NULL)
4315796c8dcSSimon Schubert     do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
4325796c8dcSSimon Schubert 
4335796c8dcSSimon Schubert   else if (flags & DISASSEMBLY_SOURCE)
4345796c8dcSSimon Schubert     do_mixed_source_and_assembly (gdbarch, uiout, &di, nlines, le, low,
4355796c8dcSSimon Schubert 				  high, symtab, how_many, flags, stb);
4365796c8dcSSimon Schubert 
4375796c8dcSSimon Schubert   do_cleanups (cleanups);
4385796c8dcSSimon Schubert   gdb_flush (gdb_stdout);
4395796c8dcSSimon Schubert }
4405796c8dcSSimon Schubert 
4415796c8dcSSimon Schubert /* Print the instruction at address MEMADDR in debugged memory,
4425796c8dcSSimon Schubert    on STREAM.  Returns the length of the instruction, in bytes,
4435796c8dcSSimon Schubert    and, if requested, the number of branch delay slot instructions.  */
4445796c8dcSSimon Schubert 
4455796c8dcSSimon Schubert int
gdb_print_insn(struct gdbarch * gdbarch,CORE_ADDR memaddr,struct ui_file * stream,int * branch_delay_insns)4465796c8dcSSimon Schubert gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
4475796c8dcSSimon Schubert 		struct ui_file *stream, int *branch_delay_insns)
4485796c8dcSSimon Schubert {
4495796c8dcSSimon Schubert   struct disassemble_info di;
4505796c8dcSSimon Schubert   int length;
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert   di = gdb_disassemble_info (gdbarch, stream);
4535796c8dcSSimon Schubert   length = gdbarch_print_insn (gdbarch, memaddr, &di);
4545796c8dcSSimon Schubert   if (branch_delay_insns)
4555796c8dcSSimon Schubert     {
4565796c8dcSSimon Schubert       if (di.insn_info_valid)
4575796c8dcSSimon Schubert 	*branch_delay_insns = di.branch_delay_insns;
4585796c8dcSSimon Schubert       else
4595796c8dcSSimon Schubert 	*branch_delay_insns = 0;
4605796c8dcSSimon Schubert     }
4615796c8dcSSimon Schubert   return length;
4625796c8dcSSimon Schubert }
463cf7f2e2dSJohn Marino 
464cf7f2e2dSJohn Marino static void
do_ui_file_delete(void * arg)465cf7f2e2dSJohn Marino do_ui_file_delete (void *arg)
466cf7f2e2dSJohn Marino {
467cf7f2e2dSJohn Marino   ui_file_delete (arg);
468cf7f2e2dSJohn Marino }
469cf7f2e2dSJohn Marino 
470cf7f2e2dSJohn Marino /* Return the length in bytes of the instruction at address MEMADDR in
471cf7f2e2dSJohn Marino    debugged memory.  */
472cf7f2e2dSJohn Marino 
473cf7f2e2dSJohn Marino int
gdb_insn_length(struct gdbarch * gdbarch,CORE_ADDR addr)474cf7f2e2dSJohn Marino gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
475cf7f2e2dSJohn Marino {
476cf7f2e2dSJohn Marino   static struct ui_file *null_stream = NULL;
477cf7f2e2dSJohn Marino 
478cf7f2e2dSJohn Marino   /* Dummy file descriptor for the disassembler.  */
479cf7f2e2dSJohn Marino   if (!null_stream)
480cf7f2e2dSJohn Marino     {
481cf7f2e2dSJohn Marino       null_stream = ui_file_new ();
482cf7f2e2dSJohn Marino       make_final_cleanup (do_ui_file_delete, null_stream);
483cf7f2e2dSJohn Marino     }
484cf7f2e2dSJohn Marino 
485cf7f2e2dSJohn Marino   return gdb_print_insn (gdbarch, addr, null_stream, NULL);
486cf7f2e2dSJohn Marino }
487cf7f2e2dSJohn Marino 
488cf7f2e2dSJohn Marino /* fprintf-function for gdb_buffered_insn_length.  This function is a
489cf7f2e2dSJohn Marino    nop, we don't want to print anything, we just want to compute the
490cf7f2e2dSJohn Marino    length of the insn.  */
491cf7f2e2dSJohn Marino 
492cf7f2e2dSJohn Marino static int ATTRIBUTE_PRINTF (2, 3)
gdb_buffered_insn_length_fprintf(void * stream,const char * format,...)493cf7f2e2dSJohn Marino gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...)
494cf7f2e2dSJohn Marino {
495cf7f2e2dSJohn Marino   return 0;
496cf7f2e2dSJohn Marino }
497cf7f2e2dSJohn Marino 
498cf7f2e2dSJohn Marino /* Initialize a struct disassemble_info for gdb_buffered_insn_length.  */
499cf7f2e2dSJohn Marino 
500cf7f2e2dSJohn Marino 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)501cf7f2e2dSJohn Marino gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
502cf7f2e2dSJohn Marino 				   struct disassemble_info *di,
503cf7f2e2dSJohn Marino 				   const gdb_byte *insn, int max_len,
504cf7f2e2dSJohn Marino 				   CORE_ADDR addr)
505cf7f2e2dSJohn Marino {
506cf7f2e2dSJohn Marino   init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf);
507cf7f2e2dSJohn Marino 
508cf7f2e2dSJohn Marino   /* init_disassemble_info installs buffer_read_memory, etc.
509cf7f2e2dSJohn Marino      so we don't need to do that here.
510cf7f2e2dSJohn Marino      The cast is necessary until disassemble_info is const-ified.  */
511cf7f2e2dSJohn Marino   di->buffer = (gdb_byte *) insn;
512cf7f2e2dSJohn Marino   di->buffer_length = max_len;
513cf7f2e2dSJohn Marino   di->buffer_vma = addr;
514cf7f2e2dSJohn Marino 
515cf7f2e2dSJohn Marino   di->arch = gdbarch_bfd_arch_info (gdbarch)->arch;
516cf7f2e2dSJohn Marino   di->mach = gdbarch_bfd_arch_info (gdbarch)->mach;
517cf7f2e2dSJohn Marino   di->endian = gdbarch_byte_order (gdbarch);
518cf7f2e2dSJohn Marino   di->endian_code = gdbarch_byte_order_for_code (gdbarch);
519cf7f2e2dSJohn Marino 
520cf7f2e2dSJohn Marino   disassemble_init_for_target (di);
521cf7f2e2dSJohn Marino }
522cf7f2e2dSJohn Marino 
523cf7f2e2dSJohn Marino /* Return the length in bytes of INSN.  MAX_LEN is the size of the
524cf7f2e2dSJohn Marino    buffer containing INSN.  */
525cf7f2e2dSJohn Marino 
526cf7f2e2dSJohn Marino int
gdb_buffered_insn_length(struct gdbarch * gdbarch,const gdb_byte * insn,int max_len,CORE_ADDR addr)527cf7f2e2dSJohn Marino gdb_buffered_insn_length (struct gdbarch *gdbarch,
528cf7f2e2dSJohn Marino 			  const gdb_byte *insn, int max_len, CORE_ADDR addr)
529cf7f2e2dSJohn Marino {
530cf7f2e2dSJohn Marino   struct disassemble_info di;
531cf7f2e2dSJohn Marino 
532cf7f2e2dSJohn Marino   gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
533cf7f2e2dSJohn Marino 
534cf7f2e2dSJohn Marino   return gdbarch_print_insn (gdbarch, addr, &di);
535cf7f2e2dSJohn Marino }
536