2009-10-19 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / tui / tui-disasm.c
CommitLineData
f377b406 1/* Disassembly display.
f33c6cbf 2
0fb0cc75 3 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009
6aba47ca 4 Free Software Foundation, Inc.
f33c6cbf 5
f377b406
SC
6 Contributed by Hewlett-Packard Company.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
a9762ec7 12 the Free Software Foundation; either version 3 of the License, or
f377b406
SC
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
a9762ec7 21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
22
23#include "defs.h"
24#include "symtab.h"
25#include "breakpoint.h"
26#include "frame.h"
fd0407d6 27#include "value.h"
52575520 28#include "source.h"
f70a7d61 29#include "disasm.h"
6d012f14 30#include "gdb_string.h"
d7b2e967
AC
31#include "tui/tui.h"
32#include "tui/tui-data.h"
33#include "tui/tui-win.h"
34#include "tui/tui-layout.h"
35#include "tui/tui-winsource.h"
36#include "tui/tui-stack.h"
37#include "tui/tui-file.h"
2c0b251b 38#include "tui/tui-disasm.h"
6c95b8df 39#include "progspace.h"
c906108c 40
6a83354a 41#include "gdb_curses.h"
96ec9981 42
aec2f747
SC
43struct tui_asm_line
44{
45 CORE_ADDR addr;
5b6fe301
MS
46 char *addr_string;
47 char *insn;
aec2f747
SC
48};
49
50/* Function to set the disassembly window's content.
51 Disassemble count lines starting at pc.
52 Return address of the count'th instruction after pc. */
53static CORE_ADDR
13274fc3 54tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines,
08ef48c5 55 CORE_ADDR pc, int count)
aec2f747
SC
56{
57 struct ui_file *gdb_dis_out;
c906108c 58
1cc6d956 59 /* Now init the ui_file structure. */
aec2f747
SC
60 gdb_dis_out = tui_sfileopen (256);
61
1cc6d956 62 /* Now construct each line. */
4cfcaf21 63 for (; count > 0; count--, asm_lines++)
aec2f747 64 {
4cfcaf21
JB
65 if (asm_lines->addr_string)
66 xfree (asm_lines->addr_string);
67 if (asm_lines->insn)
68 xfree (asm_lines->insn);
aec2f747 69
5af949e3 70 print_address (gdbarch, pc, gdb_dis_out);
4cfcaf21
JB
71 asm_lines->addr = pc;
72 asm_lines->addr_string = xstrdup (tui_file_get_strbuf (gdb_dis_out));
aec2f747
SC
73
74 ui_file_rewind (gdb_dis_out);
75
13274fc3 76 pc = pc + gdb_print_insn (gdbarch, pc, gdb_dis_out, NULL);
aec2f747 77
4cfcaf21 78 asm_lines->insn = xstrdup (tui_file_get_strbuf (gdb_dis_out));
aec2f747 79
1cc6d956 80 /* Reset the buffer to empty. */
aec2f747
SC
81 ui_file_rewind (gdb_dis_out);
82 }
83 ui_file_delete (gdb_dis_out);
84 return pc;
85}
86
1cc6d956
MS
87/* Find the disassembly address that corresponds to FROM lines above
88 or below the PC. Variable sized instructions are taken into
89 account by the algorithm. */
aec2f747 90static CORE_ADDR
13274fc3 91tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
aec2f747 92{
d02c80cd 93 CORE_ADDR new_low;
6ba8e26f 94 int max_lines;
aec2f747 95 int i;
5b6fe301 96 struct tui_asm_line *asm_lines;
aec2f747 97
6ba8e26f
AC
98 max_lines = (from > 0) ? from : - from;
99 if (max_lines <= 1)
aec2f747
SC
100 return pc;
101
4cfcaf21 102 asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line)
6ba8e26f 103 * max_lines);
4cfcaf21 104 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
aec2f747 105
6ba8e26f 106 new_low = pc;
aec2f747
SC
107 if (from > 0)
108 {
13274fc3 109 tui_disassemble (gdbarch, asm_lines, pc, max_lines);
4cfcaf21 110 new_low = asm_lines[max_lines - 1].addr;
aec2f747
SC
111 }
112 else
113 {
114 CORE_ADDR last_addr;
115 int pos;
5b6fe301 116 struct minimal_symbol *msymbol;
aec2f747 117
1cc6d956
MS
118 /* Find backward an address which is a symbol and for which
119 disassembling from that address will fill completely the
120 window. */
6ba8e26f 121 pos = max_lines - 1;
aec2f747 122 do {
6ba8e26f
AC
123 new_low -= 1 * max_lines;
124 msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0);
aec2f747
SC
125
126 if (msymbol)
6ba8e26f 127 new_low = SYMBOL_VALUE_ADDRESS (msymbol);
aec2f747 128 else
6ba8e26f 129 new_low += 1 * max_lines;
aec2f747 130
13274fc3 131 tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
4cfcaf21 132 last_addr = asm_lines[pos].addr;
aec2f747
SC
133 } while (last_addr > pc && msymbol);
134
1cc6d956
MS
135 /* Scan forward disassembling one instruction at a time until
136 the last visible instruction of the window matches the pc.
137 We keep the disassembled instructions in the 'lines' window
138 and shift it downward (increasing its addresses). */
aec2f747
SC
139 if (last_addr < pc)
140 do
141 {
142 CORE_ADDR next_addr;
143
144 pos++;
6ba8e26f 145 if (pos >= max_lines)
aec2f747
SC
146 pos = 0;
147
13274fc3
UW
148 next_addr = tui_disassemble (gdbarch, &asm_lines[pos],
149 last_addr, 1);
aec2f747
SC
150
151 /* If there are some problems while disassembling exit. */
152 if (next_addr <= last_addr)
153 break;
154 last_addr = next_addr;
155 } while (last_addr <= pc);
156 pos++;
6ba8e26f 157 if (pos >= max_lines)
aec2f747 158 pos = 0;
4cfcaf21 159 new_low = asm_lines[pos].addr;
aec2f747 160 }
6ba8e26f 161 for (i = 0; i < max_lines; i++)
aec2f747 162 {
4cfcaf21
JB
163 xfree (asm_lines[i].addr_string);
164 xfree (asm_lines[i].insn);
aec2f747 165 }
6ba8e26f 166 return new_low;
aec2f747
SC
167}
168
169/* Function to set the disassembly window's content. */
65f05602 170enum tui_status
13274fc3 171tui_set_disassem_content (struct gdbarch *gdbarch, CORE_ADDR pc)
c906108c 172{
22940a24 173 enum tui_status ret = TUI_FAILURE;
d02c80cd 174 int i;
6d012f14 175 int offset = TUI_DISASM_WIN->detail.source_info.horizontal_offset;
d02c80cd 176 int line_width, max_lines;
aec2f747 177 CORE_ADDR cur_pc;
5b6fe301 178 struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
dd1abb8c 179 int tab_len = tui_default_tab_len ();
5b6fe301 180 struct tui_asm_line *asm_lines;
aec2f747
SC
181 int insn_pos;
182 int addr_size, max_size;
5b6fe301 183 char *line;
aec2f747
SC
184
185 if (pc == 0)
186 return TUI_FAILURE;
187
6d012f14 188 ret = tui_alloc_source_buffer (TUI_DISASM_WIN);
aec2f747
SC
189 if (ret != TUI_SUCCESS)
190 return ret;
191
13274fc3 192 TUI_DISASM_WIN->detail.source_info.gdbarch = gdbarch;
362c05fe
AS
193 TUI_DISASM_WIN->detail.source_info.start_line_or_addr.loa = LOA_ADDRESS;
194 TUI_DISASM_WIN->detail.source_info.start_line_or_addr.u.addr = pc;
aec2f747 195 cur_pc = (CORE_ADDR)
6d012f14 196 (((struct tui_win_element *) locator->content[0])->which_element.locator.addr);
aec2f747 197
1cc6d956
MS
198 max_lines = TUI_DISASM_WIN->generic.height - 2; /* Account for
199 hilite. */
aec2f747
SC
200
201 /* Get temporary table that will hold all strings (addr & insn). */
4cfcaf21 202 asm_lines = (struct tui_asm_line*) alloca (sizeof (struct tui_asm_line)
6ba8e26f 203 * max_lines);
4cfcaf21 204 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
aec2f747 205
6ba8e26f 206 line_width = TUI_DISASM_WIN->generic.width - 1;
aec2f747 207
13274fc3 208 tui_disassemble (gdbarch, asm_lines, pc, max_lines);
aec2f747
SC
209
210 /* See what is the maximum length of an address and of a line. */
211 addr_size = 0;
212 max_size = 0;
6ba8e26f 213 for (i = 0; i < max_lines; i++)
c906108c 214 {
4cfcaf21 215 size_t len = strlen (asm_lines[i].addr_string);
aec2f747
SC
216 if (len > addr_size)
217 addr_size = len;
c906108c 218
4cfcaf21 219 len = strlen (asm_lines[i].insn) + tab_len;
aec2f747
SC
220 if (len > max_size)
221 max_size = len;
c906108c 222 }
aec2f747
SC
223 max_size += addr_size + tab_len;
224
225 /* Allocate memory to create each line. */
226 line = (char*) alloca (max_size);
227 insn_pos = (1 + (addr_size / tab_len)) * tab_len;
228
1cc6d956 229 /* Now construct each line. */
6ba8e26f 230 for (i = 0; i < max_lines; i++)
aec2f747 231 {
5b6fe301
MS
232 struct tui_win_element *element;
233 struct tui_source_element *src;
6ba8e26f 234 int cur_len;
aec2f747 235
6d012f14
AC
236 element = (struct tui_win_element *) TUI_DISASM_WIN->generic.content[i];
237 src = &element->which_element.source;
4cfcaf21 238 strcpy (line, asm_lines[i].addr_string);
6ba8e26f 239 cur_len = strlen (line);
aec2f747 240
1cc6d956
MS
241 /* Add spaces to make the instructions start on the same
242 column. */
6ba8e26f 243 while (cur_len < insn_pos)
aec2f747
SC
244 {
245 strcat (line, " ");
6ba8e26f 246 cur_len++;
aec2f747
SC
247 }
248
4cfcaf21 249 strcat (line, asm_lines[i].insn);
aec2f747 250
1cc6d956 251 /* Now copy the line taking the offset into account. */
aec2f747
SC
252 if (strlen (line) > offset)
253 strcpy (src->line, &line[offset]);
254 else
255 src->line[0] = '\0';
256
362c05fe
AS
257 src->line_or_addr.loa = LOA_ADDRESS;
258 src->line_or_addr.u.addr = asm_lines[i].addr;
4cfcaf21 259 src->is_exec_point = asm_lines[i].addr == cur_pc;
aec2f747
SC
260
261 /* See whether there is a breakpoint installed. */
6d012f14 262 src->has_break = (!src->is_exec_point
6c95b8df
PA
263 && breakpoint_here_p (current_program_space->aspace, pc)
264 != no_breakpoint_here);
c906108c 265
4cfcaf21
JB
266 xfree (asm_lines[i].addr_string);
267 xfree (asm_lines[i].insn);
aec2f747 268 }
6d012f14 269 TUI_DISASM_WIN->generic.content_size = i;
aec2f747
SC
270 return TUI_SUCCESS;
271}
c906108c
SS
272
273
1cc6d956 274/* Function to display the disassembly window with disassembled code. */
c906108c 275void
13274fc3 276tui_show_disassem (struct gdbarch *gdbarch, CORE_ADDR start_addr)
c906108c 277{
6ba8e26f 278 struct symtab *s = find_pc_symtab (start_addr);
5b6fe301 279 struct tui_win_info *win_with_focus = tui_win_with_focus ();
362c05fe 280 struct tui_line_or_address val;
c906108c 281
362c05fe
AS
282 val.loa = LOA_ADDRESS;
283 val.u.addr = start_addr;
080ce8c0 284 tui_add_win_to_layout (DISASSEM_WIN);
13274fc3 285 tui_update_source_window (TUI_DISASM_WIN, gdbarch, s, val, FALSE);
ef5eab5a
MS
286
287 /* If the focus was in the src win, put it in the asm win, if the
288 source view isn't split. */
e5908723
MS
289 if (tui_current_layout () != SRC_DISASSEM_COMMAND
290 && win_with_focus == TUI_SRC_WIN)
6d012f14 291 tui_set_win_focus_to (TUI_DISASM_WIN);
c906108c
SS
292
293 return;
65f05602 294}
c906108c
SS
295
296
1cc6d956 297/* Function to display the disassembly window. */
c906108c 298void
13274fc3
UW
299tui_show_disassem_and_update_source (struct gdbarch *gdbarch,
300 CORE_ADDR start_addr)
c906108c
SS
301{
302 struct symtab_and_line sal;
303
13274fc3 304 tui_show_disassem (gdbarch, start_addr);
dd1abb8c 305 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
c906108c 306 {
362c05fe 307 struct tui_line_or_address val;
aec2f747 308
ef5eab5a
MS
309 /* Update what is in the source window if it is displayed too,
310 note that it follows what is in the disassembly window and
311 visa-versa. */
6ba8e26f 312 sal = find_pc_line (start_addr, 0);
362c05fe
AS
313 val.loa = LOA_LINE;
314 val.u.line_no = sal.line;
13274fc3 315 tui_update_source_window (TUI_SRC_WIN, gdbarch, sal.symtab, val, TRUE);
3024f13a
SC
316 if (sal.symtab)
317 {
52575520 318 set_current_source_symtab_and_line (&sal);
47d3492a 319 tui_update_locator_filename (sal.symtab->filename);
3024f13a
SC
320 }
321 else
47d3492a 322 tui_update_locator_filename ("?");
c906108c
SS
323 }
324
325 return;
65f05602 326}
c906108c 327
13274fc3
UW
328void
329tui_get_begin_asm_address (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
c906108c 330{
5b6fe301
MS
331 struct tui_gen_win_info *locator;
332 struct tui_locator_element *element;
13274fc3 333 struct gdbarch *gdbarch = NULL;
c774cec6 334 CORE_ADDR addr;
c906108c 335
dd1abb8c 336 locator = tui_locator_win_info_ptr ();
6d012f14 337 element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
c906108c 338
c774cec6 339 if (element->addr == 0)
c906108c 340 {
0510ab86
SC
341 struct minimal_symbol *main_symbol;
342
343 /* Find address of the start of program.
344 Note: this should be language specific. */
345 main_symbol = lookup_minimal_symbol ("main", NULL, NULL);
346 if (main_symbol == 0)
347 main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL);
348 if (main_symbol == 0)
349 main_symbol = lookup_minimal_symbol ("_start", NULL, NULL);
350 if (main_symbol)
351 addr = SYMBOL_VALUE_ADDRESS (main_symbol);
352 else
353 addr = 0;
c906108c 354 }
1cc6d956 355 else /* The target is executing. */
13274fc3
UW
356 {
357 gdbarch = element->gdbarch;
358 addr = element->addr;
359 }
c906108c 360
13274fc3
UW
361 *gdbarch_p = gdbarch;
362 *addr_p = addr;
65f05602 363}
c906108c 364
77cad3ba 365/* Determine what the low address will be to display in the TUI's
1cc6d956
MS
366 disassembly window. This may or may not be the same as the low
367 address input. */
77cad3ba 368CORE_ADDR
13274fc3
UW
369tui_get_low_disassembly_address (struct gdbarch *gdbarch,
370 CORE_ADDR low, CORE_ADDR pc)
77cad3ba
SC
371{
372 int pos;
373
1cc6d956
MS
374 /* Determine where to start the disassembly so that the pc is about
375 in the middle of the viewport. */
080ce8c0 376 pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2;
13274fc3 377 pc = tui_find_disassembly_address (gdbarch, pc, -pos);
77cad3ba
SC
378
379 if (pc < low)
380 pc = low;
381 return pc;
382}
383
65f05602 384/* Scroll the disassembly forward or backward vertically. */
c906108c 385void
6ba8e26f
AC
386tui_vertical_disassem_scroll (enum tui_scroll_direction scroll_direction,
387 int num_to_scroll)
c906108c 388{
6d012f14 389 if (TUI_DISASM_WIN->generic.content != NULL)
c906108c 390 {
13274fc3 391 struct gdbarch *gdbarch = TUI_DISASM_WIN->detail.source_info.gdbarch;
aec2f747 392 CORE_ADDR pc;
2a8854a7 393 tui_win_content content;
362c05fe 394 struct tui_line_or_address val;
aefc7064 395 int dir;
c906108c 396
6d012f14 397 content = (tui_win_content) TUI_DISASM_WIN->generic.content;
c906108c 398
362c05fe 399 pc = content[0]->which_element.source.line_or_addr.u.addr;
aefc7064
PA
400 num_to_scroll++;
401 dir = (scroll_direction == FORWARD_SCROLL) ? num_to_scroll : -num_to_scroll;
c906108c 402
362c05fe 403 val.loa = LOA_ADDRESS;
13274fc3
UW
404 val.u.addr = tui_find_disassembly_address (gdbarch, pc, dir);
405 tui_update_source_window_as_is (TUI_DISASM_WIN, gdbarch, NULL, val, FALSE);
aec2f747
SC
406 }
407}
This page took 1.145571 seconds and 4 git commands to generate.