gdb/
[deliverable/binutils-gdb.git] / gdb / disasm.c
1 /* Disassemble support for GDB.
2
3 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
4 Free Software Foundation, Inc.
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
20 Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
22
23 #include "defs.h"
24 #include "target.h"
25 #include "value.h"
26 #include "ui-out.h"
27 #include "gdb_string.h"
28 #include "disasm.h"
29 #include "gdbcore.h"
30 #include "dis-asm.h"
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
41 struct dis_line_entry
42 {
43 int line;
44 CORE_ADDR start_pc;
45 CORE_ADDR end_pc;
46 };
47
48 /* Like target_read_memory, but slightly different parameters. */
49 static int
50 dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
51 struct disassemble_info *info)
52 {
53 return target_read_memory (memaddr, myaddr, len);
54 }
55
56 /* Like memory_error with slightly different parameters. */
57 static void
58 dis_asm_memory_error (int status, bfd_vma memaddr,
59 struct disassemble_info *info)
60 {
61 memory_error (status, memaddr);
62 }
63
64 /* Like print_address with slightly different parameters. */
65 static void
66 dis_asm_print_address (bfd_vma addr, struct disassemble_info *info)
67 {
68 print_address (addr, info->stream);
69 }
70
71 static int
72 compare_lines (const void *mle1p, const void *mle2p)
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
88 static int
89 dump_insns (struct ui_out *uiout, struct disassemble_info * di,
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;
98 int offset;
99 int line;
100 struct cleanup *ui_out_chain;
101
102 for (pc = low; pc < high;)
103 {
104 char *filename = NULL;
105 char *name = NULL;
106
107 QUIT;
108 if (how_many >= 0)
109 {
110 if (num_displayed >= how_many)
111 break;
112 else
113 num_displayed++;
114 }
115 ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
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 }
129 else
130 ui_out_text (uiout, ":\t");
131
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);
141 do_cleanups (ui_out_chain);
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. */
151 static void
152 do_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;
167 struct cleanup *ui_out_chain;
168 struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
169 struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
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
223 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
224
225 for (i = 0; i < newlines; i++)
226 {
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 {
235 ui_out_tuple_chain
236 = make_cleanup_ui_out_tuple_begin_end (uiout,
237 "src_and_asm_line");
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 {
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");
251 print_source_lines (symtab, next_line, next_line + 1,
252 0);
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);
258 }
259 /* Print the last line and leave list open for
260 asm instructions to be added. */
261 ui_out_tuple_chain
262 = make_cleanup_ui_out_tuple_begin_end (uiout,
263 "src_and_asm_line");
264 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
265 }
266 }
267 else
268 {
269 ui_out_tuple_chain
270 = make_cleanup_ui_out_tuple_begin_end (uiout, "src_and_asm_line");
271 print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
272 }
273
274 next_line = mle[i].line + 1;
275 ui_out_list_chain
276 = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
277 }
278
279 num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
280 how_many, stb);
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)
285 {
286 do_cleanups (ui_out_list_chain);
287 do_cleanups (ui_out_tuple_chain);
288 ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
289 ui_out_list_chain = make_cleanup (null_cleanup, 0);
290 ui_out_text (uiout, "\n");
291 }
292 if (how_many >= 0 && num_displayed >= how_many)
293 break;
294 }
295 do_cleanups (ui_out_chain);
296 }
297
298
299 static void
300 do_assembly_only (struct ui_out *uiout, struct disassemble_info * di,
301 CORE_ADDR low, CORE_ADDR high,
302 int how_many, struct ui_stream *stb)
303 {
304 int num_displayed = 0;
305 struct cleanup *ui_out_chain;
306
307 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
308
309 num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
310
311 do_cleanups (ui_out_chain);
312 }
313
314 /* Initialize the disassemble info struct ready for the specified
315 stream. */
316
317 static int ATTR_FORMAT (printf, 2, 3)
318 fprintf_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
328 static struct disassemble_info
329 gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
330 {
331 struct disassemble_info di;
332 init_disassemble_info (&di, file, fprintf_disasm);
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
339 was a growing list of exceptions though). Unfortunately, the
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;
345 di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
346 di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
347 di.endian = gdbarch_byte_order (gdbarch);
348 disassemble_init_for_target (&di);
349 return di;
350 }
351
352 void
353 gdb_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);
361 struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stb->stream);
362 /* To collect the instruction outputted from opcodes. */
363 struct symtab *symtab = NULL;
364 struct linetable_entry *le = NULL;
365 int nlines = -1;
366
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
385 do_cleanups (cleanups);
386 gdb_flush (gdb_stdout);
387 }
388
389 /* Print the instruction at address MEMADDR in debugged memory,
390 on STREAM. Returns length of the instruction, in bytes. */
391
392 int
393 gdb_print_insn (CORE_ADDR memaddr, struct ui_file *stream)
394 {
395 struct disassemble_info di = gdb_disassemble_info (current_gdbarch, stream);
396 return TARGET_PRINT_INSN (memaddr, &di);
397 }
This page took 0.040741 seconds and 4 git commands to generate.