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