1*80814287SRaphael Isemann //===-- CommandObjectRegister.cpp -----------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 949bcfd80SEugene Zelenko #include "CommandObjectRegister.h" 10b9c1b51eSKate Stone #include "lldb/Core/Debugger.h" 11e03334cfSPavel Labath #include "lldb/Core/DumpRegisterValue.h" 123eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 1330fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 141deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h" 1567cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueArray.h" 1632abc6edSZachary Turner #include "lldb/Interpreter/OptionValueBoolean.h" 1767cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueUInt64.h" 18b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 1930fdc8d8SChris Lattner #include "lldb/Target/ExecutionContext.h" 208f7770f8SGreg Clayton #include "lldb/Target/Process.h" 2130fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h" 22d5944cd1SGreg Clayton #include "lldb/Target/SectionLoadList.h" 238f7770f8SGreg Clayton #include "lldb/Target/Thread.h" 24145d95c9SPavel Labath #include "lldb/Utility/Args.h" 25666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h" 26d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h" 2710c41f37SPavel Labath #include "llvm/Support/Errno.h" 2830fdc8d8SChris Lattner 2930fdc8d8SChris Lattner using namespace lldb; 3030fdc8d8SChris Lattner using namespace lldb_private; 3130fdc8d8SChris Lattner 3230fdc8d8SChris Lattner // "register read" 33ec67e734SRaphael Isemann #define LLDB_OPTIONS_register_read 34ec67e734SRaphael Isemann #include "CommandOptions.inc" 351f0f5b5bSZachary Turner 36b9c1b51eSKate Stone class CommandObjectRegisterRead : public CommandObjectParsed { 3730fdc8d8SChris Lattner public: 38b9c1b51eSKate Stone CommandObjectRegisterRead(CommandInterpreter &interpreter) 39b9c1b51eSKate Stone : CommandObjectParsed( 40b9c1b51eSKate Stone interpreter, "register read", 41b9c1b51eSKate Stone "Dump the contents of one or more register values from the current " 42b9c1b51eSKate Stone "frame. If no register is specified, dumps them all.", 4349bcfd80SEugene Zelenko nullptr, 44b9c1b51eSKate Stone eCommandRequiresFrame | eCommandRequiresRegContext | 45b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 46b9c1b51eSKate Stone m_option_group(), m_format_options(eFormatDefault), 47b9c1b51eSKate Stone m_command_options() { 48405fe67fSCaroline Tice CommandArgumentEntry arg; 49405fe67fSCaroline Tice CommandArgumentData register_arg; 50405fe67fSCaroline Tice 51405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 52405fe67fSCaroline Tice register_arg.arg_type = eArgTypeRegisterName; 53405fe67fSCaroline Tice register_arg.arg_repetition = eArgRepeatStar; 54405fe67fSCaroline Tice 55b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 56b9c1b51eSKate Stone // argument entry. 57405fe67fSCaroline Tice arg.push_back(register_arg); 58405fe67fSCaroline Tice 59405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 60405fe67fSCaroline Tice m_arguments.push_back(arg); 611deb7962SGreg Clayton 621deb7962SGreg Clayton // Add the "--format" 63b9c1b51eSKate Stone m_option_group.Append(&m_format_options, 64b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 65b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 66b9c1b51eSKate Stone LLDB_OPT_SET_ALL); 671deb7962SGreg Clayton m_option_group.Append(&m_command_options); 681deb7962SGreg Clayton m_option_group.Finalize(); 6930fdc8d8SChris Lattner } 7030fdc8d8SChris Lattner 7149bcfd80SEugene Zelenko ~CommandObjectRegisterRead() override = default; 7230fdc8d8SChris Lattner 73b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 7432e0a750SGreg Clayton 75b9c1b51eSKate Stone bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, 76b9c1b51eSKate Stone RegisterContext *reg_ctx, const RegisterInfo *reg_info) { 77b9c1b51eSKate Stone if (reg_info) { 787349bd90SGreg Clayton RegisterValue reg_value; 79385aa28cSGreg Clayton 80b9c1b51eSKate Stone if (reg_ctx->ReadRegister(reg_info, reg_value)) { 81385aa28cSGreg Clayton strm.Indent(); 82385aa28cSGreg Clayton 839076c0ffSSean Callanan bool prefix_with_altname = (bool)m_command_options.alternate_name; 849a8fa916SGreg Clayton bool prefix_with_name = !prefix_with_altname; 85e03334cfSPavel Labath DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name, 86e03334cfSPavel Labath prefix_with_altname, m_format_options.GetFormat(), 8); 87b9c1b51eSKate Stone if ((reg_info->encoding == eEncodingUint) || 88b9c1b51eSKate Stone (reg_info->encoding == eEncodingSint)) { 891ac04c30SGreg Clayton Process *process = exe_ctx.GetProcessPtr(); 90b9c1b51eSKate Stone if (process && reg_info->byte_size == process->GetAddressByteSize()) { 917349bd90SGreg Clayton addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS); 92b9c1b51eSKate Stone if (reg_addr != LLDB_INVALID_ADDRESS) { 93385aa28cSGreg Clayton Address so_reg_addr; 94b9c1b51eSKate Stone if (exe_ctx.GetTargetRef() 95b9c1b51eSKate Stone .GetSectionLoadList() 96b9c1b51eSKate Stone .ResolveLoadAddress(reg_addr, so_reg_addr)) { 97385aa28cSGreg Clayton strm.PutCString(" "); 98b9c1b51eSKate Stone so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), 99b9c1b51eSKate Stone Address::DumpStyleResolvedDescription); 100385aa28cSGreg Clayton } 101385aa28cSGreg Clayton } 102385aa28cSGreg Clayton } 1031ac04c30SGreg Clayton } 104385aa28cSGreg Clayton strm.EOL(); 105385aa28cSGreg Clayton return true; 106385aa28cSGreg Clayton } 107385aa28cSGreg Clayton } 108385aa28cSGreg Clayton return false; 109385aa28cSGreg Clayton } 110385aa28cSGreg Clayton 111b9c1b51eSKate Stone bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm, 112b9c1b51eSKate Stone RegisterContext *reg_ctx, size_t set_idx, 113b9c1b51eSKate Stone bool primitive_only = false) { 114385aa28cSGreg Clayton uint32_t unavailable_count = 0; 115385aa28cSGreg Clayton uint32_t available_count = 0; 1164f5f39acSAshok Thirumurthi 1174f5f39acSAshok Thirumurthi if (!reg_ctx) 118b9c1b51eSKate Stone return false; // thread has no registers (i.e. core files are corrupt, 119b9c1b51eSKate Stone // incomplete crash logs...) 1204f5f39acSAshok Thirumurthi 121385aa28cSGreg Clayton const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx); 122b9c1b51eSKate Stone if (reg_set) { 123c3c95b22SColin Riley strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown")); 124385aa28cSGreg Clayton strm.IndentMore(); 125c7bece56SGreg Clayton const size_t num_registers = reg_set->num_registers; 126b9c1b51eSKate Stone for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { 127385aa28cSGreg Clayton const uint32_t reg = reg_set->registers[reg_idx]; 1286d4d4f7dSJohnny Chen const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg); 1296d4d4f7dSJohnny Chen // Skip the dumping of derived register if primitive_only is true. 1306d4d4f7dSJohnny Chen if (primitive_only && reg_info && reg_info->value_regs) 1316d4d4f7dSJohnny Chen continue; 1324f5f39acSAshok Thirumurthi 1336d4d4f7dSJohnny Chen if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info)) 134385aa28cSGreg Clayton ++available_count; 135385aa28cSGreg Clayton else 136385aa28cSGreg Clayton ++unavailable_count; 137385aa28cSGreg Clayton } 138385aa28cSGreg Clayton strm.IndentLess(); 139b9c1b51eSKate Stone if (unavailable_count) { 140385aa28cSGreg Clayton strm.Indent(); 141385aa28cSGreg Clayton strm.Printf("%u registers were unavailable.\n", unavailable_count); 142385aa28cSGreg Clayton } 143385aa28cSGreg Clayton strm.EOL(); 144385aa28cSGreg Clayton } 145385aa28cSGreg Clayton return available_count > 0; 146385aa28cSGreg Clayton } 147385aa28cSGreg Clayton 1485a988416SJim Ingham protected: 149b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 150385aa28cSGreg Clayton Stream &strm = result.GetOutputStream(); 151f9fc609fSGreg Clayton RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 15230fdc8d8SChris Lattner 15349bcfd80SEugene Zelenko const RegisterInfo *reg_info = nullptr; 154b9c1b51eSKate Stone if (command.GetArgumentCount() == 0) { 155c7bece56SGreg Clayton size_t set_idx; 156385aa28cSGreg Clayton 157c7bece56SGreg Clayton size_t num_register_sets = 1; 158c7bece56SGreg Clayton const size_t set_array_size = m_command_options.set_indexes.GetSize(); 159b9c1b51eSKate Stone if (set_array_size > 0) { 160b9c1b51eSKate Stone for (size_t i = 0; i < set_array_size; ++i) { 161b9c1b51eSKate Stone set_idx = m_command_options.set_indexes[i]->GetUInt64Value(UINT32_MAX, 162b9c1b51eSKate Stone nullptr); 163b9c1b51eSKate Stone if (set_idx < reg_ctx->GetRegisterSetCount()) { 164b9c1b51eSKate Stone if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) { 1654f5f39acSAshok Thirumurthi if (errno) 16610c41f37SPavel Labath result.AppendErrorWithFormatv("register read failed: {0}\n", 16710c41f37SPavel Labath llvm::sys::StrError()); 1684f5f39acSAshok Thirumurthi else 1694f5f39acSAshok Thirumurthi result.AppendError("unknown error while reading registers.\n"); 170385aa28cSGreg Clayton result.SetStatus(eReturnStatusFailed); 171385aa28cSGreg Clayton break; 172385aa28cSGreg Clayton } 173b9c1b51eSKate Stone } else { 174b9c1b51eSKate Stone result.AppendErrorWithFormat( 175b9c1b51eSKate Stone "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx); 176385aa28cSGreg Clayton result.SetStatus(eReturnStatusFailed); 177385aa28cSGreg Clayton break; 17830fdc8d8SChris Lattner } 17930fdc8d8SChris Lattner } 180b9c1b51eSKate Stone } else { 1811deb7962SGreg Clayton if (m_command_options.dump_all_sets) 182385aa28cSGreg Clayton num_register_sets = reg_ctx->GetRegisterSetCount(); 183385aa28cSGreg Clayton 184b9c1b51eSKate Stone for (set_idx = 0; set_idx < num_register_sets; ++set_idx) { 18505097246SAdrian Prantl // When dump_all_sets option is set, dump primitive as well as 18605097246SAdrian Prantl // derived registers. 187b9c1b51eSKate Stone DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx, 188b9c1b51eSKate Stone !m_command_options.dump_all_sets.GetCurrentValue()); 18930fdc8d8SChris Lattner } 19030fdc8d8SChris Lattner } 191b9c1b51eSKate Stone } else { 192b9c1b51eSKate Stone if (m_command_options.dump_all_sets) { 193b9c1b51eSKate Stone result.AppendError("the --all option can't be used when registers " 194b9c1b51eSKate Stone "names are supplied as arguments\n"); 195385aa28cSGreg Clayton result.SetStatus(eReturnStatusFailed); 196b9c1b51eSKate Stone } else if (m_command_options.set_indexes.GetSize() > 0) { 197b9c1b51eSKate Stone result.AppendError("the --set <set> option can't be used when " 198b9c1b51eSKate Stone "registers names are supplied as arguments\n"); 199385aa28cSGreg Clayton result.SetStatus(eReturnStatusFailed); 200b9c1b51eSKate Stone } else { 2012c84f908SZachary Turner for (auto &entry : command) { 20205097246SAdrian Prantl // in most LLDB commands we accept $rbx as the name for register RBX 20305097246SAdrian Prantl // - and here we would reject it and non-existant. we should be more 2042c84f908SZachary Turner // consistent towards the user and allow them to say reg read $rbx - 2052c84f908SZachary Turner // internally, however, we should be strict and not allow ourselves 2062f59302cSEnrico Granata // to call our registers $rbx in our own API 2070d9a201eSRaphael Isemann auto arg_str = entry.ref(); 2082c84f908SZachary Turner arg_str.consume_front("$"); 2092c84f908SZachary Turner 2102c84f908SZachary Turner reg_info = reg_ctx->GetRegisterInfoByName(arg_str); 21130fdc8d8SChris Lattner 212b9c1b51eSKate Stone if (reg_info) { 213f9fc609fSGreg Clayton if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info)) 214385aa28cSGreg Clayton strm.Printf("%-12s = error: unavailable\n", reg_info->name); 215b9c1b51eSKate Stone } else { 216b9c1b51eSKate Stone result.AppendErrorWithFormat("Invalid register name '%s'.\n", 2172c84f908SZachary Turner arg_str.str().c_str()); 21830fdc8d8SChris Lattner } 21930fdc8d8SChris Lattner } 22030fdc8d8SChris Lattner } 22130fdc8d8SChris Lattner } 22230fdc8d8SChris Lattner return result.Succeeded(); 22330fdc8d8SChris Lattner } 22432e0a750SGreg Clayton 225b9c1b51eSKate Stone class CommandOptions : public OptionGroup { 22632e0a750SGreg Clayton public: 227b9c1b51eSKate Stone CommandOptions() 228b9c1b51eSKate Stone : OptionGroup(), 229385aa28cSGreg Clayton set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)), 2309a8fa916SGreg Clayton dump_all_sets(false, false), // Initial and default values are false 231b9c1b51eSKate Stone alternate_name(false, false) {} 23232e0a750SGreg Clayton 23349bcfd80SEugene Zelenko ~CommandOptions() override = default; 2341deb7962SGreg Clayton 2351f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 23670602439SZachary Turner return llvm::makeArrayRef(g_register_read_options); 2371f0f5b5bSZachary Turner } 2381deb7962SGreg Clayton 239b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 2401deb7962SGreg Clayton set_indexes.Clear(); 2411deb7962SGreg Clayton dump_all_sets.Clear(); 2421deb7962SGreg Clayton alternate_name.Clear(); 2431deb7962SGreg Clayton } 2441deb7962SGreg Clayton 24597206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 246b9c1b51eSKate Stone ExecutionContext *execution_context) override { 24797206d57SZachary Turner Status error; 2481f0f5b5bSZachary Turner const int short_option = GetDefinitions()[option_idx].short_option; 249b9c1b51eSKate Stone switch (short_option) { 250b9c1b51eSKate Stone case 's': { 2511deb7962SGreg Clayton OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error)); 252385aa28cSGreg Clayton if (value_sp) 253385aa28cSGreg Clayton set_indexes.AppendValue(value_sp); 254b9c1b51eSKate Stone } break; 255385aa28cSGreg Clayton 256385aa28cSGreg Clayton case 'a': 2579a8fa916SGreg Clayton // When we don't use OptionValue::SetValueFromCString(const char *) to 2589a8fa916SGreg Clayton // set an option value, it won't be marked as being set in the options 2599a8fa916SGreg Clayton // so we make a call to let users know the value was set via option 260385aa28cSGreg Clayton dump_all_sets.SetCurrentValue(true); 2619a8fa916SGreg Clayton dump_all_sets.SetOptionWasSet(); 2629a8fa916SGreg Clayton break; 2639a8fa916SGreg Clayton 2649a8fa916SGreg Clayton case 'A': 2659a8fa916SGreg Clayton // When we don't use OptionValue::SetValueFromCString(const char *) to 2669a8fa916SGreg Clayton // set an option value, it won't be marked as being set in the options 2679a8fa916SGreg Clayton // so we make a call to let users know the value was set via option 2689a8fa916SGreg Clayton alternate_name.SetCurrentValue(true); 2699a8fa916SGreg Clayton dump_all_sets.SetOptionWasSet(); 270385aa28cSGreg Clayton break; 271385aa28cSGreg Clayton 27232e0a750SGreg Clayton default: 27336162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 27432e0a750SGreg Clayton } 27532e0a750SGreg Clayton return error; 27632e0a750SGreg Clayton } 27732e0a750SGreg Clayton 27832e0a750SGreg Clayton // Instance variables to hold the values for command options. 279385aa28cSGreg Clayton OptionValueArray set_indexes; 280385aa28cSGreg Clayton OptionValueBoolean dump_all_sets; 2819a8fa916SGreg Clayton OptionValueBoolean alternate_name; 28230fdc8d8SChris Lattner }; 28330fdc8d8SChris Lattner 2841deb7962SGreg Clayton OptionGroupOptions m_option_group; 2851deb7962SGreg Clayton OptionGroupFormat m_format_options; 2861deb7962SGreg Clayton CommandOptions m_command_options; 28732e0a750SGreg Clayton }; 28832e0a750SGreg Clayton 28930fdc8d8SChris Lattner // "register write" 290b9c1b51eSKate Stone class CommandObjectRegisterWrite : public CommandObjectParsed { 29130fdc8d8SChris Lattner public: 292b9c1b51eSKate Stone CommandObjectRegisterWrite(CommandInterpreter &interpreter) 293b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "register write", 294b9c1b51eSKate Stone "Modify a single register value.", nullptr, 295b9c1b51eSKate Stone eCommandRequiresFrame | eCommandRequiresRegContext | 296e87764f2SEnrico Granata eCommandProcessMustBeLaunched | 297b9c1b51eSKate Stone eCommandProcessMustBePaused) { 298405fe67fSCaroline Tice CommandArgumentEntry arg1; 299405fe67fSCaroline Tice CommandArgumentEntry arg2; 300405fe67fSCaroline Tice CommandArgumentData register_arg; 301405fe67fSCaroline Tice CommandArgumentData value_arg; 302405fe67fSCaroline Tice 303405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 304405fe67fSCaroline Tice register_arg.arg_type = eArgTypeRegisterName; 305405fe67fSCaroline Tice register_arg.arg_repetition = eArgRepeatPlain; 306405fe67fSCaroline Tice 307b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 308b9c1b51eSKate Stone // argument entry. 309405fe67fSCaroline Tice arg1.push_back(register_arg); 310405fe67fSCaroline Tice 311405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 312405fe67fSCaroline Tice value_arg.arg_type = eArgTypeValue; 313405fe67fSCaroline Tice value_arg.arg_repetition = eArgRepeatPlain; 314405fe67fSCaroline Tice 315b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 316b9c1b51eSKate Stone // argument entry. 317405fe67fSCaroline Tice arg2.push_back(value_arg); 318405fe67fSCaroline Tice 319405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 320405fe67fSCaroline Tice m_arguments.push_back(arg1); 321405fe67fSCaroline Tice m_arguments.push_back(arg2); 32230fdc8d8SChris Lattner } 32330fdc8d8SChris Lattner 32449bcfd80SEugene Zelenko ~CommandObjectRegisterWrite() override = default; 32530fdc8d8SChris Lattner 3265a988416SJim Ingham protected: 327b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 32830fdc8d8SChris Lattner DataExtractor reg_data; 329f9fc609fSGreg Clayton RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 33030fdc8d8SChris Lattner 331b9c1b51eSKate Stone if (command.GetArgumentCount() != 2) { 332b9c1b51eSKate Stone result.AppendError( 333b9c1b51eSKate Stone "register write takes exactly 2 arguments: <reg-name> <value>"); 33430fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 335b9c1b51eSKate Stone } else { 3360d9a201eSRaphael Isemann auto reg_name = command[0].ref(); 3370d9a201eSRaphael Isemann auto value_str = command[1].ref(); 3382f59302cSEnrico Granata 33905097246SAdrian Prantl // in most LLDB commands we accept $rbx as the name for register RBX - 34005097246SAdrian Prantl // and here we would reject it and non-existant. we should be more 34105097246SAdrian Prantl // consistent towards the user and allow them to say reg write $rbx - 34205097246SAdrian Prantl // internally, however, we should be strict and not allow ourselves to 34305097246SAdrian Prantl // call our registers $rbx in our own API 3442c84f908SZachary Turner reg_name.consume_front("$"); 3452f59302cSEnrico Granata 346385aa28cSGreg Clayton const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 34730fdc8d8SChris Lattner 348b9c1b51eSKate Stone if (reg_info) { 3497349bd90SGreg Clayton RegisterValue reg_value; 3507349bd90SGreg Clayton 35197206d57SZachary Turner Status error(reg_value.SetValueFromString(reg_info, value_str)); 352b9c1b51eSKate Stone if (error.Success()) { 353b9c1b51eSKate Stone if (reg_ctx->WriteRegister(reg_info, reg_value)) { 35405097246SAdrian Prantl // Toss all frames and anything else in the thread after a register 35505097246SAdrian Prantl // has been written. 356f9fc609fSGreg Clayton m_exe_ctx.GetThreadRef().Flush(); 35730fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishNoResult); 35830fdc8d8SChris Lattner return true; 35930fdc8d8SChris Lattner } 36030fdc8d8SChris Lattner } 361b9c1b51eSKate Stone if (error.AsCString()) { 362b9c1b51eSKate Stone result.AppendErrorWithFormat( 3632c84f908SZachary Turner "Failed to write register '%s' with value '%s': %s\n", 3642c84f908SZachary Turner reg_name.str().c_str(), value_str.str().c_str(), 3652c84f908SZachary Turner error.AsCString()); 366b9c1b51eSKate Stone } else { 367b9c1b51eSKate Stone result.AppendErrorWithFormat( 3682c84f908SZachary Turner "Failed to write register '%s' with value '%s'", 3692c84f908SZachary Turner reg_name.str().c_str(), value_str.str().c_str()); 370b1ad65c5SJason Molenda } 371b1ad65c5SJason Molenda result.SetStatus(eReturnStatusFailed); 372b9c1b51eSKate Stone } else { 373b9c1b51eSKate Stone result.AppendErrorWithFormat("Register not found for '%s'.\n", 3742c84f908SZachary Turner reg_name.str().c_str()); 37530fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 37630fdc8d8SChris Lattner } 37730fdc8d8SChris Lattner } 37830fdc8d8SChris Lattner return result.Succeeded(); 37930fdc8d8SChris Lattner } 38030fdc8d8SChris Lattner }; 38130fdc8d8SChris Lattner 38230fdc8d8SChris Lattner // CommandObjectRegister constructor 3837428a18cSKate Stone CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) 3847428a18cSKate Stone : CommandObjectMultiword(interpreter, "register", 385b9c1b51eSKate Stone "Commands to access registers for the current " 386b9c1b51eSKate Stone "thread and stack frame.", 387b9c1b51eSKate Stone "register [read|write] ...") { 388b9c1b51eSKate Stone LoadSubCommand("read", 389b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRegisterRead(interpreter))); 390b9c1b51eSKate Stone LoadSubCommand("write", 391b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRegisterWrite(interpreter))); 39230fdc8d8SChris Lattner } 39330fdc8d8SChris Lattner 39449bcfd80SEugene Zelenko CommandObjectRegister::~CommandObjectRegister() = default; 395