Introduce tui_source_window_base::set_contents method
[deliverable/binutils-gdb.git] / gdb / tui / tui-disasm.c
1 /* Disassembly display.
2
3 Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
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
11 the Free Software Foundation; either version 3 of the License, or
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
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "symtab.h"
25 #include "breakpoint.h"
26 #include "frame.h"
27 #include "value.h"
28 #include "source.h"
29 #include "disasm.h"
30 #include "tui/tui.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"
40 #include "objfiles.h"
41
42 #include "gdb_curses.h"
43
44 struct tui_asm_line
45 {
46 CORE_ADDR addr;
47 char *addr_string;
48 char *insn;
49 };
50
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. */
54 static CORE_ADDR
55 tui_disassemble (struct gdbarch *gdbarch, struct tui_asm_line *asm_lines,
56 CORE_ADDR pc, int count)
57 {
58 string_file gdb_dis_out;
59
60 /* Now construct each line. */
61 for (; count > 0; count--, asm_lines++)
62 {
63 xfree (asm_lines->addr_string);
64 xfree (asm_lines->insn);
65
66 print_address (gdbarch, pc, &gdb_dis_out);
67 asm_lines->addr = pc;
68 asm_lines->addr_string = xstrdup (gdb_dis_out.c_str ());
69
70 gdb_dis_out.clear ();
71
72 pc = pc + gdb_print_insn (gdbarch, pc, &gdb_dis_out, NULL);
73
74 asm_lines->insn = xstrdup (gdb_dis_out.c_str ());
75
76 /* Reset the buffer to empty. */
77 gdb_dis_out.clear ();
78 }
79 return pc;
80 }
81
82 /* Find the disassembly address that corresponds to FROM lines above
83 or below the PC. Variable sized instructions are taken into
84 account by the algorithm. */
85 static CORE_ADDR
86 tui_find_disassembly_address (struct gdbarch *gdbarch, CORE_ADDR pc, int from)
87 {
88 CORE_ADDR new_low;
89 int max_lines;
90 int i;
91 struct tui_asm_line *asm_lines;
92
93 max_lines = (from > 0) ? from : - from;
94 if (max_lines <= 1)
95 return pc;
96
97 asm_lines = XALLOCAVEC (struct tui_asm_line, max_lines);
98 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
99
100 new_low = pc;
101 if (from > 0)
102 {
103 tui_disassemble (gdbarch, asm_lines, pc, max_lines);
104 new_low = asm_lines[max_lines - 1].addr;
105 }
106 else
107 {
108 CORE_ADDR last_addr;
109 int pos;
110 struct bound_minimal_symbol msymbol;
111
112 /* Find backward an address which is a symbol and for which
113 disassembling from that address will fill completely the
114 window. */
115 pos = max_lines - 1;
116 do {
117 new_low -= 1 * max_lines;
118 msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0);
119
120 if (msymbol.minsym)
121 new_low = BMSYMBOL_VALUE_ADDRESS (msymbol);
122 else
123 new_low += 1 * max_lines;
124
125 tui_disassemble (gdbarch, asm_lines, new_low, max_lines);
126 last_addr = asm_lines[pos].addr;
127 } while (last_addr > pc && msymbol.minsym);
128
129 /* Scan forward disassembling one instruction at a time until
130 the last visible instruction of the window matches the pc.
131 We keep the disassembled instructions in the 'lines' window
132 and shift it downward (increasing its addresses). */
133 if (last_addr < pc)
134 do
135 {
136 CORE_ADDR next_addr;
137
138 pos++;
139 if (pos >= max_lines)
140 pos = 0;
141
142 next_addr = tui_disassemble (gdbarch, &asm_lines[pos],
143 last_addr, 1);
144
145 /* If there are some problems while disassembling exit. */
146 if (next_addr <= last_addr)
147 break;
148 last_addr = next_addr;
149 } while (last_addr <= pc);
150 pos++;
151 if (pos >= max_lines)
152 pos = 0;
153 new_low = asm_lines[pos].addr;
154 }
155 for (i = 0; i < max_lines; i++)
156 {
157 xfree (asm_lines[i].addr_string);
158 xfree (asm_lines[i].insn);
159 }
160 return new_low;
161 }
162
163 /* Function to set the disassembly window's content. */
164 enum tui_status
165 tui_disasm_window::set_contents (struct gdbarch *arch,
166 struct symtab *s,
167 struct tui_line_or_address line_or_addr)
168 {
169 int i;
170 int offset = horizontal_offset;
171 int max_lines, line_width;
172 CORE_ADDR cur_pc;
173 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
174 int tab_len = tui_tab_width;
175 struct tui_asm_line *asm_lines;
176 int insn_pos;
177 int addr_size, insn_size;
178 char *line;
179
180 gdb_assert (line_or_addr.loa == LOA_ADDRESS);
181 CORE_ADDR pc = line_or_addr.u.addr;
182 if (pc == 0)
183 return TUI_FAILURE;
184
185 gdbarch = arch;
186 start_line_or_addr.loa = LOA_ADDRESS;
187 start_line_or_addr.u.addr = pc;
188 cur_pc = locator->addr;
189
190 /* Window size, excluding highlight box. */
191 max_lines = height - 2;
192 line_width = width - 2;
193
194 /* Get temporary table that will hold all strings (addr & insn). */
195 asm_lines = XALLOCAVEC (struct tui_asm_line, max_lines);
196 memset (asm_lines, 0, sizeof (struct tui_asm_line) * max_lines);
197
198 tui_disassemble (gdbarch, asm_lines, pc, max_lines);
199
200 /* Determine maximum address- and instruction lengths. */
201 addr_size = 0;
202 insn_size = 0;
203 for (i = 0; i < max_lines; i++)
204 {
205 size_t len = strlen (asm_lines[i].addr_string);
206
207 if (len > addr_size)
208 addr_size = len;
209
210 len = strlen (asm_lines[i].insn);
211 if (len > insn_size)
212 insn_size = len;
213 }
214
215 /* Align instructions to the same column. */
216 insn_pos = (1 + (addr_size / tab_len)) * tab_len;
217
218 /* Allocate memory to create each line. */
219 line = (char*) alloca (insn_pos + insn_size + 1);
220
221 /* Now construct each line. */
222 content.resize (max_lines);
223 for (i = 0; i < max_lines; i++)
224 {
225 int cur_len;
226
227 tui_source_element *src = &content[i];
228 strcpy (line, asm_lines[i].addr_string);
229 cur_len = strlen (line);
230 memset (line + cur_len, ' ', insn_pos - cur_len);
231 strcpy (line + insn_pos, asm_lines[i].insn);
232
233 /* Now copy the line taking the offset into account. */
234 xfree (src->line);
235 if (strlen (line) > offset)
236 src->line = xstrndup (&line[offset], line_width);
237 else
238 src->line = xstrdup ("");
239
240 src->line_or_addr.loa = LOA_ADDRESS;
241 src->line_or_addr.u.addr = asm_lines[i].addr;
242 src->is_exec_point = asm_lines[i].addr == cur_pc;
243
244 xfree (asm_lines[i].addr_string);
245 xfree (asm_lines[i].insn);
246 }
247 return TUI_SUCCESS;
248 }
249
250
251 /* Function to display the disassembly window with disassembled code. */
252 void
253 tui_show_disassem (struct gdbarch *gdbarch, CORE_ADDR start_addr)
254 {
255 struct symtab *s = find_pc_line_symtab (start_addr);
256 struct tui_win_info *win_with_focus = tui_win_with_focus ();
257 struct tui_line_or_address val;
258
259 gdb_assert (TUI_DISASM_WIN != nullptr && TUI_DISASM_WIN->is_visible ());
260
261 val.loa = LOA_ADDRESS;
262 val.u.addr = start_addr;
263 TUI_DISASM_WIN->update_source_window (gdbarch, s, val);
264
265 /* If the focus was in the src win, put it in the asm win, if the
266 source view isn't split. */
267 if (tui_current_layout () != SRC_DISASSEM_COMMAND
268 && win_with_focus == TUI_SRC_WIN)
269 tui_set_win_focus_to (TUI_DISASM_WIN);
270 }
271
272
273 /* Function to display the disassembly window. */
274 void
275 tui_show_disassem_and_update_source (struct gdbarch *gdbarch,
276 CORE_ADDR start_addr)
277 {
278 struct symtab_and_line sal;
279
280 tui_show_disassem (gdbarch, start_addr);
281 if (tui_current_layout () == SRC_DISASSEM_COMMAND)
282 {
283 struct tui_line_or_address val;
284
285 /* Update what is in the source window if it is displayed too,
286 note that it follows what is in the disassembly window and
287 visa-versa. */
288 sal = find_pc_line (start_addr, 0);
289 val.loa = LOA_LINE;
290 val.u.line_no = sal.line;
291 TUI_SRC_WIN->update_source_window (gdbarch, sal.symtab, val);
292 if (sal.symtab)
293 {
294 set_current_source_symtab_and_line (sal);
295 tui_update_locator_fullname (symtab_to_fullname (sal.symtab));
296 }
297 else
298 tui_update_locator_fullname ("?");
299 }
300 }
301
302 void
303 tui_get_begin_asm_address (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
304 {
305 struct tui_locator_window *locator;
306 struct gdbarch *gdbarch = get_current_arch ();
307 CORE_ADDR addr;
308
309 locator = tui_locator_win_info_ptr ();
310
311 if (locator->addr == 0)
312 {
313 struct bound_minimal_symbol main_symbol;
314
315 /* Find address of the start of program.
316 Note: this should be language specific. */
317 main_symbol = lookup_minimal_symbol ("main", NULL, NULL);
318 if (main_symbol.minsym == 0)
319 main_symbol = lookup_minimal_symbol ("MAIN", NULL, NULL);
320 if (main_symbol.minsym == 0)
321 main_symbol = lookup_minimal_symbol ("_start", NULL, NULL);
322 if (main_symbol.minsym)
323 addr = BMSYMBOL_VALUE_ADDRESS (main_symbol);
324 else
325 addr = 0;
326 }
327 else /* The target is executing. */
328 {
329 gdbarch = locator->gdbarch;
330 addr = locator->addr;
331 }
332
333 *gdbarch_p = gdbarch;
334 *addr_p = addr;
335 }
336
337 /* Determine what the low address will be to display in the TUI's
338 disassembly window. This may or may not be the same as the low
339 address input. */
340 CORE_ADDR
341 tui_get_low_disassembly_address (struct gdbarch *gdbarch,
342 CORE_ADDR low, CORE_ADDR pc)
343 {
344 int pos;
345
346 /* Determine where to start the disassembly so that the pc is about
347 in the middle of the viewport. */
348 pos = tui_default_win_viewport_height (DISASSEM_WIN, DISASSEM_COMMAND) / 2;
349 pc = tui_find_disassembly_address (gdbarch, pc, -pos);
350
351 if (pc < low)
352 pc = low;
353 return pc;
354 }
355
356 /* Scroll the disassembly forward or backward vertically. */
357 void
358 tui_disasm_window::do_scroll_vertical (int num_to_scroll)
359 {
360 if (!content.empty ())
361 {
362 CORE_ADDR pc;
363 struct tui_line_or_address val;
364
365 pc = content[0].line_or_addr.u.addr;
366 if (num_to_scroll >= 0)
367 num_to_scroll++;
368 else
369 --num_to_scroll;
370
371 val.loa = LOA_ADDRESS;
372 val.u.addr = tui_find_disassembly_address (gdbarch, pc, num_to_scroll);
373 update_source_window_as_is (gdbarch, NULL, val);
374 }
375 }
376
377 bool
378 tui_disasm_window::location_matches_p (struct bp_location *loc, int line_no)
379 {
380 return (content[line_no].line_or_addr.loa == LOA_ADDRESS
381 && content[line_no].line_or_addr.u.addr == loc->address);
382 }
383
384 bool
385 tui_disasm_window::addr_is_displayed (CORE_ADDR addr) const
386 {
387 bool is_displayed = false;
388 int threshold = SCROLL_THRESHOLD;
389
390 int i = 0;
391 while (i < content.size () - threshold && !is_displayed)
392 {
393 is_displayed
394 = (content[i].line_or_addr.loa == LOA_ADDRESS
395 && content[i].line_or_addr.u.addr == addr);
396 i++;
397 }
398
399 return is_displayed;
400 }
401
402 void
403 tui_disasm_window::maybe_update (struct frame_info *fi, symtab_and_line sal,
404 int line_no, CORE_ADDR addr)
405 {
406 CORE_ADDR low;
407
408 if (find_pc_partial_function (get_frame_pc (fi),
409 NULL, &low, NULL) == 0)
410 {
411 /* There is no symbol available for current PC. There is no
412 safe way how to "disassemble backwards". */
413 low = get_frame_pc (fi);
414 }
415 else
416 low = tui_get_low_disassembly_address (get_frame_arch (fi),
417 low, get_frame_pc (fi));
418
419 struct tui_line_or_address a;
420
421 a.loa = LOA_ADDRESS;
422 a.u.addr = low;
423 if (!addr_is_displayed (addr))
424 update_source_window (get_frame_arch (fi), sal.symtab, a);
425 else
426 {
427 a.u.addr = addr;
428 set_is_exec_point_at (a);
429 }
430 }
This page took 0.044557 seconds and 5 git commands to generate.