* disasm.c: New file.
[deliverable/binutils-gdb.git] / gdb / disasm.c
CommitLineData
92df71f0
FN
1/* Disassemble support for GDB.
2 Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21#include "defs.h"
22#include "target.h"
23#include "value.h"
24#include "ui-out.h"
25#include "gdb_string.h"
26
27#include "disasm.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
38struct dis_line_entry
39{
40 int line;
41 CORE_ADDR start_pc;
42 CORE_ADDR end_pc;
43};
44
45/* This variable determines where memory used for disassembly is read from. */
46int gdb_disassemble_from_exec = -1;
47
48/* This is the memory_read_func for gdb_disassemble when we are
49 disassembling from the exec file. */
50static int
51gdb_dis_asm_read_memory (bfd_vma memaddr, bfd_byte * myaddr,
52 unsigned int len, disassemble_info * info)
53{
54 extern struct target_ops exec_ops;
55 int res;
56
57 errno = 0;
58 res = xfer_memory (memaddr, myaddr, len, 0, 0, &exec_ops);
59
60 if (res == len)
61 return 0;
62 else if (errno == 0)
63 return EIO;
64 else
65 return errno;
66}
67
68static int
69compare_lines (const PTR mle1p, const PTR mle2p)
70{
71 struct dis_line_entry *mle1, *mle2;
72 int val;
73
74 mle1 = (struct dis_line_entry *) mle1p;
75 mle2 = (struct dis_line_entry *) mle2p;
76
77 val = mle1->line - mle2->line;
78
79 if (val != 0)
80 return val;
81
82 return mle1->start_pc - mle2->start_pc;
83}
84
85static int
86dump_insns (struct ui_out *uiout, disassemble_info * di,
87 CORE_ADDR low, CORE_ADDR high,
88 int how_many, struct ui_stream *stb)
89{
90 int num_displayed = 0;
91 CORE_ADDR pc;
92
93 /* parts of the symbolic representation of the address */
94 int unmapped;
95 char *filename = NULL;
96 char *name = NULL;
97 int offset;
98 int line;
99
100 for (pc = low; pc < high;)
101 {
102 QUIT;
103 if (how_many >= 0)
104 {
105 if (num_displayed >= how_many)
106 break;
107 else
108 num_displayed++;
109 }
110 ui_out_tuple_begin (uiout, NULL);
111 ui_out_field_core_addr (uiout, "address", pc);
112
113 if (!build_address_symbolic (pc, 0, &name, &offset, &filename,
114 &line, &unmapped))
115 {
116 /* We don't care now about line, filename and
117 unmapped. But we might in the future. */
118 ui_out_text (uiout, " <");
119 ui_out_field_string (uiout, "func-name", name);
120 ui_out_text (uiout, "+");
121 ui_out_field_int (uiout, "offset", offset);
122 ui_out_text (uiout, ">:\t");
123 }
124 if (filename != NULL)
125 xfree (filename);
126 if (name != NULL)
127 xfree (name);
128
129 ui_file_rewind (stb->stream);
130 pc += TARGET_PRINT_INSN (pc, di);
131 ui_out_field_stream (uiout, "inst", stb);
132 ui_file_rewind (stb->stream);
133 ui_out_tuple_end (uiout);
134 ui_out_text (uiout, "\n");
135 }
136 return num_displayed;
137}
138
139/* The idea here is to present a source-O-centric view of a
140 function to the user. This means that things are presented
141 in source order, with (possibly) out of order assembly
142 immediately following. */
143static void
144do_mixed_source_and_assembly (struct ui_out *uiout,
145 struct disassemble_info *di, int nlines,
146 struct linetable_entry *le,
147 CORE_ADDR low, CORE_ADDR high,
148 struct symtab *symtab,
149 int how_many, struct ui_stream *stb)
150{
151 int newlines = 0;
152 struct dis_line_entry *mle;
153 struct symtab_and_line sal;
154 int i;
155 int out_of_order = 0;
156 int next_line = 0;
157 CORE_ADDR pc;
158 int num_displayed = 0;
159
160 mle = (struct dis_line_entry *) alloca (nlines
161 * sizeof (struct dis_line_entry));
162
163 /* Copy linetable entries for this function into our data
164 structure, creating end_pc's and setting out_of_order as
165 appropriate. */
166
167 /* First, skip all the preceding functions. */
168
169 for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
170
171 /* Now, copy all entries before the end of this function. */
172
173 for (; i < nlines - 1 && le[i].pc < high; i++)
174 {
175 if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
176 continue; /* Ignore duplicates */
177
178 /* Skip any end-of-function markers. */
179 if (le[i].line == 0)
180 continue;
181
182 mle[newlines].line = le[i].line;
183 if (le[i].line > le[i + 1].line)
184 out_of_order = 1;
185 mle[newlines].start_pc = le[i].pc;
186 mle[newlines].end_pc = le[i + 1].pc;
187 newlines++;
188 }
189
190 /* If we're on the last line, and it's part of the function,
191 then we need to get the end pc in a special way. */
192
193 if (i == nlines - 1 && le[i].pc < high)
194 {
195 mle[newlines].line = le[i].line;
196 mle[newlines].start_pc = le[i].pc;
197 sal = find_pc_line (le[i].pc, 0);
198 mle[newlines].end_pc = sal.end;
199 newlines++;
200 }
201
202 /* Now, sort mle by line #s (and, then by addresses within
203 lines). */
204
205 if (out_of_order)
206 qsort (mle, newlines, sizeof (struct dis_line_entry), compare_lines);
207
208 /* Now, for each line entry, emit the specified lines (unless
209 they have been emitted before), followed by the assembly code
210 for that line. */
211
212 ui_out_list_begin (uiout, "asm_insns");
213
214 for (i = 0; i < newlines; i++)
215 {
216 int close_list = 1;
217 /* Print out everything from next_line to the current line. */
218 if (mle[i].line >= next_line)
219 {
220 if (next_line != 0)
221 {
222 /* Just one line to print. */
223 if (next_line == mle[i].line)
224 {
225 ui_out_tuple_begin (uiout, "src_and_asm_line");
226 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
227 }
228 else
229 {
230 /* Several source lines w/o asm instructions associated. */
231 for (; next_line < mle[i].line; next_line++)
232 {
233 ui_out_tuple_begin (uiout, "src_and_asm_line");
234 print_source_lines (symtab, next_line, next_line + 1,
235 0);
236 ui_out_list_begin (uiout, "line_asm_insn");
237 ui_out_list_end (uiout);
238 ui_out_tuple_end (uiout);
239 }
240 /* Print the last line and leave list open for
241 asm instructions to be added. */
242 ui_out_tuple_begin (uiout, "src_and_asm_line");
243 print_source_lines (symtab, next_line, mle[i].line + 1, 0);
244 }
245 }
246 else
247 {
248 ui_out_tuple_begin (uiout, "src_and_asm_line");
249 print_source_lines (symtab, mle[i].line, mle[i].line + 1, 0);
250 }
251
252 next_line = mle[i].line + 1;
253 ui_out_list_begin (uiout, "line_asm_insn");
254 /* Don't close the list if the lines are not in order. */
255 if (i < (newlines - 1) && mle[i + 1].line <= mle[i].line)
256 close_list = 0;
257 }
258
259 num_displayed += dump_insns (uiout, di, mle[i].start_pc, mle[i].end_pc,
260 how_many, stb);
261 if (close_list)
262 {
263 ui_out_list_end (uiout);
264 ui_out_tuple_end (uiout);
265 ui_out_text (uiout, "\n");
266 close_list = 0;
267 }
268 if (how_many >= 0)
269 if (num_displayed >= how_many)
270 break;
271 }
272 ui_out_list_end (uiout);
273}
274
275
276static void
277do_assembly_only (struct ui_out *uiout, disassemble_info * di,
278 CORE_ADDR low, CORE_ADDR high,
279 int how_many, struct ui_stream *stb)
280{
281 int num_displayed = 0;
282
283 ui_out_list_begin (uiout, "asm_insns");
284
285 num_displayed = dump_insns (uiout, di, low, high, how_many, stb);
286
287 ui_out_list_end (uiout);
288}
289
290void
291gdb_disassembly (struct ui_out *uiout,
292 char *file_string,
293 int line_num,
294 int mixed_source_and_assembly,
295 int how_many, CORE_ADDR low, CORE_ADDR high)
296{
297 static disassemble_info di;
298 static int di_initialized;
299 /* To collect the instruction outputted from opcodes. */
300 static struct ui_stream *stb = NULL;
301 struct symtab *symtab = NULL;
302 struct linetable_entry *le = NULL;
303 int nlines = -1;
304
305 if (!di_initialized)
306 {
307 /* We don't add a cleanup for this, because the allocation of
308 the stream is done once only for each gdb run, and we need to
309 keep it around until the end. Hopefully there won't be any
310 errors in the init code below, that make this function bail
311 out. */
312 stb = ui_out_stream_new (uiout);
313 INIT_DISASSEMBLE_INFO_NO_ARCH (di, stb->stream,
314 (fprintf_ftype) fprintf_unfiltered);
315 di.flavour = bfd_target_unknown_flavour;
316 di.memory_error_func = dis_asm_memory_error;
317 di.print_address_func = dis_asm_print_address;
318 di_initialized = 1;
319 }
320
321 di.mach = TARGET_PRINT_INSN_INFO->mach;
322 if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
323 di.endian = BFD_ENDIAN_BIG;
324 else
325 di.endian = BFD_ENDIAN_LITTLE;
326
327 /* If gdb_disassemble_from_exec == -1, then we use the following heuristic to
328 determine whether or not to do disassembly from target memory or from the
329 exec file:
330
331 If we're debugging a local process, read target memory, instead of the
332 exec file. This makes disassembly of functions in shared libs work
333 correctly. Also, read target memory if we are debugging native threads.
334
335 Else, we're debugging a remote process, and should disassemble from the
336 exec file for speed. However, this is no good if the target modifies its
337 code (for relocation, or whatever). */
338
339 if (gdb_disassemble_from_exec == -1)
340 {
341 if (strcmp (target_shortname, "child") == 0
342 || strcmp (target_shortname, "procfs") == 0
343 || strcmp (target_shortname, "vxprocess") == 0
344 || strstr (target_shortname, "-threads") != NULL)
345 gdb_disassemble_from_exec = 0; /* It's a child process, read inferior mem */
346 else
347 gdb_disassemble_from_exec = 1; /* It's remote, read the exec file */
348 }
349
350 if (gdb_disassemble_from_exec)
351 di.read_memory_func = gdb_dis_asm_read_memory;
352 else
353 di.read_memory_func = dis_asm_read_memory;
354
355 /* Assume symtab is valid for whole PC range */
356 symtab = find_pc_symtab (low);
357
358 if (symtab != NULL && symtab->linetable != NULL)
359 {
360 /* Convert the linetable to a bunch of my_line_entry's. */
361 le = symtab->linetable->item;
362 nlines = symtab->linetable->nitems;
363 }
364
365 if (!mixed_source_and_assembly || nlines <= 0
366 || symtab == NULL || symtab->linetable == NULL)
367 do_assembly_only (uiout, &di, low, high, how_many, stb);
368
369 else if (mixed_source_and_assembly)
370 do_mixed_source_and_assembly (uiout, &di, nlines, le, low,
371 high, symtab, how_many, stb);
372
373 gdb_flush (gdb_stdout);
374}
This page took 0.037587 seconds and 4 git commands to generate.