OSDN Git Service

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