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