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