OSDN Git Service

2003-04-04 Elena Zannoni <ezannoni@redhat.com>
[pf3gnuchains/pf3gnuchains3x.git] / gdb / disasm.c
1 /* Disassemble support for GDB.
2
3    Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
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 "ui-out.h"
26 #include "gdb_string.h"
27
28 #include "disasm.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 /* This variable determines where memory used for disassembly is read from. */
47 int gdb_disassemble_from_exec = -1;
48
49 /* This is the memory_read_func for gdb_disassemble when we are
50    disassembling from the exec file. */
51 static int
52 gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr,
53                          unsigned int len, disassemble_info * info)
54 {
55   extern struct target_ops exec_ops;
56   int res;
57
58   errno = 0;
59   res = xfer_memory (memaddr, myaddr, len, 0, 0, &exec_ops);
60
61   if (res == len)
62     return 0;
63   else if (errno == 0)
64     return EIO;
65   else
66     return errno;
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, 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       if (filename != NULL)
128         xfree (filename);
129       if (name != NULL)
130         xfree (name);
131
132       ui_file_rewind (stb->stream);
133       pc += TARGET_PRINT_INSN (pc, di);
134       ui_out_field_stream (uiout, "inst", stb);
135       ui_file_rewind (stb->stream);
136       do_cleanups (ui_out_chain);
137       ui_out_text (uiout, "\n");
138     }
139   return num_displayed;
140 }
141
142 /* The idea here is to present a source-O-centric view of a
143    function to the user.  This means that things are presented
144    in source order, with (possibly) out of order assembly
145    immediately following.  */
146 static void
147 do_mixed_source_and_assembly (struct ui_out *uiout,
148                               struct disassemble_info *di, int nlines,
149                               struct linetable_entry *le,
150                               CORE_ADDR low, CORE_ADDR high,
151                               struct symtab *symtab,
152                               int how_many, struct ui_stream *stb)
153 {
154   int newlines = 0;
155   struct dis_line_entry *mle;
156   struct symtab_and_line sal;
157   int i;
158   int out_of_order = 0;
159   int next_line = 0;
160   CORE_ADDR pc;
161   int num_displayed = 0;
162   struct cleanup *ui_out_chain;
163
164   mle = (struct dis_line_entry *) alloca (nlines
165                                           * sizeof (struct dis_line_entry));
166
167   /* Copy linetable entries for this function into our data
168      structure, creating end_pc's and setting out_of_order as
169      appropriate.  */
170
171   /* First, skip all the preceding functions.  */
172
173   for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
174
175   /* Now, copy all entries before the end of this function.  */
176
177   for (; i < nlines - 1 && le[i].pc < high; i++)
178     {
179       if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
180         continue;               /* Ignore duplicates */
181
182       /* Skip any end-of-function markers.  */
183       if (le[i].line == 0)
184         continue;
185
186       mle[newlines].line = le[i].line;
187       if (le[i].line > le[i + 1].line)
188         out_of_order = 1;
189       mle[newlines].start_pc = le[i].pc;
190       mle[newlines].end_pc = le[i + 1].pc;
191       newlines++;
192     }
193
194   /* If we're on the last line, and it's part of the function,
195      then we need to get the end pc in a special way.  */
196
197   if (i == nlines - 1 && le[i].pc < high)
198     {
199       mle[newlines].line = le[i].line;
200       mle[newlines].start_pc = le[i].pc;
201       sal = find_pc_line (le[i].pc, 0);
202       mle[newlines].end_pc = sal.end;
203       newlines++;
204     }
205
206   /* Now, sort mle by line #s (and, then by addresses within
207      lines). */
208
209   if (out_of_order)
210     qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
211
212   /* Now, for each line entry, emit the specified lines (unless
213      they have been emitted before), followed by the assembly code
214      for that line.  */
215
216   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
217
218   for (i = 0; i < newlines; i++)
219     {
220       struct cleanup *ui_out_tuple_chain = NULL;
221       struct cleanup *ui_out_list_chain = NULL;
222       int close_list = 1;
223       
224       /* Print out everything from next_line to the current line.  */
225       if (mle[i].line >= next_line)
226         {
227           if (next_line != 0)
228             {
229               /* Just one line to print. */
230               if (next_line == mle[i].line)
231                 {
232                   ui_out_tuple_chain
233                     = make_cleanup_ui_out_tuple_begin_end (uiout,
234                                                            "src_and_asm_line");
235                   print_source_lines (symtab, next_line, mle[i].line + 1, 0);
236                 }
237               else
238                 {
239                   /* Several source lines w/o asm instructions associated. */
240                   for (; next_line < mle[i].line; next_line++)
241                     {
242                       struct cleanup *ui_out_list_chain_line;
243                       struct cleanup *ui_out_tuple_chain_line;
244                       
245                       ui_out_tuple_chain_line
246                         = make_cleanup_ui_out_tuple_begin_end (uiout,
247                                                                "src_and_asm_line");
248                       print_source_lines (symtab, next_line, next_line + 1,
249                                           0);
250                       ui_out_list_chain_line
251                         = make_cleanup_ui_out_list_begin_end (uiout,
252                                                               "line_asm_insn");
253                       do_cleanups (ui_out_list_chain_line);
254                       do_cleanups (ui_out_tuple_chain_line);
255                     }
256                   /* Print the last line and leave list open for
257                      asm instructions to be added. */
258                   ui_out_tuple_chain
259                     = make_cleanup_ui_out_tuple_begin_end (uiout,
260                                                            "src_and_asm_line");
261                   print_source_lines (symtab, next_line, mle[i].line + 1, 0);
262                 }
263             }
264           else
265             {
266               ui_out_tuple_chain
267                 = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
268               print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
269             }
270
271           next_line = mle[i].line + 1;
272           ui_out_list_chain
273             = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
274           /* Don't close the list if the lines are not in order. */
275           if (i < (newlines - 1) && mle[i + 1].line <= mle[i].line)
276             close_list = 0;
277         }
278
279       num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
280                                    how_many, stb);
281       if (close_list)
282         {
283           do_cleanups (ui_out_list_chain);
284           do_cleanups (ui_out_tuple_chain);
285           ui_out_text (uiout, "\n");
286           close_list = 0;
287         }
288       if (how_many >= 0)
289         if (num_displayed >= how_many)
290           break;
291     }
292   do_cleanups (ui_out_chain);
293 }
294
295
296 static void
297 do_assembly_only (struct ui_out *uiout, disassemble_info * di,
298                   CORE_ADDR low, CORE_ADDR high,
299                   int how_many, struct ui_stream *stb)
300 {
301   int num_displayed = 0;
302   struct cleanup *ui_out_chain;
303
304   ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
305
306   num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
307
308   do_cleanups (ui_out_chain);
309 }
310
311 void
312 gdb_disassembly (struct ui_out *uiout,
313                 char *file_string,
314                 int line_num,
315                 int mixed_source_and_assembly,
316                 int how_many, CORE_ADDR low, CORE_ADDR high)
317 {
318   static disassemble_info di;
319   static int di_initialized;
320   /* To collect the instruction outputted from opcodes. */
321   static struct ui_stream *stb = NULL;
322   struct symtab *symtab = NULL;
323   struct linetable_entry *le = NULL;
324   int nlines = -1;
325
326   if (!di_initialized)
327     {
328       /* We don't add a cleanup for this, because the allocation of
329          the stream is done once only for each gdb run, and we need to
330          keep it around until the end. Hopefully there won't be any
331          errors in the init code below, that make this function bail
332          out. */
333       stb = ui_out_stream_new (uiout);
334       INIT_DISASSEMBLE_INFO_NO_ARCH (di, stb->stream,
335                                      (fprintf_ftype) fprintf_unfiltered);
336       di.flavour = bfd_target_unknown_flavour;
337       di.memory_error_func = dis_asm_memory_error;
338       di.print_address_func = dis_asm_print_address;
339       di_initialized = 1;
340     }
341
342   di.mach = gdbarch_bfd_arch_info (current_gdbarch)->mach;
343   di.endian = gdbarch_byte_order (current_gdbarch);
344
345   /* If gdb_disassemble_from_exec == -1, then we use the following heuristic to
346      determine whether or not to do disassembly from target memory or from the
347      exec file:
348
349      If we're debugging a local process, read target memory, instead of the
350      exec file.  This makes disassembly of functions in shared libs work
351      correctly.  Also, read target memory if we are debugging native threads.
352
353      Else, we're debugging a remote process, and should disassemble from the
354      exec file for speed.  However, this is no good if the target modifies its
355      code (for relocation, or whatever).  */
356
357   if (gdb_disassemble_from_exec == -1)
358     {
359       if (strcmp (target_shortname, "child") == 0
360           || strcmp (target_shortname, "procfs") == 0
361           || strcmp (target_shortname, "vxprocess") == 0
362           || strcmp (target_shortname, "core") == 0
363           || strstr (target_shortname, "-thread") != NULL)
364         gdb_disassemble_from_exec = 0;  /* It's a child process, read inferior mem */
365       else
366         gdb_disassemble_from_exec = 1;  /* It's remote, read the exec file */
367     }
368
369   if (gdb_disassemble_from_exec)
370     di.read_memory_func = gdb_dis_asm_read_memory;
371   else
372     di.read_memory_func = dis_asm_read_memory;
373
374   /* Assume symtab is valid for whole PC range */
375   symtab = find_pc_symtab (low);
376
377   if (symtab != NULL && symtab->linetable != NULL)
378     {
379       /* Convert the linetable to a bunch of my_line_entry's.  */
380       le = symtab->linetable->item;
381       nlines = symtab->linetable->nitems;
382     }
383
384   if (!mixed_source_and_assembly || nlines <= 0
385       || symtab == NULL || symtab->linetable == NULL)
386     do_assembly_only (uiout, &di, low, high, how_many, stb);
387
388   else if (mixed_source_and_assembly)
389     do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
390                                   high, symtab, how_many, stb);
391
392   gdb_flush (gdb_stdout);
393 }