tui-winsource.c revision 1.9 1 1.1 christos /* TUI display source/assembly window.
2 1.1 christos
3 1.9 christos Copyright (C) 1998-2020 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos Contributed by Hewlett-Packard Company.
6 1.1 christos
7 1.1 christos This file is part of GDB.
8 1.1 christos
9 1.1 christos This program is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 3 of the License, or
12 1.1 christos (at your option) any later version.
13 1.1 christos
14 1.1 christos This program is distributed in the hope that it will be useful,
15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 christos GNU General Public License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 1.1 christos
22 1.1 christos #include "defs.h"
23 1.1 christos #include <ctype.h>
24 1.1 christos #include "symtab.h"
25 1.1 christos #include "frame.h"
26 1.1 christos #include "breakpoint.h"
27 1.1 christos #include "value.h"
28 1.1 christos #include "source.h"
29 1.1 christos #include "objfiles.h"
30 1.1 christos #include "filenames.h"
31 1.1 christos
32 1.1 christos #include "tui/tui.h"
33 1.1 christos #include "tui/tui-data.h"
34 1.8 christos #include "tui/tui-io.h"
35 1.1 christos #include "tui/tui-stack.h"
36 1.1 christos #include "tui/tui-win.h"
37 1.1 christos #include "tui/tui-wingeneral.h"
38 1.1 christos #include "tui/tui-winsource.h"
39 1.1 christos #include "tui/tui-source.h"
40 1.1 christos #include "tui/tui-disasm.h"
41 1.1 christos #include "gdb_curses.h"
42 1.1 christos
43 1.1 christos /* Function to display the "main" routine. */
44 1.1 christos void
45 1.9 christos tui_display_main ()
46 1.1 christos {
47 1.9 christos auto adapter = tui_source_windows ();
48 1.9 christos if (adapter.begin () != adapter.end ())
49 1.1 christos {
50 1.1 christos struct gdbarch *gdbarch;
51 1.1 christos CORE_ADDR addr;
52 1.1 christos
53 1.1 christos tui_get_begin_asm_address (&gdbarch, &addr);
54 1.1 christos if (addr != (CORE_ADDR) 0)
55 1.1 christos {
56 1.3 christos struct symtab *s;
57 1.1 christos
58 1.1 christos tui_update_source_windows_with_addr (gdbarch, addr);
59 1.3 christos s = find_pc_line_symtab (addr);
60 1.9 christos tui_update_locator_fullname (s);
61 1.1 christos }
62 1.1 christos }
63 1.1 christos }
64 1.1 christos
65 1.9 christos /* See tui-winsource.h. */
66 1.1 christos
67 1.9 christos std::string
68 1.9 christos tui_copy_source_line (const char **ptr, int line_no, int first_col,
69 1.9 christos int line_width, int ndigits)
70 1.9 christos {
71 1.9 christos const char *lineptr = *ptr;
72 1.9 christos
73 1.9 christos /* Init the line with the line number. */
74 1.9 christos std::string result;
75 1.9 christos
76 1.9 christos if (line_no > 0)
77 1.9 christos {
78 1.9 christos if (ndigits > 0)
79 1.9 christos result = string_printf ("%*d ", ndigits, line_no);
80 1.9 christos else
81 1.9 christos {
82 1.9 christos result = string_printf ("%-6d", line_no);
83 1.9 christos int len = result.size ();
84 1.9 christos len = len - ((len / tui_tab_width) * tui_tab_width);
85 1.9 christos result.append (len, ' ');
86 1.9 christos }
87 1.9 christos }
88 1.9 christos
89 1.9 christos int column = 0;
90 1.9 christos char c;
91 1.9 christos do
92 1.9 christos {
93 1.9 christos int skip_bytes;
94 1.9 christos
95 1.9 christos c = *lineptr;
96 1.9 christos if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes))
97 1.9 christos {
98 1.9 christos /* We always have to preserve escapes. */
99 1.9 christos result.append (lineptr, lineptr + skip_bytes);
100 1.9 christos lineptr += skip_bytes;
101 1.9 christos continue;
102 1.9 christos }
103 1.9 christos if (c == '\0')
104 1.9 christos break;
105 1.9 christos
106 1.9 christos ++lineptr;
107 1.9 christos ++column;
108 1.9 christos
109 1.9 christos auto process_tab = [&] ()
110 1.9 christos {
111 1.9 christos int max_tab_len = tui_tab_width;
112 1.9 christos
113 1.9 christos --column;
114 1.9 christos for (int j = column % max_tab_len;
115 1.9 christos j < max_tab_len && column < first_col + line_width;
116 1.9 christos column++, j++)
117 1.9 christos if (column >= first_col)
118 1.9 christos result.push_back (' ');
119 1.9 christos };
120 1.9 christos
121 1.9 christos /* We have to process all the text in order to pick up all the
122 1.9 christos escapes. */
123 1.9 christos if (column <= first_col || column > first_col + line_width)
124 1.9 christos {
125 1.9 christos if (c == '\t')
126 1.9 christos process_tab ();
127 1.9 christos continue;
128 1.9 christos }
129 1.9 christos
130 1.9 christos if (c == '\n' || c == '\r' || c == '\0')
131 1.9 christos {
132 1.9 christos /* Nothing. */
133 1.9 christos }
134 1.9 christos else if (c < 040 && c != '\t')
135 1.9 christos {
136 1.9 christos result.push_back ('^');
137 1.9 christos result.push_back (c + 0100);
138 1.9 christos }
139 1.9 christos else if (c == 0177)
140 1.9 christos {
141 1.9 christos result.push_back ('^');
142 1.9 christos result.push_back ('?');
143 1.9 christos }
144 1.9 christos else if (c == '\t')
145 1.9 christos process_tab ();
146 1.9 christos else
147 1.9 christos result.push_back (c);
148 1.9 christos }
149 1.9 christos while (c != '\0' && c != '\n' && c != '\r');
150 1.9 christos
151 1.9 christos if (c == '\r' && *lineptr == '\n')
152 1.9 christos ++lineptr;
153 1.9 christos *ptr = lineptr;
154 1.9 christos
155 1.9 christos return result;
156 1.9 christos }
157 1.9 christos
158 1.9 christos void
159 1.9 christos tui_source_window_base::style_changed ()
160 1.9 christos {
161 1.9 christos if (tui_active && is_visible ())
162 1.9 christos refill ();
163 1.9 christos }
164 1.1 christos
165 1.1 christos /* Function to display source in the source window. This function
166 1.1 christos initializes the horizontal scroll to 0. */
167 1.1 christos void
168 1.9 christos tui_source_window_base::update_source_window
169 1.9 christos (struct gdbarch *gdbarch,
170 1.9 christos const struct symtab_and_line &sal)
171 1.1 christos {
172 1.9 christos m_horizontal_offset = 0;
173 1.9 christos update_source_window_as_is (gdbarch, sal);
174 1.1 christos }
175 1.1 christos
176 1.1 christos
177 1.1 christos /* Function to display source in the source/asm window. This function
178 1.1 christos shows the source as specified by the horizontal offset. */
179 1.1 christos void
180 1.9 christos tui_source_window_base::update_source_window_as_is
181 1.9 christos (struct gdbarch *gdbarch,
182 1.9 christos const struct symtab_and_line &sal)
183 1.1 christos {
184 1.9 christos bool ret = set_contents (gdbarch, sal);
185 1.1 christos
186 1.9 christos if (!ret)
187 1.9 christos erase_source_content ();
188 1.1 christos else
189 1.1 christos {
190 1.9 christos update_breakpoint_info (nullptr, false);
191 1.9 christos show_source_content ();
192 1.9 christos update_exec_info ();
193 1.1 christos }
194 1.1 christos }
195 1.1 christos
196 1.1 christos
197 1.1 christos /* Function to ensure that the source and/or disassemly windows
198 1.1 christos reflect the input address. */
199 1.1 christos void
200 1.1 christos tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
201 1.1 christos {
202 1.9 christos struct symtab_and_line sal {};
203 1.1 christos if (addr != 0)
204 1.9 christos sal = find_pc_line (addr, 0);
205 1.1 christos
206 1.9 christos for (struct tui_source_window_base *win_info : tui_source_windows ())
207 1.9 christos win_info->update_source_window (gdbarch, sal);
208 1.1 christos }
209 1.1 christos
210 1.9 christos /* Function to ensure that the source and/or disassembly windows
211 1.9 christos reflect the symtab and line. */
212 1.1 christos void
213 1.9 christos tui_update_source_windows_with_line (struct symtab_and_line sal)
214 1.1 christos {
215 1.9 christos struct gdbarch *gdbarch = nullptr;
216 1.9 christos if (sal.symtab != nullptr)
217 1.9 christos {
218 1.9 christos find_line_pc (sal.symtab, sal.line, &sal.pc);
219 1.9 christos gdbarch = SYMTAB_OBJFILE (sal.symtab)->arch ();
220 1.1 christos }
221 1.1 christos
222 1.9 christos for (struct tui_source_window_base *win_info : tui_source_windows ())
223 1.9 christos win_info->update_source_window (gdbarch, sal);
224 1.1 christos }
225 1.1 christos
226 1.1 christos void
227 1.9 christos tui_source_window_base::do_erase_source_content (const char *str)
228 1.1 christos {
229 1.9 christos int x_pos;
230 1.9 christos int half_width = (width - 2) / 2;
231 1.9 christos
232 1.9 christos m_content.clear ();
233 1.9 christos if (handle != NULL)
234 1.1 christos {
235 1.9 christos werase (handle.get ());
236 1.9 christos check_and_display_highlight_if_needed ();
237 1.1 christos
238 1.9 christos if (strlen (str) >= half_width)
239 1.9 christos x_pos = 1;
240 1.9 christos else
241 1.9 christos x_pos = half_width - strlen (str);
242 1.9 christos mvwaddstr (handle.get (),
243 1.9 christos (height / 2),
244 1.9 christos x_pos,
245 1.9 christos (char *) str);
246 1.1 christos
247 1.9 christos refresh_window ();
248 1.1 christos }
249 1.1 christos }
250 1.1 christos
251 1.1 christos
252 1.9 christos /* Redraw the complete line of a source or disassembly window. */
253 1.1 christos void
254 1.9 christos tui_source_window_base::show_source_line (int lineno)
255 1.1 christos {
256 1.9 christos struct tui_source_element *line;
257 1.9 christos int x;
258 1.9 christos
259 1.9 christos line = &m_content[lineno - 1];
260 1.9 christos if (line->is_exec_point)
261 1.9 christos tui_set_reverse_mode (handle.get (), true);
262 1.9 christos
263 1.9 christos wmove (handle.get (), lineno, TUI_EXECINFO_SIZE);
264 1.9 christos tui_puts (line->line.c_str (), handle.get ());
265 1.9 christos if (line->is_exec_point)
266 1.9 christos tui_set_reverse_mode (handle.get (), false);
267 1.1 christos
268 1.9 christos /* Clear to end of line but stop before the border. */
269 1.9 christos x = getcurx (handle.get ());
270 1.9 christos while (x + 1 < width)
271 1.1 christos {
272 1.9 christos waddch (handle.get (), ' ');
273 1.9 christos x = getcurx (handle.get ());
274 1.9 christos }
275 1.9 christos }
276 1.9 christos
277 1.9 christos void
278 1.9 christos tui_source_window_base::show_source_content ()
279 1.9 christos {
280 1.9 christos gdb_assert (!m_content.empty ());
281 1.1 christos
282 1.9 christos for (int lineno = 1; lineno <= m_content.size (); lineno++)
283 1.9 christos show_source_line (lineno);
284 1.1 christos
285 1.9 christos check_and_display_highlight_if_needed ();
286 1.9 christos refresh_window ();
287 1.1 christos }
288 1.1 christos
289 1.9 christos tui_source_window_base::tui_source_window_base ()
290 1.9 christos {
291 1.9 christos m_start_line_or_addr.loa = LOA_ADDRESS;
292 1.9 christos m_start_line_or_addr.u.addr = 0;
293 1.9 christos
294 1.9 christos gdb::observers::source_styling_changed.attach
295 1.9 christos (std::bind (&tui_source_window::style_changed, this),
296 1.9 christos m_observable);
297 1.9 christos }
298 1.1 christos
299 1.9 christos tui_source_window_base::~tui_source_window_base ()
300 1.1 christos {
301 1.9 christos gdb::observers::source_styling_changed.detach (m_observable);
302 1.9 christos }
303 1.1 christos
304 1.9 christos /* See tui-data.h. */
305 1.1 christos
306 1.9 christos void
307 1.9 christos tui_source_window_base::update_tab_width ()
308 1.9 christos {
309 1.9 christos werase (handle.get ());
310 1.9 christos rerender ();
311 1.1 christos }
312 1.1 christos
313 1.1 christos void
314 1.9 christos tui_source_window_base::rerender ()
315 1.1 christos {
316 1.9 christos if (!m_content.empty ())
317 1.1 christos {
318 1.9 christos struct symtab_and_line cursal
319 1.9 christos = get_current_source_symtab_and_line ();
320 1.1 christos
321 1.9 christos if (m_start_line_or_addr.loa == LOA_LINE)
322 1.9 christos cursal.line = m_start_line_or_addr.u.line_no;
323 1.9 christos else
324 1.9 christos cursal.pc = m_start_line_or_addr.u.addr;
325 1.9 christos update_source_window (m_gdbarch, cursal);
326 1.9 christos }
327 1.9 christos else if (deprecated_safe_get_selected_frame () != NULL)
328 1.9 christos {
329 1.9 christos struct symtab_and_line cursal
330 1.9 christos = get_current_source_symtab_and_line ();
331 1.9 christos struct frame_info *frame = deprecated_safe_get_selected_frame ();
332 1.9 christos struct gdbarch *gdbarch = get_frame_arch (frame);
333 1.9 christos
334 1.9 christos struct symtab *s = find_pc_line_symtab (get_frame_pc (frame));
335 1.9 christos if (this != TUI_SRC_WIN)
336 1.9 christos find_line_pc (s, cursal.line, &cursal.pc);
337 1.9 christos update_source_window (gdbarch, cursal);
338 1.1 christos }
339 1.1 christos else
340 1.9 christos erase_source_content ();
341 1.1 christos }
342 1.1 christos
343 1.9 christos /* See tui-data.h. */
344 1.8 christos
345 1.8 christos void
346 1.9 christos tui_source_window_base::refill ()
347 1.8 christos {
348 1.9 christos symtab_and_line sal {};
349 1.8 christos
350 1.9 christos if (this == TUI_SRC_WIN)
351 1.8 christos {
352 1.9 christos sal = get_current_source_symtab_and_line ();
353 1.9 christos if (sal.symtab == NULL)
354 1.9 christos {
355 1.9 christos struct frame_info *fi = deprecated_safe_get_selected_frame ();
356 1.9 christos if (fi != nullptr)
357 1.9 christos sal = find_pc_line (get_frame_pc (fi), 0);
358 1.9 christos }
359 1.8 christos }
360 1.8 christos
361 1.9 christos if (sal.pspace == nullptr)
362 1.9 christos sal.pspace = current_program_space;
363 1.9 christos
364 1.9 christos if (m_start_line_or_addr.loa == LOA_LINE)
365 1.9 christos sal.line = m_start_line_or_addr.u.line_no;
366 1.9 christos else
367 1.9 christos sal.pc = m_start_line_or_addr.u.addr;
368 1.9 christos
369 1.9 christos update_source_window_as_is (m_gdbarch, sal);
370 1.8 christos }
371 1.1 christos
372 1.1 christos /* Scroll the source forward or backward horizontally. */
373 1.8 christos
374 1.1 christos void
375 1.9 christos tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
376 1.1 christos {
377 1.9 christos if (!m_content.empty ())
378 1.1 christos {
379 1.9 christos int offset = m_horizontal_offset + num_to_scroll;
380 1.9 christos if (offset < 0)
381 1.9 christos offset = 0;
382 1.9 christos m_horizontal_offset = offset;
383 1.9 christos refill ();
384 1.1 christos }
385 1.1 christos }
386 1.1 christos
387 1.1 christos
388 1.9 christos /* Set or clear the is_exec_point flag in the line whose line is
389 1.1 christos line_no. */
390 1.1 christos
391 1.1 christos void
392 1.9 christos tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
393 1.1 christos {
394 1.9 christos bool changed = false;
395 1.1 christos int i;
396 1.1 christos
397 1.1 christos i = 0;
398 1.9 christos while (i < m_content.size ())
399 1.1 christos {
400 1.9 christos bool new_state;
401 1.1 christos struct tui_line_or_address content_loa =
402 1.9 christos m_content[i].line_or_addr;
403 1.1 christos
404 1.1 christos if (content_loa.loa == l.loa
405 1.1 christos && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
406 1.9 christos || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr)))
407 1.9 christos new_state = true;
408 1.1 christos else
409 1.9 christos new_state = false;
410 1.9 christos if (new_state != m_content[i].is_exec_point)
411 1.1 christos {
412 1.9 christos changed = true;
413 1.9 christos m_content[i].is_exec_point = new_state;
414 1.9 christos show_source_line (i + 1);
415 1.1 christos }
416 1.1 christos i++;
417 1.1 christos }
418 1.1 christos if (changed)
419 1.9 christos refill ();
420 1.1 christos }
421 1.1 christos
422 1.9 christos /* See tui-winsource.h. */
423 1.9 christos
424 1.1 christos void
425 1.9 christos tui_update_all_breakpoint_info (struct breakpoint *being_deleted)
426 1.1 christos {
427 1.9 christos for (tui_source_window_base *win : tui_source_windows ())
428 1.1 christos {
429 1.9 christos if (win->update_breakpoint_info (being_deleted, false))
430 1.9 christos win->update_exec_info ();
431 1.1 christos }
432 1.1 christos }
433 1.1 christos
434 1.1 christos
435 1.9 christos /* Scan the source window and the breakpoints to update the break_mode
436 1.1 christos information for each line.
437 1.1 christos
438 1.9 christos Returns true if something changed and the execution window must be
439 1.1 christos refreshed. */
440 1.1 christos
441 1.9 christos bool
442 1.9 christos tui_source_window_base::update_breakpoint_info
443 1.9 christos (struct breakpoint *being_deleted, bool current_only)
444 1.1 christos {
445 1.1 christos int i;
446 1.9 christos bool need_refresh = false;
447 1.1 christos
448 1.9 christos for (i = 0; i < m_content.size (); i++)
449 1.1 christos {
450 1.1 christos struct tui_source_element *line;
451 1.1 christos
452 1.9 christos line = &m_content[i];
453 1.1 christos if (current_only && !line->is_exec_point)
454 1.1 christos continue;
455 1.1 christos
456 1.1 christos /* Scan each breakpoint to see if the current line has something to
457 1.1 christos do with it. Identify enable/disabled breakpoints as well as
458 1.1 christos those that we already hit. */
459 1.9 christos tui_bp_flags mode = 0;
460 1.9 christos iterate_over_breakpoints ([&] (breakpoint *bp) -> bool
461 1.1 christos {
462 1.1 christos struct bp_location *loc;
463 1.1 christos
464 1.9 christos if (bp == being_deleted)
465 1.9 christos return false;
466 1.1 christos
467 1.1 christos for (loc = bp->loc; loc != NULL; loc = loc->next)
468 1.1 christos {
469 1.9 christos if (location_matches_p (loc, i))
470 1.1 christos {
471 1.1 christos if (bp->enable_state == bp_disabled)
472 1.1 christos mode |= TUI_BP_DISABLED;
473 1.1 christos else
474 1.1 christos mode |= TUI_BP_ENABLED;
475 1.1 christos if (bp->hit_count)
476 1.1 christos mode |= TUI_BP_HIT;
477 1.1 christos if (bp->loc->cond)
478 1.1 christos mode |= TUI_BP_CONDITIONAL;
479 1.1 christos if (bp->type == bp_hardware_breakpoint)
480 1.1 christos mode |= TUI_BP_HARDWARE;
481 1.1 christos }
482 1.1 christos }
483 1.9 christos return false;
484 1.9 christos });
485 1.9 christos if (line->break_mode != mode)
486 1.1 christos {
487 1.9 christos line->break_mode = mode;
488 1.9 christos need_refresh = true;
489 1.1 christos }
490 1.1 christos }
491 1.1 christos return need_refresh;
492 1.1 christos }
493 1.1 christos
494 1.1 christos /* Function to initialize the content of the execution info window,
495 1.1 christos based upon the input window which is either the source or
496 1.1 christos disassembly window. */
497 1.1 christos void
498 1.9 christos tui_source_window_base::update_exec_info ()
499 1.1 christos {
500 1.9 christos update_breakpoint_info (nullptr, true);
501 1.9 christos for (int i = 0; i < m_content.size (); i++)
502 1.1 christos {
503 1.9 christos struct tui_source_element *src_element = &m_content[i];
504 1.9 christos char element[TUI_EXECINFO_SIZE] = " ";
505 1.1 christos
506 1.9 christos /* Now update the exec info content based upon the state
507 1.9 christos of each line as indicated by the source content. */
508 1.9 christos tui_bp_flags mode = src_element->break_mode;
509 1.9 christos if (mode & TUI_BP_HIT)
510 1.9 christos element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
511 1.9 christos else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
512 1.9 christos element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
513 1.1 christos
514 1.9 christos if (mode & TUI_BP_ENABLED)
515 1.9 christos element[TUI_BP_BREAK_POS] = '+';
516 1.9 christos else if (mode & TUI_BP_DISABLED)
517 1.9 christos element[TUI_BP_BREAK_POS] = '-';
518 1.1 christos
519 1.9 christos if (src_element->is_exec_point)
520 1.9 christos element[TUI_EXEC_POS] = '>';
521 1.1 christos
522 1.9 christos mvwaddstr (handle.get (), i + 1, 1, element);
523 1.1 christos }
524 1.9 christos refresh_window ();
525 1.1 christos }
526