//===-- ValueObjectRegister.cpp -------------------------------------------===// // // 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 #include namespace lldb_private { class ExecutionContextScope; } using namespace lldb; using namespace lldb_private; #pragma mark ValueObjectRegisterSet ValueObjectSP ValueObjectRegisterSet::Create(ExecutionContextScope *exe_scope, lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx) { auto manager_sp = ValueObjectManager::Create(); return (new ValueObjectRegisterSet(exe_scope, *manager_sp, reg_ctx_sp, set_idx)) ->GetSP(); } ValueObjectRegisterSet::ValueObjectRegisterSet(ExecutionContextScope *exe_scope, ValueObjectManager &manager, lldb::RegisterContextSP ®_ctx, uint32_t reg_set_idx) : ValueObject(exe_scope, manager), 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; } llvm::Optional 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.GetStringRef()); 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.GetStringRef()); 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) { auto manager_sp = ValueObjectManager::Create(); return (new ValueObjectRegister(exe_scope, *manager_sp, reg_ctx_sp, reg_num)) ->GetSP(); } ValueObjectRegister::ValueObjectRegister(ExecutionContextScope *exe_scope, ValueObjectManager &manager, lldb::RegisterContextSP ®_ctx, uint32_t reg_num) : ValueObject(exe_scope, manager), 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().GetTypeName(); 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; } llvm::Optional 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, GetExpressionPathFormat epformat) { s.Printf("$%s", m_reg_info.name); }