1 //===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectRegister.h" 10 #include "lldb/Core/Debugger.h" 11 #include "lldb/Core/DumpRegisterValue.h" 12 #include "lldb/Host/OptionParser.h" 13 #include "lldb/Interpreter/CommandInterpreter.h" 14 #include "lldb/Interpreter/CommandReturnObject.h" 15 #include "lldb/Interpreter/OptionGroupFormat.h" 16 #include "lldb/Interpreter/OptionValueArray.h" 17 #include "lldb/Interpreter/OptionValueBoolean.h" 18 #include "lldb/Interpreter/OptionValueUInt64.h" 19 #include "lldb/Interpreter/Options.h" 20 #include "lldb/Target/ExecutionContext.h" 21 #include "lldb/Target/Process.h" 22 #include "lldb/Target/RegisterContext.h" 23 #include "lldb/Target/SectionLoadList.h" 24 #include "lldb/Target/Thread.h" 25 #include "lldb/Utility/Args.h" 26 #include "lldb/Utility/DataExtractor.h" 27 #include "lldb/Utility/RegisterValue.h" 28 #include "lldb/Utility/Scalar.h" 29 #include "llvm/Support/Errno.h" 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 // "register read" 35 #define LLDB_OPTIONS_register_read 36 #include "CommandOptions.inc" 37 38 class CommandObjectRegisterRead : public CommandObjectParsed { 39 public: 40 CommandObjectRegisterRead(CommandInterpreter &interpreter) 41 : CommandObjectParsed( 42 interpreter, "register read", 43 "Dump the contents of one or more register values from the current " 44 "frame. If no register is specified, dumps them all.", 45 nullptr, 46 eCommandRequiresFrame | eCommandRequiresRegContext | 47 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 48 m_option_group(), m_format_options(eFormatDefault), 49 m_command_options() { 50 CommandArgumentEntry arg; 51 CommandArgumentData register_arg; 52 53 // Define the first (and only) variant of this arg. 54 register_arg.arg_type = eArgTypeRegisterName; 55 register_arg.arg_repetition = eArgRepeatStar; 56 57 // There is only one variant this argument could be; put it into the 58 // argument entry. 59 arg.push_back(register_arg); 60 61 // Push the data for the first argument into the m_arguments vector. 62 m_arguments.push_back(arg); 63 64 // Add the "--format" 65 m_option_group.Append(&m_format_options, 66 OptionGroupFormat::OPTION_GROUP_FORMAT | 67 OptionGroupFormat::OPTION_GROUP_GDB_FMT, 68 LLDB_OPT_SET_ALL); 69 m_option_group.Append(&m_command_options); 70 m_option_group.Finalize(); 71 } 72 73 ~CommandObjectRegisterRead() override = default; 74 75 Options *GetOptions() override { return &m_option_group; } 76 77 bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, 78 RegisterContext *reg_ctx, const RegisterInfo *reg_info) { 79 if (reg_info) { 80 RegisterValue reg_value; 81 82 if (reg_ctx->ReadRegister(reg_info, reg_value)) { 83 strm.Indent(); 84 85 bool prefix_with_altname = (bool)m_command_options.alternate_name; 86 bool prefix_with_name = !prefix_with_altname; 87 DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name, 88 prefix_with_altname, m_format_options.GetFormat(), 8); 89 if ((reg_info->encoding == eEncodingUint) || 90 (reg_info->encoding == eEncodingSint)) { 91 Process *process = exe_ctx.GetProcessPtr(); 92 if (process && reg_info->byte_size == process->GetAddressByteSize()) { 93 addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS); 94 if (reg_addr != LLDB_INVALID_ADDRESS) { 95 Address so_reg_addr; 96 if (exe_ctx.GetTargetRef() 97 .GetSectionLoadList() 98 .ResolveLoadAddress(reg_addr, so_reg_addr)) { 99 strm.PutCString(" "); 100 so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), 101 Address::DumpStyleResolvedDescription); 102 } 103 } 104 } 105 } 106 strm.EOL(); 107 return true; 108 } 109 } 110 return false; 111 } 112 113 bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm, 114 RegisterContext *reg_ctx, size_t set_idx, 115 bool primitive_only = false) { 116 uint32_t unavailable_count = 0; 117 uint32_t available_count = 0; 118 119 if (!reg_ctx) 120 return false; // thread has no registers (i.e. core files are corrupt, 121 // incomplete crash logs...) 122 123 const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx); 124 if (reg_set) { 125 strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown")); 126 strm.IndentMore(); 127 const size_t num_registers = reg_set->num_registers; 128 for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { 129 const uint32_t reg = reg_set->registers[reg_idx]; 130 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg); 131 // Skip the dumping of derived register if primitive_only is true. 132 if (primitive_only && reg_info && reg_info->value_regs) 133 continue; 134 135 if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info)) 136 ++available_count; 137 else 138 ++unavailable_count; 139 } 140 strm.IndentLess(); 141 if (unavailable_count) { 142 strm.Indent(); 143 strm.Printf("%u registers were unavailable.\n", unavailable_count); 144 } 145 strm.EOL(); 146 } 147 return available_count > 0; 148 } 149 150 protected: 151 bool DoExecute(Args &command, CommandReturnObject &result) override { 152 Stream &strm = result.GetOutputStream(); 153 RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 154 155 const RegisterInfo *reg_info = nullptr; 156 if (command.GetArgumentCount() == 0) { 157 size_t set_idx; 158 159 size_t num_register_sets = 1; 160 const size_t set_array_size = m_command_options.set_indexes.GetSize(); 161 if (set_array_size > 0) { 162 for (size_t i = 0; i < set_array_size; ++i) { 163 set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX, 164 nullptr); 165 if (set_idx < reg_ctx->GetRegisterSetCount()) { 166 if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) { 167 if (errno) 168 result.AppendErrorWithFormatv("register read failed: {0}\n", 169 llvm::sys::StrError()); 170 else 171 result.AppendError("unknown error while reading registers.\n"); 172 result.SetStatus(eReturnStatusFailed); 173 break; 174 } 175 } else { 176 result.AppendErrorWithFormat( 177 "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx); 178 result.SetStatus(eReturnStatusFailed); 179 break; 180 } 181 } 182 } else { 183 if (m_command_options.dump_all_sets) 184 num_register_sets = reg_ctx->GetRegisterSetCount(); 185 186 for (set_idx = 0; set_idx < num_register_sets; ++set_idx) { 187 // When dump_all_sets option is set, dump primitive as well as 188 // derived registers. 189 DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx, 190 !m_command_options.dump_all_sets.GetCurrentValue()); 191 } 192 } 193 } else { 194 if (m_command_options.dump_all_sets) { 195 result.AppendError("the --all option can't be used when registers " 196 "names are supplied as arguments\n"); 197 result.SetStatus(eReturnStatusFailed); 198 } else if (m_command_options.set_indexes.GetSize() > 0) { 199 result.AppendError("the --set <set> option can't be used when " 200 "registers names are supplied as arguments\n"); 201 result.SetStatus(eReturnStatusFailed); 202 } else { 203 for (auto &entry : command) { 204 // in most LLDB commands we accept $rbx as the name for register RBX 205 // - and here we would reject it and non-existant. we should be more 206 // consistent towards the user and allow them to say reg read $rbx - 207 // internally, however, we should be strict and not allow ourselves 208 // to call our registers $rbx in our own API 209 auto arg_str = entry.ref(); 210 arg_str.consume_front("$"); 211 212 reg_info = reg_ctx->GetRegisterInfoByName(arg_str); 213 214 if (reg_info) { 215 if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info)) 216 strm.Printf("%-12s = error: unavailable\n", reg_info->name); 217 } else { 218 result.AppendErrorWithFormat("Invalid register name '%s'.\n", 219 arg_str.str().c_str()); 220 } 221 } 222 } 223 } 224 return result.Succeeded(); 225 } 226 227 class CommandOptions : public OptionGroup { 228 public: 229 CommandOptions() 230 : OptionGroup(), 231 set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)), 232 dump_all_sets(false, false), // Initial and default values are false 233 alternate_name(false, false) {} 234 235 ~CommandOptions() override = default; 236 237 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 238 return llvm::makeArrayRef(g_register_read_options); 239 } 240 241 void OptionParsingStarting(ExecutionContext *execution_context) override { 242 set_indexes.Clear(); 243 dump_all_sets.Clear(); 244 alternate_name.Clear(); 245 } 246 247 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 248 ExecutionContext *execution_context) override { 249 Status error; 250 const int short_option = GetDefinitions()[option_idx].short_option; 251 switch (short_option) { 252 case 's': { 253 OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error)); 254 if (value_sp) 255 set_indexes.AppendValue(value_sp); 256 } break; 257 258 case 'a': 259 // When we don't use OptionValue::SetValueFromCString(const char *) to 260 // set an option value, it won't be marked as being set in the options 261 // so we make a call to let users know the value was set via option 262 dump_all_sets.SetCurrentValue(true); 263 dump_all_sets.SetOptionWasSet(); 264 break; 265 266 case 'A': 267 // When we don't use OptionValue::SetValueFromCString(const char *) to 268 // set an option value, it won't be marked as being set in the options 269 // so we make a call to let users know the value was set via option 270 alternate_name.SetCurrentValue(true); 271 dump_all_sets.SetOptionWasSet(); 272 break; 273 274 default: 275 llvm_unreachable("Unimplemented option"); 276 } 277 return error; 278 } 279 280 // Instance variables to hold the values for command options. 281 OptionValueArray set_indexes; 282 OptionValueBoolean dump_all_sets; 283 OptionValueBoolean alternate_name; 284 }; 285 286 OptionGroupOptions m_option_group; 287 OptionGroupFormat m_format_options; 288 CommandOptions m_command_options; 289 }; 290 291 // "register write" 292 class CommandObjectRegisterWrite : public CommandObjectParsed { 293 public: 294 CommandObjectRegisterWrite(CommandInterpreter &interpreter) 295 : CommandObjectParsed(interpreter, "register write", 296 "Modify a single register value.", nullptr, 297 eCommandRequiresFrame | eCommandRequiresRegContext | 298 eCommandProcessMustBeLaunched | 299 eCommandProcessMustBePaused) { 300 CommandArgumentEntry arg1; 301 CommandArgumentEntry arg2; 302 CommandArgumentData register_arg; 303 CommandArgumentData value_arg; 304 305 // Define the first (and only) variant of this arg. 306 register_arg.arg_type = eArgTypeRegisterName; 307 register_arg.arg_repetition = eArgRepeatPlain; 308 309 // There is only one variant this argument could be; put it into the 310 // argument entry. 311 arg1.push_back(register_arg); 312 313 // Define the first (and only) variant of this arg. 314 value_arg.arg_type = eArgTypeValue; 315 value_arg.arg_repetition = eArgRepeatPlain; 316 317 // There is only one variant this argument could be; put it into the 318 // argument entry. 319 arg2.push_back(value_arg); 320 321 // Push the data for the first argument into the m_arguments vector. 322 m_arguments.push_back(arg1); 323 m_arguments.push_back(arg2); 324 } 325 326 ~CommandObjectRegisterWrite() override = default; 327 328 protected: 329 bool DoExecute(Args &command, CommandReturnObject &result) override { 330 DataExtractor reg_data; 331 RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 332 333 if (command.GetArgumentCount() != 2) { 334 result.AppendError( 335 "register write takes exactly 2 arguments: <reg-name> <value>"); 336 result.SetStatus(eReturnStatusFailed); 337 } else { 338 auto reg_name = command[0].ref(); 339 auto value_str = command[1].ref(); 340 341 // in most LLDB commands we accept $rbx as the name for register RBX - 342 // and here we would reject it and non-existant. we should be more 343 // consistent towards the user and allow them to say reg write $rbx - 344 // internally, however, we should be strict and not allow ourselves to 345 // call our registers $rbx in our own API 346 reg_name.consume_front("$"); 347 348 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 349 350 if (reg_info) { 351 RegisterValue reg_value; 352 353 Status error(reg_value.SetValueFromString(reg_info, value_str)); 354 if (error.Success()) { 355 if (reg_ctx->WriteRegister(reg_info, reg_value)) { 356 // Toss all frames and anything else in the thread after a register 357 // has been written. 358 m_exe_ctx.GetThreadRef().Flush(); 359 result.SetStatus(eReturnStatusSuccessFinishNoResult); 360 return true; 361 } 362 } 363 if (error.AsCString()) { 364 result.AppendErrorWithFormat( 365 "Failed to write register '%s' with value '%s': %s\n", 366 reg_name.str().c_str(), value_str.str().c_str(), 367 error.AsCString()); 368 } else { 369 result.AppendErrorWithFormat( 370 "Failed to write register '%s' with value '%s'", 371 reg_name.str().c_str(), value_str.str().c_str()); 372 } 373 result.SetStatus(eReturnStatusFailed); 374 } else { 375 result.AppendErrorWithFormat("Register not found for '%s'.\n", 376 reg_name.str().c_str()); 377 result.SetStatus(eReturnStatusFailed); 378 } 379 } 380 return result.Succeeded(); 381 } 382 }; 383 384 // CommandObjectRegister constructor 385 CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) 386 : CommandObjectMultiword(interpreter, "register", 387 "Commands to access registers for the current " 388 "thread and stack frame.", 389 "register [read|write] ...") { 390 LoadSubCommand("read", 391 CommandObjectSP(new CommandObjectRegisterRead(interpreter))); 392 LoadSubCommand("write", 393 CommandObjectSP(new CommandObjectRegisterWrite(interpreter))); 394 } 395 396 CommandObjectRegister::~CommandObjectRegister() = default; 397