2003-04-30 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / disasm.c
CommitLineData
92df71f0 1/* Disassemble support for GDB.
1bac305b
AC
2
3 Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
92df71f0
FN
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"
92df71f0 27#include "disasm.h"
810ecf9f 28#include "gdbcore.h"
92df71f0
FN
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
39struct dis_line_entry
40{
41 int line;
42 CORE_ADDR start_pc;
43 CORE_ADDR end_pc;
44};
45
810ecf9f
AC
46/* Like target_read_memory, but slightly different parameters. */
47static int
48dis_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. */
55static void
56dis_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. */
62static void
63dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
64{
65 print_address (addr, info->stream);
66}
67
92df71f0
FN
68/* This variable determines where memory used for disassembly is read from. */
69int 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. */
73static int
74gdb_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
91static int
bde58177 92compare_lines (const void *mle1p, const void *mle2p)
92df71f0
FN
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
108static int
109dump_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;
92df71f0
FN
118 int offset;
119 int line;
3b31d625 120 struct cleanup *ui_out_chain;
92df71f0
FN
121
122 for (pc = low; pc < high;)
123 {
1211bce3
EZ
124 char *filename = NULL;
125 char *name = NULL;
126
92df71f0
FN
127 QUIT;
128 if (how_many >= 0)
129 {
130 if (num_displayed >= how_many)
131 break;
132 else
133 num_displayed++;
134 }
3b31d625 135 ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
92df71f0
FN
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);
3b31d625 158 do_cleanups (ui_out_chain);
92df71f0
FN
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. */
168static void
169do_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;
3b31d625 184 struct cleanup *ui_out_chain;
92df71f0
FN
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
3b31d625 238 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
92df71f0
FN
239
240 for (i = 0; i < newlines; i++)
241 {
3b31d625
EZ
242 struct cleanup *ui_out_tuple_chain = NULL;
243 struct cleanup *ui_out_list_chain = NULL;
92df71f0 244 int close_list = 1;
3b31d625 245
92df71f0
FN
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 {
3b31d625
EZ
254 ui_out_tuple_chain
255 = make_cleanup_ui_out_tuple_begin_end (uiout,
256 "src_and_asm_line");
92df71f0
FN
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 {
3b31d625
EZ
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");
92df71f0
FN
270 print_source_lines (symtab, next_line, next_line + 1,
271 0);
3b31d625
EZ
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);
92df71f0
FN
277 }
278 /* Print the last line and leave list open for
279 asm instructions to be added. */
3b31d625
EZ
280 ui_out_tuple_chain
281 = make_cleanup_ui_out_tuple_begin_end (uiout,
282 "src_and_asm_line");
92df71f0
FN
283 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
284 }
285 }
286 else
287 {
3b31d625
EZ
288 ui_out_tuple_chain
289 = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
92df71f0
FN
290 print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
291 }
292
293 next_line = mle[i].line + 1;
3b31d625
EZ
294 ui_out_list_chain
295 = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
92df71f0
FN
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 {
3b31d625
EZ
305 do_cleanups (ui_out_list_chain);
306 do_cleanups (ui_out_tuple_chain);
92df71f0
FN
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 }
3b31d625 314 do_cleanups (ui_out_chain);
92df71f0
FN
315}
316
317
318static void
319do_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;
3b31d625 324 struct cleanup *ui_out_chain;
92df71f0 325
3b31d625 326 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
92df71f0
FN
327
328 num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
329
3b31d625 330 do_cleanups (ui_out_chain);
92df71f0
FN
331}
332
333void
334gdb_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
26ca4152
AC
364 di.mach = gdbarch_bfd_arch_info (current_gdbarch)->mach;
365 di.endian = gdbarch_byte_order (current_gdbarch);
92df71f0
FN
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
1211bce3
EZ
384 || strcmp (target_shortname, "core") == 0
385 || strstr (target_shortname, "-thread") != NULL)
92df71f0
FN
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}
810ecf9f
AC
416
417\f
418/* FIXME: cagney/2003-04-28: This global deprecated_tm_print_insn_info
419 is going away. */
420disassemble_info deprecated_tm_print_insn_info;
421
422extern void _initialize_disasm (void);
423
424void
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}
This page took 0.085278 seconds and 4 git commands to generate.