OSDN Git Service

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