15ffd83dbSDimitry Andric //===-- CommandObjectRegister.cpp -----------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "CommandObjectRegister.h" 100b57cec5SDimitry Andric #include "lldb/Core/Debugger.h" 1106c3fb27SDimitry Andric #include "lldb/Core/DumpRegisterInfo.h" 120b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h" 130b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 1406c3fb27SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 15fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 160b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 170b57cec5SDimitry Andric #include "lldb/Interpreter/OptionGroupFormat.h" 180b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueArray.h" 190b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueBoolean.h" 200b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueUInt64.h" 210b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 220b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 230b57cec5SDimitry Andric #include "lldb/Target/Process.h" 240b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h" 250b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h" 260b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 270b57cec5SDimitry Andric #include "lldb/Utility/Args.h" 280b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h" 290b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h" 300b57cec5SDimitry Andric #include "llvm/Support/Errno.h" 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric using namespace lldb; 330b57cec5SDimitry Andric using namespace lldb_private; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric // "register read" 369dba64beSDimitry Andric #define LLDB_OPTIONS_register_read 379dba64beSDimitry Andric #include "CommandOptions.inc" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric class CommandObjectRegisterRead : public CommandObjectParsed { 400b57cec5SDimitry Andric public: 410b57cec5SDimitry Andric CommandObjectRegisterRead(CommandInterpreter &interpreter) 420b57cec5SDimitry Andric : CommandObjectParsed( 430b57cec5SDimitry Andric interpreter, "register read", 440b57cec5SDimitry Andric "Dump the contents of one or more register values from the current " 450b57cec5SDimitry Andric "frame. If no register is specified, dumps them all.", 460b57cec5SDimitry Andric nullptr, 470b57cec5SDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext | 480b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 4906c3fb27SDimitry Andric m_format_options(eFormatDefault, UINT64_MAX, UINT64_MAX, 5006c3fb27SDimitry Andric {{CommandArgumentType::eArgTypeFormat, 5106c3fb27SDimitry Andric "Specify a format to be used for display. If this " 5206c3fb27SDimitry Andric "is set, register fields will not be displayed."}}) { 53*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeRegisterName, eArgRepeatStar); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Add the "--format" 560b57cec5SDimitry Andric m_option_group.Append(&m_format_options, 570b57cec5SDimitry Andric OptionGroupFormat::OPTION_GROUP_FORMAT | 580b57cec5SDimitry Andric OptionGroupFormat::OPTION_GROUP_GDB_FMT, 590b57cec5SDimitry Andric LLDB_OPT_SET_ALL); 600b57cec5SDimitry Andric m_option_group.Append(&m_command_options); 610b57cec5SDimitry Andric m_option_group.Finalize(); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric ~CommandObjectRegisterRead() override = default; 650b57cec5SDimitry Andric 665ffd83dbSDimitry Andric void 675ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 685ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override { 695ffd83dbSDimitry Andric if (!m_exe_ctx.HasProcessScope()) 705ffd83dbSDimitry Andric return; 71*0fca6ea1SDimitry Andric CommandObject::HandleArgumentCompletion(request, opt_element_vector); 725ffd83dbSDimitry Andric } 735ffd83dbSDimitry Andric 740b57cec5SDimitry Andric Options *GetOptions() override { return &m_option_group; } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm, 7706c3fb27SDimitry Andric RegisterContext ®_ctx, const RegisterInfo ®_info, 7806c3fb27SDimitry Andric bool print_flags) { 790b57cec5SDimitry Andric RegisterValue reg_value; 8006c3fb27SDimitry Andric if (!reg_ctx.ReadRegister(®_info, reg_value)) 8106c3fb27SDimitry Andric return false; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric strm.Indent(); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric bool prefix_with_altname = (bool)m_command_options.alternate_name; 860b57cec5SDimitry Andric bool prefix_with_name = !prefix_with_altname; 8706c3fb27SDimitry Andric DumpRegisterValue(reg_value, strm, reg_info, prefix_with_name, 88bdd1243dSDimitry Andric prefix_with_altname, m_format_options.GetFormat(), 8, 8906c3fb27SDimitry Andric exe_ctx.GetBestExecutionContextScope(), print_flags, 9006c3fb27SDimitry Andric exe_ctx.GetTargetSP()); 9106c3fb27SDimitry Andric if ((reg_info.encoding == eEncodingUint) || 9206c3fb27SDimitry Andric (reg_info.encoding == eEncodingSint)) { 930b57cec5SDimitry Andric Process *process = exe_ctx.GetProcessPtr(); 9406c3fb27SDimitry Andric if (process && reg_info.byte_size == process->GetAddressByteSize()) { 950b57cec5SDimitry Andric addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS); 960b57cec5SDimitry Andric if (reg_addr != LLDB_INVALID_ADDRESS) { 970b57cec5SDimitry Andric Address so_reg_addr; 9806c3fb27SDimitry Andric if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress( 9906c3fb27SDimitry Andric reg_addr, so_reg_addr)) { 1000b57cec5SDimitry Andric strm.PutCString(" "); 1010b57cec5SDimitry Andric so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), 1020b57cec5SDimitry Andric Address::DumpStyleResolvedDescription); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric strm.EOL(); 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric bool DumpRegisterSet(const ExecutionContext &exe_ctx, Stream &strm, 1120b57cec5SDimitry Andric RegisterContext *reg_ctx, size_t set_idx, 1130b57cec5SDimitry Andric bool primitive_only = false) { 1140b57cec5SDimitry Andric uint32_t unavailable_count = 0; 1150b57cec5SDimitry Andric uint32_t available_count = 0; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric if (!reg_ctx) 1180b57cec5SDimitry Andric return false; // thread has no registers (i.e. core files are corrupt, 1190b57cec5SDimitry Andric // incomplete crash logs...) 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric const RegisterSet *const reg_set = reg_ctx->GetRegisterSet(set_idx); 1220b57cec5SDimitry Andric if (reg_set) { 1230b57cec5SDimitry Andric strm.Printf("%s:\n", (reg_set->name ? reg_set->name : "unknown")); 1240b57cec5SDimitry Andric strm.IndentMore(); 1250b57cec5SDimitry Andric const size_t num_registers = reg_set->num_registers; 1260b57cec5SDimitry Andric for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { 1270b57cec5SDimitry Andric const uint32_t reg = reg_set->registers[reg_idx]; 1280b57cec5SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg); 1290b57cec5SDimitry Andric // Skip the dumping of derived register if primitive_only is true. 1300b57cec5SDimitry Andric if (primitive_only && reg_info && reg_info->value_regs) 1310b57cec5SDimitry Andric continue; 1320b57cec5SDimitry Andric 13306c3fb27SDimitry Andric if (reg_info && DumpRegister(exe_ctx, strm, *reg_ctx, *reg_info, 13406c3fb27SDimitry Andric /*print_flags=*/false)) 1350b57cec5SDimitry Andric ++available_count; 1360b57cec5SDimitry Andric else 1370b57cec5SDimitry Andric ++unavailable_count; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric strm.IndentLess(); 1400b57cec5SDimitry Andric if (unavailable_count) { 1410b57cec5SDimitry Andric strm.Indent(); 1420b57cec5SDimitry Andric strm.Printf("%u registers were unavailable.\n", unavailable_count); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric strm.EOL(); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric return available_count > 0; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric protected: 1505f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 1510b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 1520b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 1550b57cec5SDimitry Andric size_t set_idx; 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric size_t num_register_sets = 1; 1580b57cec5SDimitry Andric const size_t set_array_size = m_command_options.set_indexes.GetSize(); 1590b57cec5SDimitry Andric if (set_array_size > 0) { 1600b57cec5SDimitry Andric for (size_t i = 0; i < set_array_size; ++i) { 16106c3fb27SDimitry Andric set_idx = 16206c3fb27SDimitry Andric m_command_options.set_indexes[i]->GetValueAs<uint64_t>().value_or( 16306c3fb27SDimitry Andric UINT32_MAX); 1640b57cec5SDimitry Andric if (set_idx < reg_ctx->GetRegisterSetCount()) { 1650b57cec5SDimitry Andric if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) { 1660b57cec5SDimitry Andric if (errno) 1670b57cec5SDimitry Andric result.AppendErrorWithFormatv("register read failed: {0}\n", 1680b57cec5SDimitry Andric llvm::sys::StrError()); 1690b57cec5SDimitry Andric else 1700b57cec5SDimitry Andric result.AppendError("unknown error while reading registers.\n"); 1710b57cec5SDimitry Andric break; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } else { 1740b57cec5SDimitry Andric result.AppendErrorWithFormat( 1750b57cec5SDimitry Andric "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx); 1760b57cec5SDimitry Andric break; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric } else { 1800b57cec5SDimitry Andric if (m_command_options.dump_all_sets) 1810b57cec5SDimitry Andric num_register_sets = reg_ctx->GetRegisterSetCount(); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric for (set_idx = 0; set_idx < num_register_sets; ++set_idx) { 1840b57cec5SDimitry Andric // When dump_all_sets option is set, dump primitive as well as 1850b57cec5SDimitry Andric // derived registers. 1860b57cec5SDimitry Andric DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx, 1870b57cec5SDimitry Andric !m_command_options.dump_all_sets.GetCurrentValue()); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric } else { 1910b57cec5SDimitry Andric if (m_command_options.dump_all_sets) { 1920b57cec5SDimitry Andric result.AppendError("the --all option can't be used when registers " 1930b57cec5SDimitry Andric "names are supplied as arguments\n"); 1940b57cec5SDimitry Andric } else if (m_command_options.set_indexes.GetSize() > 0) { 1950b57cec5SDimitry Andric result.AppendError("the --set <set> option can't be used when " 1960b57cec5SDimitry Andric "registers names are supplied as arguments\n"); 1970b57cec5SDimitry Andric } else { 1980b57cec5SDimitry Andric for (auto &entry : command) { 1990b57cec5SDimitry Andric // in most LLDB commands we accept $rbx as the name for register RBX 2000b57cec5SDimitry Andric // - and here we would reject it and non-existant. we should be more 2010b57cec5SDimitry Andric // consistent towards the user and allow them to say reg read $rbx - 2020b57cec5SDimitry Andric // internally, however, we should be strict and not allow ourselves 2030b57cec5SDimitry Andric // to call our registers $rbx in our own API 2049dba64beSDimitry Andric auto arg_str = entry.ref(); 2050b57cec5SDimitry Andric arg_str.consume_front("$"); 2060b57cec5SDimitry Andric 20706c3fb27SDimitry Andric if (const RegisterInfo *reg_info = 20806c3fb27SDimitry Andric reg_ctx->GetRegisterInfoByName(arg_str)) { 20906c3fb27SDimitry Andric // If they have asked for a specific format don't obscure that by 21006c3fb27SDimitry Andric // printing flags afterwards. 21106c3fb27SDimitry Andric bool print_flags = 21206c3fb27SDimitry Andric !m_format_options.GetFormatValue().OptionWasSet(); 21306c3fb27SDimitry Andric if (!DumpRegister(m_exe_ctx, strm, *reg_ctx, *reg_info, 21406c3fb27SDimitry Andric print_flags)) 2150b57cec5SDimitry Andric strm.Printf("%-12s = error: unavailable\n", reg_info->name); 2160b57cec5SDimitry Andric } else { 2170b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid register name '%s'.\n", 2180b57cec5SDimitry Andric arg_str.str().c_str()); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric class CommandOptions : public OptionGroup { 2260b57cec5SDimitry Andric public: 2270b57cec5SDimitry Andric CommandOptions() 22804eeddc0SDimitry Andric : set_indexes(OptionValue::ConvertTypeToMask(OptionValue::eTypeUInt64)), 2290b57cec5SDimitry Andric dump_all_sets(false, false), // Initial and default values are false 2300b57cec5SDimitry Andric alternate_name(false, false) {} 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric ~CommandOptions() override = default; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 235bdd1243dSDimitry Andric return llvm::ArrayRef(g_register_read_options); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2390b57cec5SDimitry Andric set_indexes.Clear(); 2400b57cec5SDimitry Andric dump_all_sets.Clear(); 2410b57cec5SDimitry Andric alternate_name.Clear(); 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 2450b57cec5SDimitry Andric ExecutionContext *execution_context) override { 2460b57cec5SDimitry Andric Status error; 2470b57cec5SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option; 2480b57cec5SDimitry Andric switch (short_option) { 2490b57cec5SDimitry Andric case 's': { 2500b57cec5SDimitry Andric OptionValueSP value_sp(OptionValueUInt64::Create(option_value, error)); 2510b57cec5SDimitry Andric if (value_sp) 2520b57cec5SDimitry Andric set_indexes.AppendValue(value_sp); 2530b57cec5SDimitry Andric } break; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric case 'a': 2560b57cec5SDimitry Andric // When we don't use OptionValue::SetValueFromCString(const char *) to 2570b57cec5SDimitry Andric // set an option value, it won't be marked as being set in the options 2580b57cec5SDimitry Andric // so we make a call to let users know the value was set via option 2590b57cec5SDimitry Andric dump_all_sets.SetCurrentValue(true); 2600b57cec5SDimitry Andric dump_all_sets.SetOptionWasSet(); 2610b57cec5SDimitry Andric break; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric case 'A': 2640b57cec5SDimitry Andric // When we don't use OptionValue::SetValueFromCString(const char *) to 2650b57cec5SDimitry Andric // set an option value, it won't be marked as being set in the options 2660b57cec5SDimitry Andric // so we make a call to let users know the value was set via option 2670b57cec5SDimitry Andric alternate_name.SetCurrentValue(true); 2680b57cec5SDimitry Andric dump_all_sets.SetOptionWasSet(); 2690b57cec5SDimitry Andric break; 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric default: 2729dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric return error; 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric // Instance variables to hold the values for command options. 2780b57cec5SDimitry Andric OptionValueArray set_indexes; 2790b57cec5SDimitry Andric OptionValueBoolean dump_all_sets; 2800b57cec5SDimitry Andric OptionValueBoolean alternate_name; 2810b57cec5SDimitry Andric }; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric OptionGroupOptions m_option_group; 2840b57cec5SDimitry Andric OptionGroupFormat m_format_options; 2850b57cec5SDimitry Andric CommandOptions m_command_options; 2860b57cec5SDimitry Andric }; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // "register write" 2890b57cec5SDimitry Andric class CommandObjectRegisterWrite : public CommandObjectParsed { 2900b57cec5SDimitry Andric public: 2910b57cec5SDimitry Andric CommandObjectRegisterWrite(CommandInterpreter &interpreter) 2920b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "register write", 2930b57cec5SDimitry Andric "Modify a single register value.", nullptr, 2940b57cec5SDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext | 2950b57cec5SDimitry Andric eCommandProcessMustBeLaunched | 2960b57cec5SDimitry Andric eCommandProcessMustBePaused) { 2970b57cec5SDimitry Andric CommandArgumentEntry arg1; 2980b57cec5SDimitry Andric CommandArgumentEntry arg2; 2990b57cec5SDimitry Andric CommandArgumentData register_arg; 3000b57cec5SDimitry Andric CommandArgumentData value_arg; 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3030b57cec5SDimitry Andric register_arg.arg_type = eArgTypeRegisterName; 3040b57cec5SDimitry Andric register_arg.arg_repetition = eArgRepeatPlain; 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3070b57cec5SDimitry Andric // argument entry. 3080b57cec5SDimitry Andric arg1.push_back(register_arg); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3110b57cec5SDimitry Andric value_arg.arg_type = eArgTypeValue; 3120b57cec5SDimitry Andric value_arg.arg_repetition = eArgRepeatPlain; 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3150b57cec5SDimitry Andric // argument entry. 3160b57cec5SDimitry Andric arg2.push_back(value_arg); 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 3190b57cec5SDimitry Andric m_arguments.push_back(arg1); 3200b57cec5SDimitry Andric m_arguments.push_back(arg2); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric ~CommandObjectRegisterWrite() override = default; 3240b57cec5SDimitry Andric 3255ffd83dbSDimitry Andric void 3265ffd83dbSDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 3275ffd83dbSDimitry Andric OptionElementVector &opt_element_vector) override { 3285ffd83dbSDimitry Andric if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) 3295ffd83dbSDimitry Andric return; 3305ffd83dbSDimitry Andric 33106c3fb27SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 33206c3fb27SDimitry Andric GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr); 3335ffd83dbSDimitry Andric } 3345ffd83dbSDimitry Andric 3350b57cec5SDimitry Andric protected: 3365f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 3370b57cec5SDimitry Andric DataExtractor reg_data; 3380b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric if (command.GetArgumentCount() != 2) { 3410b57cec5SDimitry Andric result.AppendError( 3420b57cec5SDimitry Andric "register write takes exactly 2 arguments: <reg-name> <value>"); 3430b57cec5SDimitry Andric } else { 3449dba64beSDimitry Andric auto reg_name = command[0].ref(); 3459dba64beSDimitry Andric auto value_str = command[1].ref(); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric // in most LLDB commands we accept $rbx as the name for register RBX - 3480b57cec5SDimitry Andric // and here we would reject it and non-existant. we should be more 3490b57cec5SDimitry Andric // consistent towards the user and allow them to say reg write $rbx - 3500b57cec5SDimitry Andric // internally, however, we should be strict and not allow ourselves to 3510b57cec5SDimitry Andric // call our registers $rbx in our own API 3520b57cec5SDimitry Andric reg_name.consume_front("$"); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric if (reg_info) { 3570b57cec5SDimitry Andric RegisterValue reg_value; 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric Status error(reg_value.SetValueFromString(reg_info, value_str)); 3600b57cec5SDimitry Andric if (error.Success()) { 3610b57cec5SDimitry Andric if (reg_ctx->WriteRegister(reg_info, reg_value)) { 3620b57cec5SDimitry Andric // Toss all frames and anything else in the thread after a register 3630b57cec5SDimitry Andric // has been written. 3640b57cec5SDimitry Andric m_exe_ctx.GetThreadRef().Flush(); 3650b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 3665f757f3fSDimitry Andric return; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric if (error.AsCString()) { 3700b57cec5SDimitry Andric result.AppendErrorWithFormat( 3710b57cec5SDimitry Andric "Failed to write register '%s' with value '%s': %s\n", 3720b57cec5SDimitry Andric reg_name.str().c_str(), value_str.str().c_str(), 3730b57cec5SDimitry Andric error.AsCString()); 3740b57cec5SDimitry Andric } else { 3750b57cec5SDimitry Andric result.AppendErrorWithFormat( 3760b57cec5SDimitry Andric "Failed to write register '%s' with value '%s'", 3770b57cec5SDimitry Andric reg_name.str().c_str(), value_str.str().c_str()); 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric } else { 3800b57cec5SDimitry Andric result.AppendErrorWithFormat("Register not found for '%s'.\n", 3810b57cec5SDimitry Andric reg_name.str().c_str()); 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric }; 3860b57cec5SDimitry Andric 38706c3fb27SDimitry Andric // "register info" 38806c3fb27SDimitry Andric class CommandObjectRegisterInfo : public CommandObjectParsed { 38906c3fb27SDimitry Andric public: 39006c3fb27SDimitry Andric CommandObjectRegisterInfo(CommandInterpreter &interpreter) 39106c3fb27SDimitry Andric : CommandObjectParsed(interpreter, "register info", 39206c3fb27SDimitry Andric "View information about a register.", nullptr, 3935f757f3fSDimitry Andric eCommandRequiresFrame | eCommandRequiresRegContext | 3945f757f3fSDimitry Andric eCommandProcessMustBeLaunched | 3955f757f3fSDimitry Andric eCommandProcessMustBePaused) { 39606c3fb27SDimitry Andric SetHelpLong(R"( 39706c3fb27SDimitry Andric Name The name lldb uses for the register, optionally with an alias. 39806c3fb27SDimitry Andric Size The size of the register in bytes and again in bits. 39906c3fb27SDimitry Andric Invalidates (*) The registers that would be changed if you wrote this 40006c3fb27SDimitry Andric register. For example, writing to a narrower alias of a wider 40106c3fb27SDimitry Andric register would change the value of the wider register. 40206c3fb27SDimitry Andric Read from (*) The registers that the value of this register is constructed 40306c3fb27SDimitry Andric from. For example, a narrower alias of a wider register will be 40406c3fb27SDimitry Andric read from the wider register. 40506c3fb27SDimitry Andric In sets (*) The register sets that contain this register. For example the 40606c3fb27SDimitry Andric PC will be in the "General Purpose Register" set. 40706c3fb27SDimitry Andric Fields (*) A table of the names and bit positions of the values contained 40806c3fb27SDimitry Andric in this register. 40906c3fb27SDimitry Andric 41006c3fb27SDimitry Andric Fields marked with (*) may not always be present. Some information may be 41106c3fb27SDimitry Andric different for the same register when connected to different debug servers.)"); 41206c3fb27SDimitry Andric 413*0fca6ea1SDimitry Andric AddSimpleArgumentList(eArgTypeRegisterName); 41406c3fb27SDimitry Andric } 41506c3fb27SDimitry Andric 41606c3fb27SDimitry Andric ~CommandObjectRegisterInfo() override = default; 41706c3fb27SDimitry Andric 41806c3fb27SDimitry Andric void 41906c3fb27SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 42006c3fb27SDimitry Andric OptionElementVector &opt_element_vector) override { 42106c3fb27SDimitry Andric if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) 42206c3fb27SDimitry Andric return; 423*0fca6ea1SDimitry Andric CommandObject::HandleArgumentCompletion(request, opt_element_vector); 42406c3fb27SDimitry Andric } 42506c3fb27SDimitry Andric 42606c3fb27SDimitry Andric protected: 4275f757f3fSDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override { 42806c3fb27SDimitry Andric if (command.GetArgumentCount() != 1) { 42906c3fb27SDimitry Andric result.AppendError("register info takes exactly 1 argument: <reg-name>"); 4305f757f3fSDimitry Andric return; 43106c3fb27SDimitry Andric } 43206c3fb27SDimitry Andric 43306c3fb27SDimitry Andric llvm::StringRef reg_name = command[0].ref(); 43406c3fb27SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 43506c3fb27SDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 43606c3fb27SDimitry Andric if (reg_info) { 43706c3fb27SDimitry Andric DumpRegisterInfo( 43806c3fb27SDimitry Andric result.GetOutputStream(), *reg_ctx, *reg_info, 43906c3fb27SDimitry Andric GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 44006c3fb27SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 44106c3fb27SDimitry Andric } else 44206c3fb27SDimitry Andric result.AppendErrorWithFormat("No register found with name '%s'.\n", 44306c3fb27SDimitry Andric reg_name.str().c_str()); 44406c3fb27SDimitry Andric } 44506c3fb27SDimitry Andric }; 44606c3fb27SDimitry Andric 4470b57cec5SDimitry Andric // CommandObjectRegister constructor 4480b57cec5SDimitry Andric CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) 4490b57cec5SDimitry Andric : CommandObjectMultiword(interpreter, "register", 4500b57cec5SDimitry Andric "Commands to access registers for the current " 4510b57cec5SDimitry Andric "thread and stack frame.", 45206c3fb27SDimitry Andric "register [read|write|info] ...") { 4530b57cec5SDimitry Andric LoadSubCommand("read", 4540b57cec5SDimitry Andric CommandObjectSP(new CommandObjectRegisterRead(interpreter))); 4550b57cec5SDimitry Andric LoadSubCommand("write", 4560b57cec5SDimitry Andric CommandObjectSP(new CommandObjectRegisterWrite(interpreter))); 45706c3fb27SDimitry Andric LoadSubCommand("info", 45806c3fb27SDimitry Andric CommandObjectSP(new CommandObjectRegisterInfo(interpreter))); 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric CommandObjectRegister::~CommandObjectRegister() = default; 462