1//===-- ValueObjectRegister.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Core/ValueObjectRegister.h"
10
11#include "lldb/Core/Module.h"
12#include "lldb/Core/Value.h"
13#include "lldb/Symbol/CompilerType.h"
14#include "lldb/Symbol/TypeSystem.h"
15#include "lldb/Target/ExecutionContext.h"
16#include "lldb/Target/Process.h"
17#include "lldb/Target/RegisterContext.h"
18#include "lldb/Target/StackFrame.h"
19#include "lldb/Target/Target.h"
20#include "lldb/Utility/DataExtractor.h"
21#include "lldb/Utility/LLDBLog.h"
22#include "lldb/Utility/Log.h"
23#include "lldb/Utility/Scalar.h"
24#include "lldb/Utility/Status.h"
25#include "lldb/Utility/Stream.h"
26
27#include "llvm/ADT/StringRef.h"
28
29#include <cassert>
30#include <memory>
31#include <optional>
32
33namespace lldb_private {
34class ExecutionContextScope;
35}
36
37using namespace lldb;
38using namespace lldb_private;
39
40#pragma mark ValueObjectRegisterSet
41
42ValueObjectSP
43ValueObjectRegisterSet::Create(ExecutionContextScope *exe_scope,
44 lldb::RegisterContextSP &reg_ctx_sp,
45 uint32_t set_idx) {
46 auto manager_sp = ValueObjectManager::Create();
47 return (new ValueObjectRegisterSet(exe_scope, *manager_sp, reg_ctx_sp,
48 set_idx))
49 ->GetSP();
50}
51
52ValueObjectRegisterSet::ValueObjectRegisterSet(ExecutionContextScope *exe_scope,
53 ValueObjectManager &manager,
54 lldb::RegisterContextSP &reg_ctx,
55 uint32_t reg_set_idx)
56 : ValueObject(exe_scope, manager), m_reg_ctx_sp(reg_ctx),
57 m_reg_set(nullptr), m_reg_set_idx(reg_set_idx) {
58 assert(reg_ctx);
59 m_reg_set = reg_ctx->GetRegisterSet(reg_set: m_reg_set_idx);
60 if (m_reg_set) {
61 m_name.SetCString(m_reg_set->name);
62 }
63}
64
65ValueObjectRegisterSet::~ValueObjectRegisterSet() = default;
66
67CompilerType ValueObjectRegisterSet::GetCompilerTypeImpl() {
68 return CompilerType();
69}
70
71ConstString ValueObjectRegisterSet::GetTypeName() { return ConstString(); }
72
73ConstString ValueObjectRegisterSet::GetQualifiedTypeName() {
74 return ConstString();
75}
76
77llvm::Expected<uint32_t>
78ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) {
79 const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(reg_set: m_reg_set_idx);
80 if (reg_set) {
81 auto reg_count = reg_set->num_registers;
82 return reg_count <= max ? reg_count : max;
83 }
84 return 0;
85}
86
87std::optional<uint64_t> ValueObjectRegisterSet::GetByteSize() { return 0; }
88
89bool ValueObjectRegisterSet::UpdateValue() {
90 m_error.Clear();
91 SetValueDidChange(false);
92 ExecutionContext exe_ctx(GetExecutionContextRef());
93 StackFrame *frame = exe_ctx.GetFramePtr();
94 if (frame == nullptr)
95 m_reg_ctx_sp.reset();
96 else {
97 m_reg_ctx_sp = frame->GetRegisterContext();
98 if (m_reg_ctx_sp) {
99 const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(reg_set: m_reg_set_idx);
100 if (reg_set == nullptr)
101 m_reg_ctx_sp.reset();
102 else if (m_reg_set != reg_set) {
103 SetValueDidChange(true);
104 m_name.SetCString(reg_set->name);
105 }
106 }
107 }
108 if (m_reg_ctx_sp) {
109 SetValueIsValid(true);
110 } else {
111 SetValueIsValid(false);
112 m_error.SetErrorToGenericError();
113 m_children.Clear();
114 }
115 return m_error.Success();
116}
117
118ValueObject *ValueObjectRegisterSet::CreateChildAtIndex(
119 size_t idx, bool synthetic_array_member, int32_t synthetic_index) {
120 ValueObject *valobj = nullptr;
121 if (m_reg_ctx_sp && m_reg_set) {
122 uint32_t num_children = GetNumChildrenIgnoringErrors();
123 if (idx < num_children)
124 valobj = new ValueObjectRegister(
125 *this, m_reg_ctx_sp,
126 m_reg_ctx_sp->GetRegisterInfoAtIndex(reg: m_reg_set->registers[idx]));
127 }
128 return valobj;
129}
130
131lldb::ValueObjectSP
132ValueObjectRegisterSet::GetChildMemberWithName(llvm::StringRef name,
133 bool can_create) {
134 ValueObject *valobj = nullptr;
135 if (m_reg_ctx_sp && m_reg_set) {
136 const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName(reg_name: name);
137 if (reg_info != nullptr)
138 valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, reg_info);
139 }
140 if (valobj)
141 return valobj->GetSP();
142 else
143 return ValueObjectSP();
144}
145
146size_t ValueObjectRegisterSet::GetIndexOfChildWithName(llvm::StringRef name) {
147 if (m_reg_ctx_sp && m_reg_set) {
148 const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName(reg_name: name);
149 if (reg_info != nullptr)
150 return reg_info->kinds[eRegisterKindLLDB];
151 }
152 return UINT32_MAX;
153}
154
155#pragma mark -
156#pragma mark ValueObjectRegister
157
158void ValueObjectRegister::ConstructObject(const RegisterInfo *reg_info) {
159 if (reg_info) {
160 m_reg_info = *reg_info;
161 if (reg_info->name)
162 m_name.SetCString(reg_info->name);
163 else if (reg_info->alt_name)
164 m_name.SetCString(reg_info->alt_name);
165 }
166}
167
168ValueObjectRegister::ValueObjectRegister(ValueObject &parent,
169 lldb::RegisterContextSP &reg_ctx_sp,
170 const RegisterInfo *reg_info)
171 : ValueObject(parent), m_reg_ctx_sp(reg_ctx_sp), m_reg_info(),
172 m_reg_value(), m_type_name(), m_compiler_type() {
173 assert(reg_ctx_sp.get());
174 ConstructObject(reg_info);
175}
176
177ValueObjectSP ValueObjectRegister::Create(ExecutionContextScope *exe_scope,
178 lldb::RegisterContextSP &reg_ctx_sp,
179 const RegisterInfo *reg_info) {
180 auto manager_sp = ValueObjectManager::Create();
181 return (new ValueObjectRegister(exe_scope, *manager_sp, reg_ctx_sp, reg_info))
182 ->GetSP();
183}
184
185ValueObjectRegister::ValueObjectRegister(ExecutionContextScope *exe_scope,
186 ValueObjectManager &manager,
187 lldb::RegisterContextSP &reg_ctx,
188 const RegisterInfo *reg_info)
189 : ValueObject(exe_scope, manager), m_reg_ctx_sp(reg_ctx), m_reg_info(),
190 m_reg_value(), m_type_name(), m_compiler_type() {
191 assert(reg_ctx);
192 ConstructObject(reg_info);
193}
194
195ValueObjectRegister::~ValueObjectRegister() = default;
196
197CompilerType ValueObjectRegister::GetCompilerTypeImpl() {
198 if (!m_compiler_type.IsValid()) {
199 ExecutionContext exe_ctx(GetExecutionContextRef());
200 if (auto *target = exe_ctx.GetTargetPtr()) {
201 if (auto *exe_module = target->GetExecutableModulePointer()) {
202 auto type_system_or_err =
203 exe_module->GetTypeSystemForLanguage(language: eLanguageTypeC);
204 if (auto err = type_system_or_err.takeError()) {
205 LLDB_LOG_ERROR(GetLog(LLDBLog::Types), std::move(err),
206 "Unable to get CompilerType from TypeSystem: {0}");
207 } else {
208 if (auto ts = *type_system_or_err)
209 m_compiler_type = ts->GetBuiltinTypeForEncodingAndBitSize(
210 encoding: m_reg_info.encoding, bit_size: m_reg_info.byte_size * 8);
211 }
212 }
213 }
214 }
215 return m_compiler_type;
216}
217
218ConstString ValueObjectRegister::GetTypeName() {
219 if (m_type_name.IsEmpty())
220 m_type_name = GetCompilerType().GetTypeName();
221 return m_type_name;
222}
223
224llvm::Expected<uint32_t>
225ValueObjectRegister::CalculateNumChildren(uint32_t max) {
226 ExecutionContext exe_ctx(GetExecutionContextRef());
227 auto children_count = GetCompilerType().GetNumChildren(omit_empty_base_classes: true, exe_ctx: &exe_ctx);
228 if (!children_count)
229 return children_count;
230 return *children_count <= max ? *children_count : max;
231}
232
233std::optional<uint64_t> ValueObjectRegister::GetByteSize() {
234 return m_reg_info.byte_size;
235}
236
237bool ValueObjectRegister::UpdateValue() {
238 m_error.Clear();
239 ExecutionContext exe_ctx(GetExecutionContextRef());
240 StackFrame *frame = exe_ctx.GetFramePtr();
241 if (frame == nullptr) {
242 m_reg_ctx_sp.reset();
243 m_reg_value.Clear();
244 }
245
246 if (m_reg_ctx_sp) {
247 RegisterValue m_old_reg_value(m_reg_value);
248 if (m_reg_ctx_sp->ReadRegister(reg_info: &m_reg_info, reg_value&: m_reg_value)) {
249 if (m_reg_value.GetData(data&: m_data)) {
250 Process *process = exe_ctx.GetProcessPtr();
251 if (process)
252 m_data.SetAddressByteSize(process->GetAddressByteSize());
253 m_value.SetContext(context_type: Value::ContextType::RegisterInfo,
254 p: (void *)&m_reg_info);
255 m_value.SetValueType(Value::ValueType::HostAddress);
256 m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
257 SetValueIsValid(true);
258 SetValueDidChange(!(m_old_reg_value == m_reg_value));
259 return true;
260 }
261 }
262 }
263
264 SetValueIsValid(false);
265 m_error.SetErrorToGenericError();
266 return false;
267}
268
269bool ValueObjectRegister::SetValueFromCString(const char *value_str,
270 Status &error) {
271 // The new value will be in the m_data. Copy that into our register value.
272 error =
273 m_reg_value.SetValueFromString(reg_info: &m_reg_info, value_str: llvm::StringRef(value_str));
274 if (!error.Success())
275 return false;
276
277 if (!m_reg_ctx_sp->WriteRegister(reg_info: &m_reg_info, reg_value: m_reg_value)) {
278 error.SetErrorString("unable to write back to register");
279 return false;
280 }
281
282 SetNeedsUpdate();
283 return true;
284}
285
286bool ValueObjectRegister::SetData(DataExtractor &data, Status &error) {
287 error = m_reg_value.SetValueFromData(reg_info: m_reg_info, data, offset: 0, partial_data_ok: false);
288 if (!error.Success())
289 return false;
290
291 if (!m_reg_ctx_sp->WriteRegister(reg_info: &m_reg_info, reg_value: m_reg_value)) {
292 error.SetErrorString("unable to write back to register");
293 return false;
294 }
295
296 SetNeedsUpdate();
297 return true;
298}
299
300bool ValueObjectRegister::ResolveValue(Scalar &scalar) {
301 if (UpdateValueIfNeeded(
302 update_format: false)) // make sure that you are up to date before returning anything
303 return m_reg_value.GetScalarValue(scalar);
304 return false;
305}
306
307void ValueObjectRegister::GetExpressionPath(Stream &s,
308 GetExpressionPathFormat epformat) {
309 s.Printf(format: "$%s", m_reg_info.name);
310}
311

source code of lldb/source/Core/ValueObjectRegister.cpp