Import gdb-7.0
[dragonfly.git] / contrib / gdb-6 / gdb / disasm.c
1 /* Disassemble support for GDB.
2
3    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
4    Free Software Foundation, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include "defs.h"
22 #include "target.h"
23 #include "value.h"
24 #include "ui-out.h"
25 #include "gdb_string.h"
26 #include "disasm.h"
27 #include "gdbcore.h"
28 #include "dis-asm.h"
29
30 /* Disassemble functions.
31    FIXME: We should get rid of all the duplicate code in gdb that does
32    the same thing: disassemble_command() and the gdbtk variation. */
33
34 /* This Structure is used to store line number information.
35    We need a different sort of line table from the normal one cuz we can't
36    depend upon implicit line-end pc's for lines to do the
37    reordering in this function.  */
38
39 struct dis_line_entry
40 {
41   int line;
42   CORE_ADDR start_pc;
43   CORE_ADDR end_pc;
44 };
45
46 /* Like target_read_memory, but slightly different parameters.  */
47 static int
48 dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
49                      struct disassemble_info *info)
50 {
51   return target_read_memory (memaddr, myaddr, len);
52 }
53
54 /* Like memory_error with slightly different parameters.  */
55 static void
56 dis_asm_memory_error (int status, bfd_vma memaddr,
57                       struct disassemble_info *info)
58 {
59   memory_error (status, memaddr);
60 }
61
62 /* Like print_address with slightly different parameters.  */
63 static void
64 dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
65 {
66   print_address (addr, info->stream);
67 }
68
69 static int
70 compare_lines (const void *mle1p, const void *mle2p)
71 {
72   struct dis_line_entry *mle1, *mle2;
73   int val;
74
75   mle1 = (struct dis_line_entry *) mle1p;
76   mle2 = (struct dis_line_entry *) mle2p;
77
78   val = mle1->line - mle2->line;
79
80   if (val != 0)
81     return val;
82
83   return mle1->start_pc - mle2->start_pc;
84 }
85
86 static int
87 dump_insns (struct ui_out *uiout, struct disassemble_info * di,
88             CORE_ADDR low, CORE_ADDR high,
89             int how_many, struct ui_stream *stb)
90 {
91   int num_displayed = 0;
92   CORE_ADDR pc;
93
94   /* parts of the symbolic representation of the address */
95   int unmapped;
96   int offset;
97   int line;
98   struct cleanup *ui_out_chain;
99
100   for (pc = low; pc < high;)
101     {
102       char *filename = NULL;
103       char *name = NULL;
104
105       QUIT;
106       if (how_many >= 0)
107         {
108           if (num_displayed >= how_many)
109             break;
110           else
111             num_displayed++;
112         }
113       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
114       ui_out_field_core_addr (uiout, "address", pc);
115
116       if (!build_address_symbolic (pc, 0, &name, &offset, &filename,
117                                    &line, &unmapped))
118         {
119           /* We don't care now about line, filename and
120              unmapped. But we might in the future. */
121           ui_out_text (uiout, " <");
122           ui_out_field_string (uiout, "func-name", name);
123           ui_out_text (uiout, "+");
124           ui_out_field_int (uiout, "offset", offset);
125           ui_out_text (uiout, ">:\t");
126         }
127       else
128         ui_out_text (uiout, ":\t");
129
130       if (filename != NULL)
131         xfree (filename);
132       if (name != NULL)
133         xfree (name);
134
135       ui_file_rewind (stb->stream);
136       pc += gdbarch_print_insn (current_gdbarch, pc, di);
137       ui_out_field_stream (uiout, "inst", stb);
138       ui_file_rewind (stb->stream);
139       do_cleanups (ui_out_chain);
140       ui_out_text (uiout, "\n");
141     }
142   return num_displayed;
143 }
144
145 /* The idea here is to present a source-O-centric view of a
146    function to the user.  This means that things are presented
147    in source order, with (possibly) out of order assembly
148    immediately following.  */
149 static void
150 do_mixed_source_and_assembly (struct ui_out *uiout,
151                               struct disassemble_info *di, int nlines,
152                               struct linetable_entry *le,
153                               CORE_ADDR low, CORE_ADDR high,
154                               struct symtab *symtab,
155                               int how_many, struct ui_stream *stb)
156 {
157   int newlines = 0;
158   struct dis_line_entry *mle;
159   struct symtab_and_line sal;
160   int i;
161   int out_of_order = 0;
162   int next_line = 0;
163   CORE_ADDR pc;
164   int num_displayed = 0;
165   struct cleanup *ui_out_chain;
166   struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
167   struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
168
169   mle = (struct dis_line_entry *) alloca (nlines
170                                           * sizeof (struct dis_line_entry));
171
172   /* Copy linetable entries for this function into our data
173      structure, creating end_pc's and setting out_of_order as
174      appropriate.  */
175
176   /* First, skip all the preceding functions.  */
177
178   for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
179
180   /* Now, copy all entries before the end of this function.  */
181
182   for (; i < nlines - 1 && le[i].pc < high; i++)
183     {
184       if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
185         continue;               /* Ignore duplicates */
186
187       /* Skip any end-of-function markers.  */
188       if (le[i].line == 0)
189         continue;
190
191       mle[newlines].line = le[i].line;
192       if (le[i].line > le[i + 1].line)
193         out_of_order = 1;
194       mle[newlines].start_pc = le[i].pc;
195       mle[newlines].end_pc = le[i + 1].pc;
196       newlines++;
197     }
198
199   /* If we're on the last line, and it's part of the function,
200      then we need to get the end pc in a special way.  */
201
202   if (i == nlines - 1 && le[i].pc < high)
203     {
204       mle[newlines].line = le[i].line;
205       mle[newlines].start_pc = le[i].pc;
206       sal = find_pc_line (le[i].pc, 0);
207       mle[newlines].end_pc = sal.end;
208       newlines++;
209     }
210
211   /* Now, sort mle by line #s (and, then by addresses within
212      lines). */
213
214   if (out_of_order)
215     qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
216
217   /* Now, for each line entry, emit the specified lines (unless
218      they have been emitted before), followed by the assembly code
219      for that line.  */
220
221   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
222
223   for (i = 0; i < newlines; i++)
224     {
225       /* Print out everything from next_line to the current line.  */
226       if (mle[i].line >= next_line)
227         {
228           if (next_line != 0)
229             {
230               /* Just one line to print. */
231               if (next_line == mle[i].line)
232                 {
233                   ui_out_tuple_chain
234                     = make_cleanup_ui_out_tuple_begin_end (uiout,
235                                                            "src_and_asm_line");
236                   print_source_lines (symtab, next_line, mle[i].line + 1, 0);
237                 }
238               else
239                 {
240                   /* Several source lines w/o asm instructions associated. */
241                   for (; next_line < mle[i].line; next_line++)
242                     {
243                       struct cleanup *ui_out_list_chain_line;
244                       struct cleanup *ui_out_tuple_chain_line;
245                       
246                       ui_out_tuple_chain_line
247                         = make_cleanup_ui_out_tuple_begin_end (uiout,
248                                                                "src_and_asm_line");
249                       print_source_lines (symtab, next_line, next_line + 1,
250                                           0);
251                       ui_out_list_chain_line
252                         = make_cleanup_ui_out_list_begin_end (uiout,
253                                                               "line_asm_insn");
254                       do_cleanups (ui_out_list_chain_line);
255                       do_cleanups (ui_out_tuple_chain_line);
256                     }
257                   /* Print the last line and leave list open for
258                      asm instructions to be added. */
259                   ui_out_tuple_chain
260                     = make_cleanup_ui_out_tuple_begin_end (uiout,
261                                                            "src_and_asm_line");
262                   print_source_lines (symtab, next_line, mle[i].line + 1, 0);
263                 }
264             }
265           else
266             {
267               ui_out_tuple_chain
268                 = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
269               print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
270             }
271
272           next_line = mle[i].line + 1;
273           ui_out_list_chain
274             = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
275         }
276
277       num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
278                                    how_many, stb);
279
280       /* When we've reached the end of the mle array, or we've seen the last
281          assembly range for this source line, close out the list/tuple.  */
282       if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
283         {
284           do_cleanups (ui_out_list_chain);
285           do_cleanups (ui_out_tuple_chain);
286           ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
287           ui_out_list_chain = make_cleanup (null_cleanup, 0);
288           ui_out_text (uiout, "\n");
289         }
290       if (how_many >= 0 && num_displayed >= how_many)
291         break;
292     }
293   do_cleanups (ui_out_chain);
294 }
295
296
297 static void
298 do_assembly_only (struct ui_out *uiout, struct disassemble_info * di,
299                   CORE_ADDR low, CORE_ADDR high,
300                   int how_many, struct ui_stream *stb)
301 {
302   int num_displayed = 0;
303   struct cleanup *ui_out_chain;
304
305   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
306
307   num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
308
309   do_cleanups (ui_out_chain);
310 }
311
312 /* Initialize the disassemble info struct ready for the specified
313    stream.  */
314
315 static int ATTR_FORMAT (printf, 2, 3)
316 fprintf_disasm (void *stream, const char *format, ...)
317 {
318   va_list args;
319   va_start (args, format);
320   vfprintf_filtered (stream, format, args);
321   va_end (args);
322   /* Something non -ve.  */
323   return 0;
324 }
325
326 static struct disassemble_info
327 gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
328 {
329   struct disassemble_info di;
330   init_disassemble_info (&di, file, fprintf_disasm);
331   di.flavour = bfd_target_unknown_flavour;
332   di.memory_error_func = dis_asm_memory_error;
333   di.print_address_func = dis_asm_print_address;
334   /* NOTE: cagney/2003-04-28: The original code, from the old Insight
335      disassembler had a local optomization here.  By default it would
336      access the executable file, instead of the target memory (there
337      was a growing list of exceptions though).  Unfortunately, the
338      heuristic was flawed.  Commands like "disassemble &variable"
339      didn't work as they relied on the access going to the target.
340      Further, it has been supperseeded by trust-read-only-sections
341      (although that should be superseeded by target_trust..._p()).  */
342   di.read_memory_func = dis_asm_read_memory;
343   di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
344   di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
345   di.endian = gdbarch_byte_order (gdbarch);
346   disassemble_init_for_target (&di);
347   return di;
348 }
349
350 void
351 gdb_disassembly (struct ui_out *uiout,
352                 char *file_string,
353                 int line_num,
354                 int mixed_source_and_assembly,
355                 int how_many, CORE_ADDR low, CORE_ADDR high)
356 {
357   struct ui_stream *stb = ui_out_stream_new (uiout);
358   struct cleanup *cleanups = make_cleanup_ui_out_stream_delete (stb);
359   struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream);
360   /* To collect the instruction outputted from opcodes. */
361   struct symtab *symtab = NULL;
362   struct linetable_entry *le = NULL;
363   int nlines = -1;
364
365   /* Assume symtab is valid for whole PC range */
366   symtab = find_pc_symtab (low);
367
368   if (symtab != NULL && symtab->linetable != NULL)
369     {
370       /* Convert the linetable to a bunch of my_line_entry's.  */
371       le = symtab->linetable->item;
372       nlines = symtab->linetable->nitems;
373     }
374
375   if (!mixed_source_and_assembly || nlines <= 0
376       || symtab == NULL || symtab->linetable == NULL)
377     do_assembly_only (uiout, &di, low, high, how_many, stb);
378
379   else if (mixed_source_and_assembly)
380     do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
381                                   high, symtab, how_many, stb);
382
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 the length of the instruction, in bytes,
389    and, if requested, the number of branch delay slot instructions.  */
390
391 int
392 gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream,
393                 int *branch_delay_insns)
394 {
395   struct disassemble_info di;
396   int length;
397
398   di = gdb_disassemble_info (current_gdbarch, stream);
399   length = gdbarch_print_insn (current_gdbarch, memaddr, &di);
400   if (branch_delay_insns)
401     {
402       if (di.insn_info_valid)
403         *branch_delay_insns = di.branch_delay_insns;
404       else
405         *branch_delay_insns = 0;
406     }
407   return length;
408 }