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