1 /* TUI display locator. 2 3 Copyright (C) 1998-2023 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 "symtab.h" 24 #include "breakpoint.h" 25 #include "frame.h" 26 #include "command.h" 27 #include "inferior.h" 28 #include "target.h" 29 #include "top.h" 30 #include "gdb-demangle.h" 31 #include "source.h" 32 #include "tui/tui.h" 33 #include "tui/tui-data.h" 34 #include "tui/tui-stack.h" 35 #include "tui/tui-wingeneral.h" 36 #include "tui/tui-source.h" 37 #include "tui/tui-winsource.h" 38 #include "tui/tui-file.h" 39 #include "tui/tui-location.h" 40 41 #include "gdb_curses.h" 42 43 #define PROC_PREFIX "In: " 44 #define LINE_PREFIX "L" 45 #define PC_PREFIX "PC: " 46 47 /* Strings to display in the TUI status line. */ 48 #define SINGLE_KEY "(SingleKey)" 49 50 /* Minimum/Maximum length of some fields displayed in the TUI status 51 line. */ 52 #define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line 53 numbers. */ 54 #define MIN_PROC_WIDTH 12 55 #define MAX_TARGET_WIDTH 10 56 #define MAX_PID_WIDTH 19 57 58 59 60 std::string 61 tui_locator_window::make_status_line () const 62 { 63 char line_buf[50]; 64 int status_size; 65 int proc_width; 66 const char *pid_name; 67 int target_width; 68 int pid_width; 69 int line_width; 70 71 std::string pid_name_holder; 72 if (inferior_ptid == null_ptid) 73 pid_name = "No process"; 74 else 75 { 76 pid_name_holder = target_pid_to_str (inferior_ptid); 77 pid_name = pid_name_holder.c_str (); 78 } 79 80 target_width = strlen (target_shortname ()); 81 if (target_width > MAX_TARGET_WIDTH) 82 target_width = MAX_TARGET_WIDTH; 83 84 pid_width = strlen (pid_name); 85 if (pid_width > MAX_PID_WIDTH) 86 pid_width = MAX_PID_WIDTH; 87 88 status_size = width; 89 90 /* Translate line number and obtain its size. */ 91 int line_no = tui_location.line_no (); 92 if (line_no > 0) 93 xsnprintf (line_buf, sizeof (line_buf), "%d", line_no); 94 else 95 strcpy (line_buf, "??"); 96 line_width = strlen (line_buf); 97 if (line_width < MIN_LINE_WIDTH) 98 line_width = MIN_LINE_WIDTH; 99 100 /* Translate PC address. */ 101 struct gdbarch *gdbarch = tui_location.gdbarch (); 102 CORE_ADDR addr = tui_location.addr (); 103 std::string pc_out (gdbarch 104 ? paddress (gdbarch, addr) 105 : "??"); 106 const char *pc_buf = pc_out.c_str (); 107 int pc_width = pc_out.size (); 108 109 /* First determine the amount of proc name width we have available. 110 The +1 are for a space separator between fields. 111 The -1 are to take into account the \0 counted by sizeof. */ 112 proc_width = (status_size 113 - (target_width + 1) 114 - (pid_width + 1) 115 - (sizeof (PROC_PREFIX) - 1 + 1) 116 - (sizeof (LINE_PREFIX) - 1 + line_width + 1) 117 - (sizeof (PC_PREFIX) - 1 + pc_width + 1) 118 - (tui_current_key_mode == TUI_SINGLE_KEY_MODE 119 ? (sizeof (SINGLE_KEY) - 1 + 1) 120 : 0)); 121 122 /* If there is no room to print the function name, try by removing 123 some fields. */ 124 if (proc_width < MIN_PROC_WIDTH) 125 { 126 proc_width += target_width + 1; 127 target_width = 0; 128 if (proc_width < MIN_PROC_WIDTH) 129 { 130 proc_width += pid_width + 1; 131 pid_width = 0; 132 if (proc_width <= MIN_PROC_WIDTH) 133 { 134 proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1; 135 pc_width = 0; 136 if (proc_width < 0) 137 { 138 proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1; 139 line_width = 0; 140 if (proc_width < 0) 141 proc_width = 0; 142 } 143 } 144 } 145 } 146 147 /* Now create the locator line from the string version of the 148 elements. */ 149 string_file string; 150 151 if (target_width > 0) 152 string.printf ("%*.*s ", -target_width, target_width, target_shortname ()); 153 if (pid_width > 0) 154 string.printf ("%*.*s ", -pid_width, pid_width, pid_name); 155 156 /* Show whether we are in SingleKey mode. */ 157 if (tui_current_key_mode == TUI_SINGLE_KEY_MODE) 158 { 159 string.puts (SINGLE_KEY); 160 string.puts (" "); 161 } 162 163 /* Procedure/class name. */ 164 if (proc_width > 0) 165 { 166 const std::string &proc_name = tui_location.proc_name (); 167 if (proc_name.size () > proc_width) 168 string.printf ("%s%*.*s* ", PROC_PREFIX, 169 1 - proc_width, proc_width - 1, proc_name.c_str ()); 170 else 171 string.printf ("%s%*.*s ", PROC_PREFIX, 172 -proc_width, proc_width, proc_name.c_str ()); 173 } 174 175 if (line_width > 0) 176 string.printf ("%s%*.*s ", LINE_PREFIX, 177 -line_width, line_width, line_buf); 178 if (pc_width > 0) 179 { 180 string.puts (PC_PREFIX); 181 string.puts (pc_buf); 182 } 183 184 std::string string_val = string.release (); 185 186 if (string.size () < status_size) 187 string_val.append (status_size - string.size (), ' '); 188 else if (string.size () > status_size) 189 string_val.erase (status_size, string.size ()); 190 191 return string_val; 192 } 193 194 /* Get a printable name for the function at the address. The symbol 195 name is demangled if demangling is turned on. Returns a pointer to 196 a static area holding the result. */ 197 static char* 198 tui_get_function_from_frame (frame_info_ptr fi) 199 { 200 static char name[256]; 201 string_file stream; 202 203 print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi), 204 &stream, demangle, ""); 205 206 /* Use simple heuristics to isolate the function name. The symbol 207 can be demangled and we can have function parameters. Remove 208 them because the status line is too short to display them. */ 209 const char *d = stream.c_str (); 210 if (*d == '<') 211 d++; 212 strncpy (name, d, sizeof (name) - 1); 213 name[sizeof (name) - 1] = 0; 214 215 char *p = strchr (name, '('); 216 if (!p) 217 p = strchr (name, '>'); 218 if (p) 219 *p = 0; 220 p = strchr (name, '+'); 221 if (p) 222 *p = 0; 223 return name; 224 } 225 226 void 227 tui_locator_window::rerender () 228 { 229 gdb_assert (handle != NULL); 230 231 std::string string = make_status_line (); 232 scrollok (handle.get (), FALSE); 233 wmove (handle.get (), 0, 0); 234 /* We ignore the return value from wstandout and wstandend, casting them 235 to void in order to avoid a compiler warning. The warning itself was 236 introduced by a patch to ncurses 5.7 dated 2009-08-29, changing these 237 macro to expand to code that causes the compiler to generate an 238 unused-value warning. */ 239 (void) wstandout (handle.get ()); 240 waddstr (handle.get (), string.c_str ()); 241 wclrtoeol (handle.get ()); 242 (void) wstandend (handle.get ()); 243 refresh_window (); 244 wmove (handle.get (), 0, 0); 245 } 246 247 /* Function to print the frame information for the TUI. The windows are 248 refreshed only if frame information has changed since the last refresh. 249 250 Return true if frame information has changed (and windows 251 subsequently refreshed), false otherwise. */ 252 253 bool 254 tui_show_frame_info (frame_info_ptr fi) 255 { 256 bool locator_changed_p; 257 258 if (fi != nullptr) 259 { 260 symtab_and_line sal = find_frame_sal (fi); 261 262 const char *func_name; 263 /* find_frame_sal does not always set PC, but we want to ensure 264 that it is available in the SAL. */ 265 if (get_frame_pc_if_available (fi, &sal.pc)) 266 func_name = tui_get_function_from_frame (fi); 267 else 268 func_name = _("<unavailable>"); 269 270 locator_changed_p 271 = tui_location.set_location (get_frame_arch (fi), sal, func_name); 272 273 /* If the locator information has not changed, then frame information has 274 not changed. If frame information has not changed, then the windows' 275 contents will not change. So don't bother refreshing the windows. */ 276 if (!locator_changed_p) 277 return false; 278 279 for (struct tui_source_window_base *win_info : tui_source_windows ()) 280 { 281 win_info->maybe_update (fi, sal); 282 win_info->update_exec_info (); 283 } 284 } 285 else 286 { 287 symtab_and_line sal {}; 288 289 locator_changed_p = tui_location.set_location (NULL, sal, ""); 290 291 if (!locator_changed_p) 292 return false; 293 294 for (struct tui_source_window_base *win_info : tui_source_windows ()) 295 win_info->erase_source_content (); 296 } 297 298 return true; 299 } 300 301 void 302 tui_show_locator_content () 303 { 304 if (tui_is_window_visible (STATUS_WIN)) 305 TUI_STATUS_WIN->rerender (); 306 } 307 308 /* Command to update the display with the current execution point. */ 309 static void 310 tui_update_command (const char *arg, int from_tty) 311 { 312 execute_command ("frame 0", from_tty); 313 } 314 315 /* Function to initialize gdb commands, for tui window stack 316 manipulation. */ 317 318 void _initialize_tui_stack (); 319 void 320 _initialize_tui_stack () 321 { 322 add_com ("update", class_tui, tui_update_command, 323 _("Update the source window and locator to " 324 "display the current execution point.\n\ 325 Usage: update")); 326 } 327