Use TUI_DISASM_WIN instead of tui_win_list array
[deliverable/binutils-gdb.git] / gdb / tui / tui-disasm.c
CommitLineData
f377b406 1/* Disassembly display.
f33c6cbf 2
b811d2c2 3 Copyright (C) 1998-2020 Free Software Foundation, Inc.
f33c6cbf 4
f377b406
SC
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
f377b406
SC
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
21
22#include "defs.h"
957b8b5a 23#include "arch-utils.h"
c906108c
SS
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"
d7b2e967 30#include "tui/tui.h"
6d7fd9aa 31#include "tui/tui-command.h"
d7b2e967
AC
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"
bfad4537 39#include "tui/tui-source.h"
6c95b8df 40#include "progspace.h"
77e371c0 41#include "objfiles.h"
1df2f9ef 42#include "cli/cli-style.h"
c906108c 43
6a83354a 44#include "gdb_curses.h"
96ec9981 45
a61b4f69 46struct tui_asm_line
aec2f747
SC
47{
48 CORE_ADDR addr;
6b915f7d 49 std::string addr_string;
825165c5 50 size_t addr_size;
6b915f7d 51 std::string insn;
aec2f747
SC
52};
53
1df2f9ef
TT
54/* Helper function to find the number of characters in STR, skipping
55 any ANSI escape sequences. */
56static size_t
57len_without_escapes (const std::string &str)
58{
59 size_t len = 0;
60 const char *ptr = str.c_str ();
61 char c;
62
63 while ((c = *ptr++) != '\0')
64 {
65 if (c == '\033')
66 {
67 ui_file_style style;
68 size_t n_read;
69 if (style.parse (ptr, &n_read))
70 ptr += n_read;
71 else
72 {
73 /* Shouldn't happen, but just skip the ESC if it somehow
74 does. */
75 ++ptr;
76 }
77 }
78 else
79 ++len;
80 }
81 return len;
82}
83
733d0a67
AB
84/* Function to disassemble up to COUNT instructions starting from address
85 PC into the ASM_LINES vector (which will be emptied of any previous
86 contents). Return the address of the COUNT'th instruction after pc.
87 When ADDR_SIZE is non-null then place the maximum size of an address and
88 label into the value pointed to by ADDR_SIZE, and set the addr_size
89 field on each item in ASM_LINES, otherwise the addr_size fields within
90 ASM_LINES are undefined.
91
92 It is worth noting that ASM_LINES might not have COUNT entries when this
93 function returns. If the disassembly is truncated for some other
94 reason, for example, we hit invalid memory, then ASM_LINES can have
95 fewer entries than requested. */
aec2f747 96static CORE_ADDR
6b915f7d
TT
97tui_disassemble (struct gdbarch *gdbarch,
98 std::vector<tui_asm_line> &asm_lines,
733d0a67 99 CORE_ADDR pc, int count,
1df2f9ef 100 size_t *addr_size = nullptr)
aec2f747 101{
1df2f9ef
TT
102 bool term_out = source_styling && gdb_stdout->can_emit_style_escape ();
103 string_file gdb_dis_out (term_out);
aec2f747 104
733d0a67
AB
105 /* Must start with an empty list. */
106 asm_lines.clear ();
107
1cc6d956 108 /* Now construct each line. */
6b915f7d 109 for (int i = 0; i < count; ++i)
aec2f747 110 {
733d0a67
AB
111 tui_asm_line tal;
112 CORE_ADDR orig_pc = pc;
aec2f747 113
733d0a67
AB
114 try
115 {
116 pc = pc + gdb_print_insn (gdbarch, pc, &gdb_dis_out, NULL);
117 }
118 catch (const gdb_exception_error &except)
119 {
120 /* If PC points to an invalid address then we'll catch a
121 MEMORY_ERROR here, this should stop the disassembly, but
122 otherwise is fine. */
123 if (except.error != MEMORY_ERROR)
124 throw;
125 return pc;
126 }
127
128 /* Capture the disassembled instruction. */
129 tal.insn = std::move (gdb_dis_out.string ());
130 gdb_dis_out.clear ();
131
132 /* And capture the address the instruction is at. */
133 tal.addr = orig_pc;
134 print_address (gdbarch, orig_pc, &gdb_dis_out);
135 tal.addr_string = std::move (gdb_dis_out.string ());
d7e74731 136 gdb_dis_out.clear ();
aec2f747 137
1df2f9ef
TT
138 if (addr_size != nullptr)
139 {
140 size_t new_size;
141
142 if (term_out)
733d0a67 143 new_size = len_without_escapes (tal.addr_string);
1df2f9ef 144 else
733d0a67 145 new_size = tal.addr_string.size ();
1df2f9ef 146 *addr_size = std::max (*addr_size, new_size);
733d0a67 147 tal.addr_size = new_size;
1df2f9ef
TT
148 }
149
733d0a67 150 asm_lines.push_back (std::move (tal));
aec2f747 151 }
aec2f747
SC
152 return pc;
153}
154
733d0a67
AB
155/* Look backward from ADDR for an address from which we can start
156 disassembling, this needs to be something we can be reasonably
157 confident will fall on an instruction boundary. We use msymbol
158 addresses, or the start of a section. */
159
160static CORE_ADDR
161tui_find_backward_disassembly_start_address (CORE_ADDR addr)
162{
163 struct bound_minimal_symbol msym, msym_prev;
164
165 msym = lookup_minimal_symbol_by_pc_section (addr - 1, nullptr,
166 lookup_msym_prefer::TEXT,
167 &msym_prev);
168 if (msym.minsym != nullptr)
169 return BMSYMBOL_VALUE_ADDRESS (msym);
170 else if (msym_prev.minsym != nullptr)
171 return BMSYMBOL_VALUE_ADDRESS (msym_prev);
172
173 /* Find the section that ADDR is in, and look for the start of the
174 section. */
175 struct obj_section *section = find_pc_section (addr);
176 if (section != NULL)
177 return obj_section_addr (section);
178
179 return addr;
180}
181
1cc6d956
MS
182/* Find the disassembly address that corresponds to FROM lines above
183 or below the PC. Variable sized instructions are taken into
184 account by the algorithm. */
aec2f747 185static CORE_ADDR
13274fc3 186tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
aec2f747 187{
d02c80cd 188 CORE_ADDR new_low;
6ba8e26f 189 int max_lines;
aec2f747 190
6ba8e26f 191 max_lines = (from > 0) ? from : - from;
733d0a67 192 if (max_lines == 0)
6b915f7d 193 return pc;
aec2f747 194
733d0a67 195 std::vector<tui_asm_line> asm_lines;
aec2f747 196
6ba8e26f 197 new_low = pc;
aec2f747
SC
198 if (from > 0)
199 {
733d0a67
AB
200 /* Always disassemble 1 extra instruction here, then if the last
201 instruction fails to disassemble we will take the address of the
202 previous instruction that did disassemble as the result. */
203 tui_disassemble (gdbarch, asm_lines, pc, max_lines + 1);
204 new_low = asm_lines.back ().addr;
aec2f747
SC
205 }
206 else
207 {
733d0a67
AB
208 /* In order to disassemble backwards we need to find a suitable
209 address to start disassembling from and then work forward until we
210 re-find the address we're currently at. We can then figure out
211 which address will be at the top of the TUI window after our
212 backward scroll. During our backward disassemble we need to be
213 able to distinguish between the case where the last address we
214 _can_ disassemble is ADDR, and the case where the disassembly
215 just happens to stop at ADDR, for this reason we increase
216 MAX_LINES by one. */
217 max_lines++;
218
219 /* When we disassemble a series of instructions this will hold the
220 address of the last instruction disassembled. */
aec2f747 221 CORE_ADDR last_addr;
733d0a67
AB
222
223 /* And this will hold the address of the next instruction that would
224 have been disassembled. */
225 CORE_ADDR next_addr;
226
227 /* As we search backward if we find an address that looks like a
228 promising starting point then we record it in this structure. If
229 the next address we try is not a suitable starting point then we
230 will fall back to the address held here. */
231 gdb::optional<CORE_ADDR> possible_new_low;
232
233 /* The previous value of NEW_LOW so we know if the new value is
234 different or not. */
235 CORE_ADDR prev_low;
236
237 do
238 {
239 /* Find an address from which we can start disassembling. */
240 prev_low = new_low;
241 new_low = tui_find_backward_disassembly_start_address (new_low);
242
243 /* Disassemble forward. */
244 next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
245 last_addr = asm_lines.back ().addr;
246
247 /* If disassembling from the current value of NEW_LOW reached PC
248 (or went past it) then this would do as a starting point if we
249 can't find anything better, so remember it. */
250 if (last_addr >= pc && new_low != prev_low
251 && asm_lines.size () >= max_lines)
252 possible_new_low.emplace (new_low);
253
254 /* Continue searching until we find a value of NEW_LOW from which
255 disassembling MAX_LINES instructions doesn't reach PC. We
256 know this means we can find the required number of previous
257 instructions then. */
258 }
259 while ((last_addr > pc
260 || (last_addr == pc && asm_lines.size () < max_lines))
261 && new_low != prev_low);
262
263 /* If we failed to disassemble the required number of lines then the
264 following walk forward is not going to work, it assumes that
265 ASM_LINES contains exactly MAX_LINES entries. Instead we should
266 consider falling back to a previous possible start address in
267 POSSIBLE_NEW_LOW. */
268 if (asm_lines.size () < max_lines)
269 {
270 if (!possible_new_low.has_value ())
42330a68 271 return new_low;
733d0a67
AB
272
273 /* Take the best possible match we have. */
274 new_low = *possible_new_low;
275 next_addr = tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
276 last_addr = asm_lines.back ().addr;
277 gdb_assert (asm_lines.size () >= max_lines);
278 }
aec2f747 279
1cc6d956
MS
280 /* Scan forward disassembling one instruction at a time until
281 the last visible instruction of the window matches the pc.
282 We keep the disassembled instructions in the 'lines' window
283 and shift it downward (increasing its addresses). */
733d0a67 284 int pos = max_lines - 1;
aec2f747
SC
285 if (last_addr < pc)
286 do
287 {
aec2f747 288 pos++;
6ba8e26f 289 if (pos >= max_lines)
aec2f747
SC
290 pos = 0;
291
733d0a67
AB
292 CORE_ADDR old_next_addr = next_addr;
293 std::vector<tui_asm_line> single_asm_line;
294 next_addr = tui_disassemble (gdbarch, single_asm_line,
295 next_addr, 1);
aec2f747 296 /* If there are some problems while disassembling exit. */
733d0a67
AB
297 if (next_addr <= old_next_addr)
298 return pc;
299 gdb_assert (single_asm_line.size () == 1);
300 asm_lines[pos] = single_asm_line[0];
301 } while (next_addr <= pc);
aec2f747 302 pos++;
6ba8e26f 303 if (pos >= max_lines)
aec2f747 304 pos = 0;
4cfcaf21 305 new_low = asm_lines[pos].addr;
733d0a67
AB
306
307 /* When scrolling backward the addresses should move backward, or at
308 the very least stay the same if we are at the first address that
309 can be disassembled. */
310 gdb_assert (new_low <= pc);
aec2f747 311 }
6ba8e26f 312 return new_low;
aec2f747
SC
313}
314
315/* Function to set the disassembly window's content. */
61c33f10 316bool
81c82c4b 317tui_disasm_window::set_contents (struct gdbarch *arch,
9f7540a5 318 const struct symtab_and_line &sal)
c906108c 319{
d02c80cd 320 int i;
81c82c4b 321 int offset = horizontal_offset;
0bb65f1e 322 int max_lines, line_width;
aec2f747 323 CORE_ADDR cur_pc;
3add462f 324 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
7806cea7 325 int tab_len = tui_tab_width;
aec2f747 326 int insn_pos;
1df2f9ef 327
9f7540a5 328 CORE_ADDR pc = sal.pc;
aec2f747 329 if (pc == 0)
61c33f10 330 return false;
aec2f747 331
81c82c4b
TT
332 gdbarch = arch;
333 start_line_or_addr.loa = LOA_ADDRESS;
334 start_line_or_addr.u.addr = pc;
3add462f 335 cur_pc = locator->addr;
aec2f747 336
0bb65f1e 337 /* Window size, excluding highlight box. */
81c82c4b 338 max_lines = height - 2;
398fdd60 339 line_width = width - TUI_EXECINFO_SIZE - 2;
aec2f747
SC
340
341 /* Get temporary table that will hold all strings (addr & insn). */
733d0a67 342 std::vector<tui_asm_line> asm_lines;
1df2f9ef 343 size_t addr_size = 0;
733d0a67 344 tui_disassemble (gdbarch, asm_lines, pc, max_lines, &addr_size);
aec2f747 345
f5396833 346 /* Align instructions to the same column. */
aec2f747
SC
347 insn_pos = (1 + (addr_size / tab_len)) * tab_len;
348
1cc6d956 349 /* Now construct each line. */
81c82c4b 350 content.resize (max_lines);
6ba8e26f 351 for (i = 0; i < max_lines; i++)
aec2f747 352 {
81c82c4b 353 tui_source_element *src = &content[i];
6b915f7d 354
733d0a67
AB
355 std::string line;
356 CORE_ADDR addr;
357
358 if (i < asm_lines.size ())
359 {
360 line
361 = (asm_lines[i].addr_string
362 + n_spaces (insn_pos - asm_lines[i].addr_size)
363 + asm_lines[i].insn);
364 addr = asm_lines[i].addr;
365 }
366 else
367 {
368 line = "";
369 addr = 0;
370 }
aec2f747 371
1df2f9ef 372 const char *ptr = line.c_str ();
d1da6b01 373 src->line = tui_copy_source_line (&ptr, -1, offset, line_width, 0);
aec2f747 374
362c05fe 375 src->line_or_addr.loa = LOA_ADDRESS;
733d0a67
AB
376 src->line_or_addr.u.addr = addr;
377 src->is_exec_point = (addr == cur_pc && line.size () > 0);
aec2f747 378 }
61c33f10 379 return true;
aec2f747 380}
c906108c
SS
381
382
13274fc3
UW
383void
384tui_get_begin_asm_address (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
c906108c 385{
3add462f 386 struct tui_locator_window *locator;
957b8b5a 387 struct gdbarch *gdbarch = get_current_arch ();
52469d76 388 CORE_ADDR addr = 0;
c906108c 389
dd1abb8c 390 locator = tui_locator_win_info_ptr ();
c906108c 391
3add462f 392 if (locator->addr == 0)
c906108c 393 {
52469d76
TT
394 if (have_full_symbols () || have_partial_symbols ())
395 {
396 set_default_source_symtab_and_line ();
397 struct symtab_and_line sal = get_current_source_symtab_and_line ();
398
399 if (sal.symtab != nullptr)
400 find_line_pc (sal.symtab, sal.line, &addr);
401 }
402
403 if (addr == 0)
404 {
405 struct bound_minimal_symbol main_symbol
406 = lookup_minimal_symbol (main_name (), nullptr, nullptr);
407 if (main_symbol.minsym != nullptr)
408 addr = BMSYMBOL_VALUE_ADDRESS (main_symbol);
409 }
c906108c 410 }
1cc6d956 411 else /* The target is executing. */
13274fc3 412 {
3add462f
TT
413 gdbarch = locator->gdbarch;
414 addr = locator->addr;
13274fc3 415 }
c906108c 416
13274fc3
UW
417 *gdbarch_p = gdbarch;
418 *addr_p = addr;
65f05602 419}
c906108c 420
77cad3ba 421/* Determine what the low address will be to display in the TUI's
1cc6d956
MS
422 disassembly window. This may or may not be the same as the low
423 address input. */
77cad3ba 424CORE_ADDR
13274fc3
UW
425tui_get_low_disassembly_address (struct gdbarch *gdbarch,
426 CORE_ADDR low, CORE_ADDR pc)
77cad3ba
SC
427{
428 int pos;
429
1cc6d956
MS
430 /* Determine where to start the disassembly so that the pc is about
431 in the middle of the viewport. */
2a3d458b
TT
432 if (TUI_DISASM_WIN != NULL)
433 pos = TUI_DISASM_WIN->height;
6d7fd9aa
TT
434 else if (TUI_CMD_WIN == NULL)
435 pos = tui_term_height () / 2 - 2;
436 else
437 pos = tui_term_height () - TUI_CMD_WIN->height - 2;
438 pos = (pos - 2) / 2;
439
13274fc3 440 pc = tui_find_disassembly_address (gdbarch, pc, -pos);
77cad3ba
SC
441
442 if (pc < low)
443 pc = low;
444 return pc;
445}
446
65f05602 447/* Scroll the disassembly forward or backward vertically. */
c906108c 448void
c3bd716f 449tui_disasm_window::do_scroll_vertical (int num_to_scroll)
c906108c 450{
53e7cdba 451 if (!content.empty ())
c906108c 452 {
aec2f747 453 CORE_ADDR pc;
c906108c 454
57e4b379 455 pc = start_line_or_addr.u.addr;
c906108c 456
9f7540a5
TT
457 symtab_and_line sal {};
458 sal.pspace = current_program_space;
459 sal.pc = tui_find_disassembly_address (gdbarch, pc, num_to_scroll);
460 update_source_window_as_is (gdbarch, sal);
aec2f747
SC
461 }
462}
c2cd8994
TT
463
464bool
465tui_disasm_window::location_matches_p (struct bp_location *loc, int line_no)
466{
467 return (content[line_no].line_or_addr.loa == LOA_ADDRESS
468 && content[line_no].line_or_addr.u.addr == loc->address);
469}
a54700c6 470
088f37dd
TT
471bool
472tui_disasm_window::addr_is_displayed (CORE_ADDR addr) const
473{
cbfa8581
SV
474 if (content.size () < SCROLL_THRESHOLD)
475 return false;
088f37dd 476
cbfa8581 477 for (size_t i = 0; i < content.size () - SCROLL_THRESHOLD; ++i)
088f37dd 478 {
cbfa8581
SV
479 if (content[i].line_or_addr.loa == LOA_ADDRESS
480 && content[i].line_or_addr.u.addr == addr)
481 return true;
088f37dd
TT
482 }
483
cbfa8581 484 return false;
088f37dd
TT
485}
486
a54700c6 487void
1ae58f0c 488tui_disasm_window::maybe_update (struct frame_info *fi, symtab_and_line sal)
a54700c6
TT
489{
490 CORE_ADDR low;
491
1ae58f0c
TT
492 struct gdbarch *frame_arch = get_frame_arch (fi);
493
494 if (find_pc_partial_function (sal.pc, NULL, &low, NULL) == 0)
a54700c6
TT
495 {
496 /* There is no symbol available for current PC. There is no
497 safe way how to "disassemble backwards". */
1ae58f0c 498 low = sal.pc;
a54700c6
TT
499 }
500 else
1ae58f0c 501 low = tui_get_low_disassembly_address (frame_arch, low, sal.pc);
a54700c6
TT
502
503 struct tui_line_or_address a;
504
505 a.loa = LOA_ADDRESS;
506 a.u.addr = low;
1ae58f0c 507 if (!addr_is_displayed (sal.pc))
9f7540a5
TT
508 {
509 sal.pc = low;
510 update_source_window (frame_arch, sal);
511 }
a54700c6
TT
512 else
513 {
1ae58f0c 514 a.u.addr = sal.pc;
a54700c6
TT
515 set_is_exec_point_at (a);
516 }
517}
This page took 2.016127 seconds and 4 git commands to generate.