]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/disasm.c
e3d3349200e64455ceed3aeac44b696ce201f417
[thirdparty/binutils-gdb.git] / gdb / disasm.c
1 /* Disassemble support for GDB.
2
3 Copyright (C) 2000-2005, 2007-2012 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 3 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, see <http://www.gnu.org/licenses/>. */
19
20 #include "defs.h"
21 #include "target.h"
22 #include "value.h"
23 #include "ui-out.h"
24 #include "gdb_string.h"
25 #include "disasm.h"
26 #include "gdbcore.h"
27 #include "dis-asm.h"
28
29 /* Disassemble functions.
30 FIXME: We should get rid of all the duplicate code in gdb that does
31 the same thing: disassemble_command() and the gdbtk variation. */
32
33 /* This Structure is used to store line number information.
34 We need a different sort of line table from the normal one cuz we can't
35 depend upon implicit line-end pc's for lines to do the
36 reordering in this function. */
37
38 struct dis_line_entry
39 {
40 int line;
41 CORE_ADDR start_pc;
42 CORE_ADDR end_pc;
43 };
44
45 /* Like target_read_memory, but slightly different parameters. */
46 static int
47 dis_asm_read_memory (bfd_vma memaddr, gdb_byte *myaddr, unsigned int len,
48 struct disassemble_info *info)
49 {
50 return target_read_memory (memaddr, myaddr, len);
51 }
52
53 /* Like memory_error with slightly different parameters. */
54 static void
55 dis_asm_memory_error (int status, bfd_vma memaddr,
56 struct 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 struct gdbarch *gdbarch = info->application_data;
66
67 print_address (gdbarch, addr, info->stream);
68 }
69
70 static int
71 compare_lines (const void *mle1p, const void *mle2p)
72 {
73 struct dis_line_entry *mle1, *mle2;
74 int val;
75
76 mle1 = (struct dis_line_entry *) mle1p;
77 mle2 = (struct dis_line_entry *) mle2p;
78
79 /* End of sequence markers have a line number of 0 but don't want to
80 be sorted to the head of the list, instead sort by PC. */
81 if (mle1->line == 0 || mle2->line == 0)
82 {
83 val = mle1->start_pc - mle2->start_pc;
84 if (val == 0)
85 val = mle1->line - mle2->line;
86 }
87 else
88 {
89 val = mle1->line - mle2->line;
90 if (val == 0)
91 val = mle1->start_pc - mle2->start_pc;
92 }
93 return val;
94 }
95
96 static int
97 dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
98 struct disassemble_info * di,
99 CORE_ADDR low, CORE_ADDR high,
100 int how_many, int flags, struct ui_file *stb)
101 {
102 int num_displayed = 0;
103 CORE_ADDR pc;
104
105 /* parts of the symbolic representation of the address */
106 int unmapped;
107 int offset;
108 int line;
109 struct cleanup *ui_out_chain;
110
111 for (pc = low; pc < high;)
112 {
113 char *filename = NULL;
114 char *name = NULL;
115
116 QUIT;
117 if (how_many >= 0)
118 {
119 if (num_displayed >= how_many)
120 break;
121 else
122 num_displayed++;
123 }
124 ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
125 ui_out_text (uiout, pc_prefix (pc));
126 ui_out_field_core_addr (uiout, "address", gdbarch, pc);
127
128 if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename,
129 &line, &unmapped))
130 {
131 /* We don't care now about line, filename and
132 unmapped. But we might in the future. */
133 ui_out_text (uiout, " <");
134 if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
135 ui_out_field_string (uiout, "func-name", name);
136 ui_out_text (uiout, "+");
137 ui_out_field_int (uiout, "offset", offset);
138 ui_out_text (uiout, ">:\t");
139 }
140 else
141 ui_out_text (uiout, ":\t");
142
143 if (filename != NULL)
144 xfree (filename);
145 if (name != NULL)
146 xfree (name);
147
148 ui_file_rewind (stb);
149 if (flags & DISASSEMBLY_RAW_INSN)
150 {
151 CORE_ADDR old_pc = pc;
152 bfd_byte data;
153 int status;
154 const char *spacer = "";
155
156 /* Build the opcodes using a temporary stream so we can
157 write them out in a single go for the MI. */
158 struct ui_file *opcode_stream = mem_fileopen ();
159 struct cleanup *cleanups =
160 make_cleanup_ui_file_delete (opcode_stream);
161
162 pc += gdbarch_print_insn (gdbarch, pc, di);
163 for (;old_pc < pc; old_pc++)
164 {
165 status = (*di->read_memory_func) (old_pc, &data, 1, di);
166 if (status != 0)
167 (*di->memory_error_func) (status, old_pc, di);
168 fprintf_filtered (opcode_stream, "%s%02x",
169 spacer, (unsigned) data);
170 spacer = " ";
171 }
172 ui_out_field_stream (uiout, "opcodes", opcode_stream);
173 ui_out_text (uiout, "\t");
174
175 do_cleanups (cleanups);
176 }
177 else
178 pc += gdbarch_print_insn (gdbarch, pc, di);
179 ui_out_field_stream (uiout, "inst", stb);
180 ui_file_rewind (stb);
181 do_cleanups (ui_out_chain);
182 ui_out_text (uiout, "\n");
183 }
184 return num_displayed;
185 }
186
187 /* The idea here is to present a source-O-centric view of a
188 function to the user. This means that things are presented
189 in source order, with (possibly) out of order assembly
190 immediately following. */
191
192 static void
193 do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout,
194 struct disassemble_info *di, int nlines,
195 struct linetable_entry *le,
196 CORE_ADDR low, CORE_ADDR high,
197 struct symtab *symtab,
198 int how_many, int flags, struct ui_file *stb)
199 {
200 int newlines = 0;
201 struct dis_line_entry *mle;
202 struct symtab_and_line sal;
203 int i;
204 int out_of_order = 0;
205 int next_line = 0;
206 int num_displayed = 0;
207 struct cleanup *ui_out_chain;
208 struct cleanup *ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
209 struct cleanup *ui_out_list_chain = make_cleanup (null_cleanup, 0);
210
211 mle = (struct dis_line_entry *) alloca (nlines
212 * sizeof (struct dis_line_entry));
213
214 /* Copy linetable entries for this function into our data
215 structure, creating end_pc's and setting out_of_order as
216 appropriate. */
217
218 /* First, skip all the preceding functions. */
219
220 for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
221
222 /* Now, copy all entries before the end of this function. */
223
224 for (; i < nlines - 1 && le[i].pc < high; i++)
225 {
226 if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
227 continue; /* Ignore duplicates. */
228
229 /* Skip any end-of-function markers. */
230 if (le[i].line == 0)
231 continue;
232
233 mle[newlines].line = le[i].line;
234 if (le[i].line > le[i + 1].line)
235 out_of_order = 1;
236 mle[newlines].start_pc = le[i].pc;
237 mle[newlines].end_pc = le[i + 1].pc;
238 newlines++;
239 }
240
241 /* If we're on the last line, and it's part of the function,
242 then we need to get the end pc in a special way. */
243
244 if (i == nlines - 1 && le[i].pc < high)
245 {
246 mle[newlines].line = le[i].line;
247 mle[newlines].start_pc = le[i].pc;
248 sal = find_pc_line (le[i].pc, 0);
249 mle[newlines].end_pc = sal.end;
250 newlines++;
251 }
252
253 /* Now, sort mle by line #s (and, then by addresses within
254 lines). */
255
256 if (out_of_order)
257 qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
258
259 /* Now, for each line entry, emit the specified lines (unless
260 they have been emitted before), followed by the assembly code
261 for that line. */
262
263 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
264
265 for (i = 0; i < newlines; i++)
266 {
267 /* Print out everything from next_line to the current line. */
268 if (mle[i].line >= next_line)
269 {
270 if (next_line != 0)
271 {
272 /* Just one line to print. */
273 if (next_line == mle[i].line)
274 {
275 ui_out_tuple_chain
276 = make_cleanup_ui_out_tuple_begin_end (uiout,
277 "src_and_asm_line");
278 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
279 }
280 else
281 {
282 /* Several source lines w/o asm instructions associated. */
283 for (; next_line < mle[i].line; next_line++)
284 {
285 struct cleanup *ui_out_list_chain_line;
286 struct cleanup *ui_out_tuple_chain_line;
287
288 ui_out_tuple_chain_line
289 = make_cleanup_ui_out_tuple_begin_end (uiout,
290 "src_and_asm_line");
291 print_source_lines (symtab, next_line, next_line + 1,
292 0);
293 ui_out_list_chain_line
294 = make_cleanup_ui_out_list_begin_end (uiout,
295 "line_asm_insn");
296 do_cleanups (ui_out_list_chain_line);
297 do_cleanups (ui_out_tuple_chain_line);
298 }
299 /* Print the last line and leave list open for
300 asm instructions to be added. */
301 ui_out_tuple_chain
302 = make_cleanup_ui_out_tuple_begin_end (uiout,
303 "src_and_asm_line");
304 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
305 }
306 }
307 else
308 {
309 ui_out_tuple_chain
310 = make_cleanup_ui_out_tuple_begin_end (uiout,
311 "src_and_asm_line");
312 print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
313 }
314
315 next_line = mle[i].line + 1;
316 ui_out_list_chain
317 = make_cleanup_ui_out_list_begin_end (uiout, "line_asm_insn");
318 }
319
320 num_displayed += dump_insns (gdbarch, uiout, di,
321 mle[i].start_pc, mle[i].end_pc,
322 how_many, flags, stb);
323
324 /* When we've reached the end of the mle array, or we've seen the last
325 assembly range for this source line, close out the list/tuple. */
326 if (i == (newlines - 1) || mle[i + 1].line > mle[i].line)
327 {
328 do_cleanups (ui_out_list_chain);
329 do_cleanups (ui_out_tuple_chain);
330 ui_out_tuple_chain = make_cleanup (null_cleanup, 0);
331 ui_out_list_chain = make_cleanup (null_cleanup, 0);
332 ui_out_text (uiout, "\n");
333 }
334 if (how_many >= 0 && num_displayed >= how_many)
335 break;
336 }
337 do_cleanups (ui_out_chain);
338 }
339
340
341 static void
342 do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout,
343 struct disassemble_info * di,
344 CORE_ADDR low, CORE_ADDR high,
345 int how_many, int flags, struct ui_file *stb)
346 {
347 int num_displayed = 0;
348 struct cleanup *ui_out_chain;
349
350 ui_out_chain = make_cleanup_ui_out_list_begin_end (uiout, "asm_insns");
351
352 num_displayed = dump_insns (gdbarch, uiout, di, low, high, how_many,
353 flags, stb);
354
355 do_cleanups (ui_out_chain);
356 }
357
358 /* Initialize the disassemble info struct ready for the specified
359 stream. */
360
361 static int ATTRIBUTE_PRINTF (2, 3)
362 fprintf_disasm (void *stream, const char *format, ...)
363 {
364 va_list args;
365
366 va_start (args, format);
367 vfprintf_filtered (stream, format, args);
368 va_end (args);
369 /* Something non -ve. */
370 return 0;
371 }
372
373 static struct disassemble_info
374 gdb_disassemble_info (struct gdbarch *gdbarch, struct ui_file *file)
375 {
376 struct disassemble_info di;
377
378 init_disassemble_info (&di, file, fprintf_disasm);
379 di.flavour = bfd_target_unknown_flavour;
380 di.memory_error_func = dis_asm_memory_error;
381 di.print_address_func = dis_asm_print_address;
382 /* NOTE: cagney/2003-04-28: The original code, from the old Insight
383 disassembler had a local optomization here. By default it would
384 access the executable file, instead of the target memory (there
385 was a growing list of exceptions though). Unfortunately, the
386 heuristic was flawed. Commands like "disassemble &variable"
387 didn't work as they relied on the access going to the target.
388 Further, it has been supperseeded by trust-read-only-sections
389 (although that should be superseeded by target_trust..._p()). */
390 di.read_memory_func = dis_asm_read_memory;
391 di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
392 di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
393 di.endian = gdbarch_byte_order (gdbarch);
394 di.endian_code = gdbarch_byte_order_for_code (gdbarch);
395 di.application_data = gdbarch;
396 disassemble_init_for_target (&di);
397 return di;
398 }
399
400 void
401 gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout,
402 char *file_string, int flags, int how_many,
403 CORE_ADDR low, CORE_ADDR high)
404 {
405 struct ui_file *stb = mem_fileopen ();
406 struct cleanup *cleanups = make_cleanup_ui_file_delete (stb);
407 struct disassemble_info di = gdb_disassemble_info (gdbarch, stb);
408 /* To collect the instruction outputted from opcodes. */
409 struct symtab *symtab = NULL;
410 struct linetable_entry *le = NULL;
411 int nlines = -1;
412
413 /* Assume symtab is valid for whole PC range. */
414 symtab = find_pc_symtab (low);
415
416 if (symtab != NULL && symtab->linetable != NULL)
417 {
418 /* Convert the linetable to a bunch of my_line_entry's. */
419 le = symtab->linetable->item;
420 nlines = symtab->linetable->nitems;
421 }
422
423 if (!(flags & DISASSEMBLY_SOURCE) || nlines <= 0
424 || symtab == NULL || symtab->linetable == NULL)
425 do_assembly_only (gdbarch, uiout, &di, low, high, how_many, flags, stb);
426
427 else if (flags & DISASSEMBLY_SOURCE)
428 do_mixed_source_and_assembly (gdbarch, uiout, &di, nlines, le, low,
429 high, symtab, how_many, flags, stb);
430
431 do_cleanups (cleanups);
432 gdb_flush (gdb_stdout);
433 }
434
435 /* Print the instruction at address MEMADDR in debugged memory,
436 on STREAM. Returns the length of the instruction, in bytes,
437 and, if requested, the number of branch delay slot instructions. */
438
439 int
440 gdb_print_insn (struct gdbarch *gdbarch, CORE_ADDR memaddr,
441 struct ui_file *stream, int *branch_delay_insns)
442 {
443 struct disassemble_info di;
444 int length;
445
446 di = gdb_disassemble_info (gdbarch, stream);
447 length = gdbarch_print_insn (gdbarch, memaddr, &di);
448 if (branch_delay_insns)
449 {
450 if (di.insn_info_valid)
451 *branch_delay_insns = di.branch_delay_insns;
452 else
453 *branch_delay_insns = 0;
454 }
455 return length;
456 }
457
458 static void
459 do_ui_file_delete (void *arg)
460 {
461 ui_file_delete (arg);
462 }
463
464 /* Return the length in bytes of the instruction at address MEMADDR in
465 debugged memory. */
466
467 int
468 gdb_insn_length (struct gdbarch *gdbarch, CORE_ADDR addr)
469 {
470 static struct ui_file *null_stream = NULL;
471
472 /* Dummy file descriptor for the disassembler. */
473 if (!null_stream)
474 {
475 null_stream = ui_file_new ();
476 make_final_cleanup (do_ui_file_delete, null_stream);
477 }
478
479 return gdb_print_insn (gdbarch, addr, null_stream, NULL);
480 }
481
482 /* fprintf-function for gdb_buffered_insn_length. This function is a
483 nop, we don't want to print anything, we just want to compute the
484 length of the insn. */
485
486 static int ATTRIBUTE_PRINTF (2, 3)
487 gdb_buffered_insn_length_fprintf (void *stream, const char *format, ...)
488 {
489 return 0;
490 }
491
492 /* Initialize a struct disassemble_info for gdb_buffered_insn_length. */
493
494 static void
495 gdb_buffered_insn_length_init_dis (struct gdbarch *gdbarch,
496 struct disassemble_info *di,
497 const gdb_byte *insn, int max_len,
498 CORE_ADDR addr)
499 {
500 init_disassemble_info (di, NULL, gdb_buffered_insn_length_fprintf);
501
502 /* init_disassemble_info installs buffer_read_memory, etc.
503 so we don't need to do that here.
504 The cast is necessary until disassemble_info is const-ified. */
505 di->buffer = (gdb_byte *) insn;
506 di->buffer_length = max_len;
507 di->buffer_vma = addr;
508
509 di->arch = gdbarch_bfd_arch_info (gdbarch)->arch;
510 di->mach = gdbarch_bfd_arch_info (gdbarch)->mach;
511 di->endian = gdbarch_byte_order (gdbarch);
512 di->endian_code = gdbarch_byte_order_for_code (gdbarch);
513
514 disassemble_init_for_target (di);
515 }
516
517 /* Return the length in bytes of INSN. MAX_LEN is the size of the
518 buffer containing INSN. */
519
520 int
521 gdb_buffered_insn_length (struct gdbarch *gdbarch,
522 const gdb_byte *insn, int max_len, CORE_ADDR addr)
523 {
524 struct disassemble_info di;
525
526 gdb_buffered_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
527
528 return gdbarch_print_insn (gdbarch, addr, &di);
529 }