mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-01 18:56:05 +00:00

StringRef will call strlen on the C string which is inefficient (as ConstString already knows the string lenght and so does StringRef). This patch replaces all those calls with GetStringRef() which doesn't recompute the length.
297 lines
9.4 KiB
C++
297 lines
9.4 KiB
C++
//===-- 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 <assert.h>
|
|
#include <memory>
|
|
|
|
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) {
|
|
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.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) {
|
|
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,
|
|
GetExpressionPathFormat epformat) {
|
|
s.Printf("$%s", m_reg_info.name);
|
|
}
|