| //===-- ValueObjectRegister.cpp ---------------------------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Core/ValueObjectRegister.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/Value.h" | |
| #include "lldb/Symbol/CompilerType.h" | |
| #include "lldb/Symbol/TypeSystem.h" | |
| #include "lldb/Target/ExecutionContext.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/RegisterContext.h" | |
| #include "lldb/Target/StackFrame.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Utility/DataExtractor.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/Utility/Scalar.h" | |
| #include "lldb/Utility/Status.h" | |
| #include "lldb/Utility/Stream.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include <assert.h> | |
| #include <memory> | |
| namespace lldb_private { | |
| class ExecutionContextScope; | |
| } | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| #pragma mark ValueObjectRegisterContext | |
| ValueObjectRegisterContext::ValueObjectRegisterContext( | |
| ValueObject &parent, RegisterContextSP ®_ctx) | |
| : ValueObject(parent), m_reg_ctx_sp(reg_ctx) { | |
| assert(reg_ctx); | |
| m_name.SetCString("Registers"); | |
| SetValueIsValid(true); | |
| } | |
| ValueObjectRegisterContext::~ValueObjectRegisterContext() {} | |
| CompilerType ValueObjectRegisterContext::GetCompilerTypeImpl() { | |
| return CompilerType(); | |
| } | |
| ConstString ValueObjectRegisterContext::GetTypeName() { return ConstString(); } | |
| ConstString ValueObjectRegisterContext::GetDisplayTypeName() { | |
| return ConstString(); | |
| } | |
| ConstString ValueObjectRegisterContext::GetQualifiedTypeName() { | |
| return ConstString(); | |
| } | |
| size_t ValueObjectRegisterContext::CalculateNumChildren(uint32_t max) { | |
| auto reg_set_count = m_reg_ctx_sp->GetRegisterSetCount(); | |
| return reg_set_count <= max ? reg_set_count : max; | |
| } | |
| uint64_t ValueObjectRegisterContext::GetByteSize() { return 0; } | |
| bool ValueObjectRegisterContext::UpdateValue() { | |
| m_error.Clear(); | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| StackFrame *frame = exe_ctx.GetFramePtr(); | |
| if (frame) | |
| m_reg_ctx_sp = frame->GetRegisterContext(); | |
| else | |
| m_reg_ctx_sp.reset(); | |
| if (m_reg_ctx_sp.get() == nullptr) { | |
| SetValueIsValid(false); | |
| m_error.SetErrorToGenericError(); | |
| } else | |
| SetValueIsValid(true); | |
| return m_error.Success(); | |
| } | |
| ValueObject *ValueObjectRegisterContext::CreateChildAtIndex( | |
| size_t idx, bool synthetic_array_member, int32_t synthetic_index) { | |
| ValueObject *new_valobj = nullptr; | |
| const size_t num_children = GetNumChildren(); | |
| if (idx < num_children) { | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| new_valobj = new ValueObjectRegisterSet( | |
| exe_ctx.GetBestExecutionContextScope(), m_reg_ctx_sp, idx); | |
| } | |
| return new_valobj; | |
| } | |
| #pragma mark - | |
| #pragma mark ValueObjectRegisterSet | |
| ValueObjectSP | |
| ValueObjectRegisterSet::Create(ExecutionContextScope *exe_scope, | |
| lldb::RegisterContextSP ®_ctx_sp, | |
| uint32_t set_idx) { | |
| return (new ValueObjectRegisterSet(exe_scope, reg_ctx_sp, set_idx))->GetSP(); | |
| } | |
| ValueObjectRegisterSet::ValueObjectRegisterSet(ExecutionContextScope *exe_scope, | |
| lldb::RegisterContextSP ®_ctx, | |
| uint32_t reg_set_idx) | |
| : ValueObject(exe_scope), m_reg_ctx_sp(reg_ctx), m_reg_set(nullptr), | |
| m_reg_set_idx(reg_set_idx) { | |
| assert(reg_ctx); | |
| m_reg_set = reg_ctx->GetRegisterSet(m_reg_set_idx); | |
| if (m_reg_set) { | |
| m_name.SetCString(m_reg_set->name); | |
| } | |
| } | |
| ValueObjectRegisterSet::~ValueObjectRegisterSet() {} | |
| CompilerType ValueObjectRegisterSet::GetCompilerTypeImpl() { | |
| return CompilerType(); | |
| } | |
| ConstString ValueObjectRegisterSet::GetTypeName() { return ConstString(); } | |
| ConstString ValueObjectRegisterSet::GetQualifiedTypeName() { | |
| return ConstString(); | |
| } | |
| size_t ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) { | |
| const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx); | |
| if (reg_set) { | |
| auto reg_count = reg_set->num_registers; | |
| return reg_count <= max ? reg_count : max; | |
| } | |
| return 0; | |
| } | |
| uint64_t ValueObjectRegisterSet::GetByteSize() { return 0; } | |
| bool ValueObjectRegisterSet::UpdateValue() { | |
| m_error.Clear(); | |
| SetValueDidChange(false); | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| StackFrame *frame = exe_ctx.GetFramePtr(); | |
| if (frame == nullptr) | |
| m_reg_ctx_sp.reset(); | |
| else { | |
| m_reg_ctx_sp = frame->GetRegisterContext(); | |
| if (m_reg_ctx_sp) { | |
| const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx); | |
| if (reg_set == nullptr) | |
| m_reg_ctx_sp.reset(); | |
| else if (m_reg_set != reg_set) { | |
| SetValueDidChange(true); | |
| m_name.SetCString(reg_set->name); | |
| } | |
| } | |
| } | |
| if (m_reg_ctx_sp) { | |
| SetValueIsValid(true); | |
| } else { | |
| SetValueIsValid(false); | |
| m_error.SetErrorToGenericError(); | |
| m_children.Clear(); | |
| } | |
| return m_error.Success(); | |
| } | |
| ValueObject *ValueObjectRegisterSet::CreateChildAtIndex( | |
| size_t idx, bool synthetic_array_member, int32_t synthetic_index) { | |
| ValueObject *valobj = nullptr; | |
| if (m_reg_ctx_sp && m_reg_set) { | |
| const size_t num_children = GetNumChildren(); | |
| if (idx < num_children) | |
| valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, | |
| m_reg_set->registers[idx]); | |
| } | |
| return valobj; | |
| } | |
| lldb::ValueObjectSP | |
| ValueObjectRegisterSet::GetChildMemberWithName(ConstString name, | |
| bool can_create) { | |
| ValueObject *valobj = nullptr; | |
| if (m_reg_ctx_sp && m_reg_set) { | |
| const RegisterInfo *reg_info = | |
| m_reg_ctx_sp->GetRegisterInfoByName(name.AsCString()); | |
| if (reg_info != nullptr) | |
| valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, | |
| reg_info->kinds[eRegisterKindLLDB]); | |
| } | |
| if (valobj) | |
| return valobj->GetSP(); | |
| else | |
| return ValueObjectSP(); | |
| } | |
| size_t | |
| ValueObjectRegisterSet::GetIndexOfChildWithName(ConstString name) { | |
| if (m_reg_ctx_sp && m_reg_set) { | |
| const RegisterInfo *reg_info = | |
| m_reg_ctx_sp->GetRegisterInfoByName(name.AsCString()); | |
| if (reg_info != nullptr) | |
| return reg_info->kinds[eRegisterKindLLDB]; | |
| } | |
| return UINT32_MAX; | |
| } | |
| #pragma mark - | |
| #pragma mark ValueObjectRegister | |
| void ValueObjectRegister::ConstructObject(uint32_t reg_num) { | |
| const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); | |
| if (reg_info) { | |
| m_reg_info = *reg_info; | |
| if (reg_info->name) | |
| m_name.SetCString(reg_info->name); | |
| else if (reg_info->alt_name) | |
| m_name.SetCString(reg_info->alt_name); | |
| } | |
| } | |
| ValueObjectRegister::ValueObjectRegister(ValueObject &parent, | |
| lldb::RegisterContextSP ®_ctx_sp, | |
| uint32_t reg_num) | |
| : ValueObject(parent), m_reg_ctx_sp(reg_ctx_sp), m_reg_info(), | |
| m_reg_value(), m_type_name(), m_compiler_type() { | |
| assert(reg_ctx_sp.get()); | |
| ConstructObject(reg_num); | |
| } | |
| ValueObjectSP ValueObjectRegister::Create(ExecutionContextScope *exe_scope, | |
| lldb::RegisterContextSP ®_ctx_sp, | |
| uint32_t reg_num) { | |
| return (new ValueObjectRegister(exe_scope, reg_ctx_sp, reg_num))->GetSP(); | |
| } | |
| ValueObjectRegister::ValueObjectRegister(ExecutionContextScope *exe_scope, | |
| lldb::RegisterContextSP ®_ctx, | |
| uint32_t reg_num) | |
| : ValueObject(exe_scope), m_reg_ctx_sp(reg_ctx), m_reg_info(), | |
| m_reg_value(), m_type_name(), m_compiler_type() { | |
| assert(reg_ctx); | |
| ConstructObject(reg_num); | |
| } | |
| ValueObjectRegister::~ValueObjectRegister() {} | |
| CompilerType ValueObjectRegister::GetCompilerTypeImpl() { | |
| if (!m_compiler_type.IsValid()) { | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| if (auto *target = exe_ctx.GetTargetPtr()) { | |
| if (auto *exe_module = target->GetExecutableModulePointer()) { | |
| auto type_system_or_err = | |
| exe_module->GetTypeSystemForLanguage(eLanguageTypeC); | |
| if (auto err = type_system_or_err.takeError()) { | |
| LLDB_LOG_ERROR( | |
| lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES), | |
| std::move(err), "Unable to get CompilerType from TypeSystem"); | |
| } else { | |
| m_compiler_type = | |
| type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( | |
| m_reg_info.encoding, m_reg_info.byte_size * 8); | |
| } | |
| } | |
| } | |
| } | |
| return m_compiler_type; | |
| } | |
| ConstString ValueObjectRegister::GetTypeName() { | |
| if (m_type_name.IsEmpty()) | |
| m_type_name = GetCompilerType().GetConstTypeName(); | |
| return m_type_name; | |
| } | |
| size_t ValueObjectRegister::CalculateNumChildren(uint32_t max) { | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); | |
| return children_count <= max ? children_count : max; | |
| } | |
| uint64_t ValueObjectRegister::GetByteSize() { return m_reg_info.byte_size; } | |
| bool ValueObjectRegister::UpdateValue() { | |
| m_error.Clear(); | |
| ExecutionContext exe_ctx(GetExecutionContextRef()); | |
| StackFrame *frame = exe_ctx.GetFramePtr(); | |
| if (frame == nullptr) { | |
| m_reg_ctx_sp.reset(); | |
| m_reg_value.Clear(); | |
| } | |
| if (m_reg_ctx_sp) { | |
| RegisterValue m_old_reg_value(m_reg_value); | |
| if (m_reg_ctx_sp->ReadRegister(&m_reg_info, m_reg_value)) { | |
| if (m_reg_value.GetData(m_data)) { | |
| Process *process = exe_ctx.GetProcessPtr(); | |
| if (process) | |
| m_data.SetAddressByteSize(process->GetAddressByteSize()); | |
| m_value.SetContext(Value::eContextTypeRegisterInfo, | |
| (void *)&m_reg_info); | |
| m_value.SetValueType(Value::eValueTypeHostAddress); | |
| m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); | |
| SetValueIsValid(true); | |
| SetValueDidChange(!(m_old_reg_value == m_reg_value)); | |
| return true; | |
| } | |
| } | |
| } | |
| SetValueIsValid(false); | |
| m_error.SetErrorToGenericError(); | |
| return false; | |
| } | |
| bool ValueObjectRegister::SetValueFromCString(const char *value_str, | |
| Status &error) { | |
| // The new value will be in the m_data. Copy that into our register value. | |
| error = | |
| m_reg_value.SetValueFromString(&m_reg_info, llvm::StringRef(value_str)); | |
| if (error.Success()) { | |
| if (m_reg_ctx_sp->WriteRegister(&m_reg_info, m_reg_value)) { | |
| SetNeedsUpdate(); | |
| return true; | |
| } else | |
| return false; | |
| } else | |
| return false; | |
| } | |
| bool ValueObjectRegister::SetData(DataExtractor &data, Status &error) { | |
| error = m_reg_value.SetValueFromData(&m_reg_info, data, 0, false); | |
| if (error.Success()) { | |
| if (m_reg_ctx_sp->WriteRegister(&m_reg_info, m_reg_value)) { | |
| SetNeedsUpdate(); | |
| return true; | |
| } else | |
| return false; | |
| } else | |
| return false; | |
| } | |
| bool ValueObjectRegister::ResolveValue(Scalar &scalar) { | |
| if (UpdateValueIfNeeded( | |
| false)) // make sure that you are up to date before returning anything | |
| return m_reg_value.GetScalarValue(scalar); | |
| return false; | |
| } | |
| void ValueObjectRegister::GetExpressionPath(Stream &s, | |
| bool qualify_cxx_base_classes, | |
| GetExpressionPathFormat epformat) { | |
| s.Printf("$%s", m_reg_info.name); | |
| } |