1 /* Copyright (C) 1986-2023 Free Software Foundation, Inc. 2 3 This file is part of GDB. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "defs.h" 19 #include "gdbcmd.h" 20 #include "regcache.h" 21 #include "gdbsupport/def-vector.h" 22 #include "valprint.h" 23 #include "remote.h" 24 #include "reggroups.h" 25 #include "target.h" 26 #include "gdbarch.h" 27 28 /* Dump registers from regcache, used for dumping raw registers and 29 cooked registers. */ 30 31 class register_dump_regcache : public register_dump 32 { 33 public: 34 register_dump_regcache (regcache *regcache, bool dump_pseudo) 35 : register_dump (regcache->arch ()), m_regcache (regcache), 36 m_dump_pseudo (dump_pseudo) 37 { 38 } 39 40 protected: 41 void dump_reg (ui_file *file, int regnum) override 42 { 43 if (regnum < 0) 44 { 45 if (m_dump_pseudo) 46 gdb_printf (file, "Cooked value"); 47 else 48 gdb_printf (file, "Raw value"); 49 } 50 else 51 { 52 if (regnum < gdbarch_num_regs (m_gdbarch) || m_dump_pseudo) 53 { 54 auto size = register_size (m_gdbarch, regnum); 55 56 if (size == 0) 57 return; 58 59 gdb::def_vector<gdb_byte> buf (size); 60 auto status = m_regcache->cooked_read (regnum, buf.data ()); 61 62 if (status == REG_UNKNOWN) 63 gdb_printf (file, "<invalid>"); 64 else if (status == REG_UNAVAILABLE) 65 gdb_printf (file, "<unavailable>"); 66 else 67 { 68 print_hex_chars (file, buf.data (), size, 69 gdbarch_byte_order (m_gdbarch), true); 70 } 71 } 72 else 73 { 74 /* Just print "<cooked>" for pseudo register when 75 regcache_dump_raw. */ 76 gdb_printf (file, "<cooked>"); 77 } 78 } 79 } 80 81 private: 82 regcache *m_regcache; 83 84 /* Dump pseudo registers or not. */ 85 const bool m_dump_pseudo; 86 }; 87 88 /* Dump from reg_buffer, used when there is no thread or 89 registers. */ 90 91 class register_dump_reg_buffer : public register_dump, reg_buffer 92 { 93 public: 94 register_dump_reg_buffer (gdbarch *gdbarch, bool dump_pseudo) 95 : register_dump (gdbarch), reg_buffer (gdbarch, dump_pseudo) 96 { 97 } 98 99 protected: 100 void dump_reg (ui_file *file, int regnum) override 101 { 102 if (regnum < 0) 103 { 104 if (m_has_pseudo) 105 gdb_printf (file, "Cooked value"); 106 else 107 gdb_printf (file, "Raw value"); 108 } 109 else 110 { 111 if (regnum < gdbarch_num_regs (m_gdbarch) || m_has_pseudo) 112 { 113 auto size = register_size (m_gdbarch, regnum); 114 115 if (size == 0) 116 return; 117 118 auto status = get_register_status (regnum); 119 120 gdb_assert (status != REG_VALID); 121 122 if (status == REG_UNKNOWN) 123 gdb_printf (file, "<invalid>"); 124 else 125 gdb_printf (file, "<unavailable>"); 126 } 127 else 128 { 129 /* Just print "<cooked>" for pseudo register when 130 regcache_dump_raw. */ 131 gdb_printf (file, "<cooked>"); 132 } 133 } 134 } 135 }; 136 137 /* For "maint print registers". */ 138 139 class register_dump_none : public register_dump 140 { 141 public: 142 register_dump_none (gdbarch *arch) 143 : register_dump (arch) 144 {} 145 146 protected: 147 void dump_reg (ui_file *file, int regnum) override 148 {} 149 }; 150 151 /* For "maint print remote-registers". */ 152 153 class register_dump_remote : public register_dump 154 { 155 public: 156 register_dump_remote (gdbarch *arch) 157 : register_dump (arch) 158 {} 159 160 protected: 161 void dump_reg (ui_file *file, int regnum) override 162 { 163 if (regnum < 0) 164 { 165 gdb_printf (file, "Rmt Nr g/G Offset"); 166 } 167 else if (regnum < gdbarch_num_regs (m_gdbarch)) 168 { 169 int pnum, poffset; 170 171 if (remote_register_number_and_offset (m_gdbarch, regnum, 172 &pnum, &poffset)) 173 gdb_printf (file, "%7d %11d", pnum, poffset); 174 } 175 } 176 }; 177 178 /* For "maint print register-groups". */ 179 180 class register_dump_groups : public register_dump 181 { 182 public: 183 register_dump_groups (gdbarch *arch) 184 : register_dump (arch) 185 {} 186 187 protected: 188 void dump_reg (ui_file *file, int regnum) override 189 { 190 if (regnum < 0) 191 gdb_printf (file, "Groups"); 192 else 193 { 194 const char *sep = ""; 195 for (const struct reggroup *group : gdbarch_reggroups (m_gdbarch)) 196 { 197 if (gdbarch_register_reggroup_p (m_gdbarch, regnum, group)) 198 { 199 gdb_printf (file, "%s%s", sep, group->name ()); 200 sep = ","; 201 } 202 } 203 } 204 } 205 }; 206 207 enum regcache_dump_what 208 { 209 regcache_dump_none, regcache_dump_raw, 210 regcache_dump_cooked, regcache_dump_groups, 211 regcache_dump_remote 212 }; 213 214 static void 215 regcache_print (const char *args, enum regcache_dump_what what_to_dump) 216 { 217 /* Where to send output. */ 218 stdio_file file; 219 ui_file *out; 220 221 if (args == NULL) 222 out = gdb_stdout; 223 else 224 { 225 if (!file.open (args, "w")) 226 perror_with_name (_("maintenance print architecture")); 227 out = &file; 228 } 229 230 std::unique_ptr<register_dump> dump; 231 std::unique_ptr<regcache> regs; 232 gdbarch *gdbarch; 233 234 if (target_has_registers ()) 235 gdbarch = get_current_regcache ()->arch (); 236 else 237 gdbarch = target_gdbarch (); 238 239 switch (what_to_dump) 240 { 241 case regcache_dump_none: 242 dump.reset (new register_dump_none (gdbarch)); 243 break; 244 case regcache_dump_remote: 245 dump.reset (new register_dump_remote (gdbarch)); 246 break; 247 case regcache_dump_groups: 248 dump.reset (new register_dump_groups (gdbarch)); 249 break; 250 case regcache_dump_raw: 251 case regcache_dump_cooked: 252 { 253 auto dump_pseudo = (what_to_dump == regcache_dump_cooked); 254 255 if (target_has_registers ()) 256 dump.reset (new register_dump_regcache (get_current_regcache (), 257 dump_pseudo)); 258 else 259 { 260 /* For the benefit of "maint print registers" & co when 261 debugging an executable, allow dumping a regcache even when 262 there is no thread selected / no registers. */ 263 dump.reset (new register_dump_reg_buffer (target_gdbarch (), 264 dump_pseudo)); 265 } 266 } 267 break; 268 } 269 270 dump->dump (out); 271 } 272 273 static void 274 maintenance_print_registers (const char *args, int from_tty) 275 { 276 regcache_print (args, regcache_dump_none); 277 } 278 279 static void 280 maintenance_print_raw_registers (const char *args, int from_tty) 281 { 282 regcache_print (args, regcache_dump_raw); 283 } 284 285 static void 286 maintenance_print_cooked_registers (const char *args, int from_tty) 287 { 288 regcache_print (args, regcache_dump_cooked); 289 } 290 291 static void 292 maintenance_print_register_groups (const char *args, int from_tty) 293 { 294 regcache_print (args, regcache_dump_groups); 295 } 296 297 static void 298 maintenance_print_remote_registers (const char *args, int from_tty) 299 { 300 regcache_print (args, regcache_dump_remote); 301 } 302 303 void _initialize_regcache_dump (); 304 void 305 _initialize_regcache_dump () 306 { 307 add_cmd ("registers", class_maintenance, maintenance_print_registers, 308 _("Print the internal register configuration.\n" 309 "Takes an optional file parameter."), &maintenanceprintlist); 310 add_cmd ("raw-registers", class_maintenance, 311 maintenance_print_raw_registers, 312 _("Print the internal register configuration " 313 "including raw values.\n" 314 "Takes an optional file parameter."), &maintenanceprintlist); 315 add_cmd ("cooked-registers", class_maintenance, 316 maintenance_print_cooked_registers, 317 _("Print the internal register configuration " 318 "including cooked values.\n" 319 "Takes an optional file parameter."), &maintenanceprintlist); 320 add_cmd ("register-groups", class_maintenance, 321 maintenance_print_register_groups, 322 _("Print the internal register configuration " 323 "including each register's group.\n" 324 "Takes an optional file parameter."), 325 &maintenanceprintlist); 326 add_cmd ("remote-registers", class_maintenance, 327 maintenance_print_remote_registers, _("\ 328 Print the internal register configuration including remote register number " 329 "and g/G packets offset.\n\ 330 Takes an optional file parameter."), 331 &maintenanceprintlist); 332 } 333