1 /* Disassembly display.
3 Copyright (C) 1998-2019 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
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
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "arch-utils.h"
25 #include "breakpoint.h"
31 #include "tui/tui-data.h"
32 #include "tui/tui-win.h"
33 #include "tui/tui-layout.h"
34 #include "tui/tui-winsource.h"
35 #include "tui/tui-stack.h"
36 #include "tui/tui-file.h"
37 #include "tui/tui-disasm.h"
38 #include "tui/tui-source.h"
39 #include "progspace.h"
42 #include "gdb_curses.h"
47 std::string addr_string
;
51 /* Function to set the disassembly window's content.
52 Disassemble count lines starting at pc.
53 Return address of the count'th instruction after pc. */
55 tui_disassemble (struct gdbarch
*gdbarch
,
56 std::vector
<tui_asm_line
> &asm_lines
,
57 CORE_ADDR pc
, int pos
, int count
)
59 string_file gdb_dis_out
;
61 /* Now construct each line. */
62 for (int i
= 0; i
< count
; ++i
)
64 print_address (gdbarch
, pc
, &gdb_dis_out
);
65 asm_lines
[pos
+ i
].addr
= pc
;
66 asm_lines
[pos
+ i
].addr_string
= std::move (gdb_dis_out
.string ());
70 pc
= pc
+ gdb_print_insn (gdbarch
, pc
, &gdb_dis_out
, NULL
);
72 asm_lines
[pos
+ i
].insn
= std::move (gdb_dis_out
.string ());
74 /* Reset the buffer to empty. */
80 /* Find the disassembly address that corresponds to FROM lines above
81 or below the PC. Variable sized instructions are taken into
82 account by the algorithm. */
84 tui_find_disassembly_address (struct gdbarch
*gdbarch
, CORE_ADDR pc
, int from
)
89 max_lines
= (from
> 0) ? from
: - from
;
93 std::vector
<tui_asm_line
> asm_lines (max_lines
);
98 tui_disassemble (gdbarch
, asm_lines
, pc
, 0, max_lines
);
99 new_low
= asm_lines
[max_lines
- 1].addr
;
105 struct bound_minimal_symbol msymbol
;
107 /* Find backward an address which is a symbol and for which
108 disassembling from that address will fill completely the
112 new_low
-= 1 * max_lines
;
113 msymbol
= lookup_minimal_symbol_by_pc_section (new_low
, 0);
116 new_low
= BMSYMBOL_VALUE_ADDRESS (msymbol
);
118 new_low
+= 1 * max_lines
;
120 tui_disassemble (gdbarch
, asm_lines
, new_low
, 0, max_lines
);
121 last_addr
= asm_lines
[pos
].addr
;
122 } while (last_addr
> pc
&& msymbol
.minsym
);
124 /* Scan forward disassembling one instruction at a time until
125 the last visible instruction of the window matches the pc.
126 We keep the disassembled instructions in the 'lines' window
127 and shift it downward (increasing its addresses). */
134 if (pos
>= max_lines
)
137 next_addr
= tui_disassemble (gdbarch
, asm_lines
,
140 /* If there are some problems while disassembling exit. */
141 if (next_addr
<= last_addr
)
143 last_addr
= next_addr
;
144 } while (last_addr
<= pc
);
146 if (pos
>= max_lines
)
148 new_low
= asm_lines
[pos
].addr
;
153 /* Function to set the disassembly window's content. */
155 tui_disasm_window::set_contents (struct gdbarch
*arch
,
157 struct tui_line_or_address line_or_addr
)
160 int offset
= horizontal_offset
;
161 int max_lines
, line_width
;
163 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
164 int tab_len
= tui_tab_width
;
166 int addr_size
, insn_size
;
168 gdb_assert (line_or_addr
.loa
== LOA_ADDRESS
);
169 CORE_ADDR pc
= line_or_addr
.u
.addr
;
174 start_line_or_addr
.loa
= LOA_ADDRESS
;
175 start_line_or_addr
.u
.addr
= pc
;
176 cur_pc
= locator
->addr
;
178 /* Window size, excluding highlight box. */
179 max_lines
= height
- 2;
180 line_width
= width
- TUI_EXECINFO_SIZE
- 2;
182 /* Get temporary table that will hold all strings (addr & insn). */
183 std::vector
<tui_asm_line
> asm_lines (max_lines
);
185 tui_disassemble (gdbarch
, asm_lines
, pc
, 0, max_lines
);
187 /* Determine maximum address- and instruction lengths. */
190 for (i
= 0; i
< max_lines
; i
++)
192 size_t len
= asm_lines
[i
].addr_string
.size ();
197 len
= asm_lines
[i
].insn
.size ();
202 /* Align instructions to the same column. */
203 insn_pos
= (1 + (addr_size
/ tab_len
)) * tab_len
;
205 /* Now construct each line. */
206 content
.resize (max_lines
);
207 for (i
= 0; i
< max_lines
; i
++)
209 tui_source_element
*src
= &content
[i
];
212 = (asm_lines
[i
].addr_string
214 - asm_lines
[i
].addr_string
.size ())
215 + asm_lines
[i
].insn
);
217 /* Now copy the line taking the offset into account. */
218 if (line
.size() > offset
)
219 src
->line
.reset (xstrndup (&line
[offset
], line_width
));
221 src
->line
.reset (xstrdup (""));
223 src
->line_or_addr
.loa
= LOA_ADDRESS
;
224 src
->line_or_addr
.u
.addr
= asm_lines
[i
].addr
;
225 src
->is_exec_point
= asm_lines
[i
].addr
== cur_pc
;
231 /* Function to display the disassembly window with disassembled code. */
233 tui_show_disassem (struct gdbarch
*gdbarch
, CORE_ADDR start_addr
)
235 struct symtab
*s
= find_pc_line_symtab (start_addr
);
236 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
237 struct tui_line_or_address val
;
239 gdb_assert (TUI_DISASM_WIN
!= nullptr && TUI_DISASM_WIN
->is_visible ());
241 val
.loa
= LOA_ADDRESS
;
242 val
.u
.addr
= start_addr
;
243 TUI_DISASM_WIN
->update_source_window (gdbarch
, s
, val
);
245 /* If the focus was in the src win, put it in the asm win, if the
246 source view isn't split. */
247 if (tui_current_layout () != SRC_DISASSEM_COMMAND
248 && win_with_focus
== TUI_SRC_WIN
)
249 tui_set_win_focus_to (TUI_DISASM_WIN
);
253 /* Function to display the disassembly window. */
255 tui_show_disassem_and_update_source (struct gdbarch
*gdbarch
,
256 CORE_ADDR start_addr
)
258 struct symtab_and_line sal
;
260 tui_show_disassem (gdbarch
, start_addr
);
261 if (tui_current_layout () == SRC_DISASSEM_COMMAND
)
263 struct tui_line_or_address val
;
265 /* Update what is in the source window if it is displayed too,
266 note that it follows what is in the disassembly window and
268 sal
= find_pc_line (start_addr
, 0);
270 val
.u
.line_no
= sal
.line
;
271 TUI_SRC_WIN
->update_source_window (gdbarch
, sal
.symtab
, val
);
274 set_current_source_symtab_and_line (sal
);
275 tui_update_locator_fullname (symtab_to_fullname (sal
.symtab
));
278 tui_update_locator_fullname ("?");
283 tui_get_begin_asm_address (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
285 struct tui_locator_window
*locator
;
286 struct gdbarch
*gdbarch
= get_current_arch ();
289 locator
= tui_locator_win_info_ptr ();
291 if (locator
->addr
== 0)
293 struct bound_minimal_symbol main_symbol
;
295 /* Find address of the start of program.
296 Note: this should be language specific. */
297 main_symbol
= lookup_minimal_symbol ("main", NULL
, NULL
);
298 if (main_symbol
.minsym
== 0)
299 main_symbol
= lookup_minimal_symbol ("MAIN", NULL
, NULL
);
300 if (main_symbol
.minsym
== 0)
301 main_symbol
= lookup_minimal_symbol ("_start", NULL
, NULL
);
302 if (main_symbol
.minsym
)
303 addr
= BMSYMBOL_VALUE_ADDRESS (main_symbol
);
307 else /* The target is executing. */
309 gdbarch
= locator
->gdbarch
;
310 addr
= locator
->addr
;
313 *gdbarch_p
= gdbarch
;
317 /* Determine what the low address will be to display in the TUI's
318 disassembly window. This may or may not be the same as the low
321 tui_get_low_disassembly_address (struct gdbarch
*gdbarch
,
322 CORE_ADDR low
, CORE_ADDR pc
)
326 /* Determine where to start the disassembly so that the pc is about
327 in the middle of the viewport. */
328 pos
= tui_default_win_viewport_height (DISASSEM_WIN
, DISASSEM_COMMAND
) / 2;
329 pc
= tui_find_disassembly_address (gdbarch
, pc
, -pos
);
336 /* Scroll the disassembly forward or backward vertically. */
338 tui_disasm_window::do_scroll_vertical (int num_to_scroll
)
340 if (!content
.empty ())
343 struct tui_line_or_address val
;
345 pc
= content
[0].line_or_addr
.u
.addr
;
346 if (num_to_scroll
>= 0)
351 val
.loa
= LOA_ADDRESS
;
352 val
.u
.addr
= tui_find_disassembly_address (gdbarch
, pc
, num_to_scroll
);
353 update_source_window_as_is (gdbarch
, NULL
, val
);
358 tui_disasm_window::location_matches_p (struct bp_location
*loc
, int line_no
)
360 return (content
[line_no
].line_or_addr
.loa
== LOA_ADDRESS
361 && content
[line_no
].line_or_addr
.u
.addr
== loc
->address
);
365 tui_disasm_window::addr_is_displayed (CORE_ADDR addr
) const
367 bool is_displayed
= false;
368 int threshold
= SCROLL_THRESHOLD
;
371 while (i
< content
.size () - threshold
&& !is_displayed
)
374 = (content
[i
].line_or_addr
.loa
== LOA_ADDRESS
375 && content
[i
].line_or_addr
.u
.addr
== addr
);
383 tui_disasm_window::maybe_update (struct frame_info
*fi
, symtab_and_line sal
,
384 int line_no
, CORE_ADDR addr
)
388 if (find_pc_partial_function (get_frame_pc (fi
),
389 NULL
, &low
, NULL
) == 0)
391 /* There is no symbol available for current PC. There is no
392 safe way how to "disassemble backwards". */
393 low
= get_frame_pc (fi
);
396 low
= tui_get_low_disassembly_address (get_frame_arch (fi
),
397 low
, get_frame_pc (fi
));
399 struct tui_line_or_address a
;
403 if (!addr_is_displayed (addr
))
404 update_source_window (get_frame_arch (fi
), sal
.symtab
, a
);
408 set_is_exec_point_at (a
);