1 //===-- ValueObjectMemory.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/ValueObjectMemory.h"
10 #include "lldb/Core/Value.h"
11 #include "lldb/Core/ValueObject.h"
12 #include "lldb/Symbol/Type.h"
13 #include "lldb/Target/ExecutionContext.h"
14 #include "lldb/Target/Target.h"
15 #include "lldb/Utility/DataExtractor.h"
16 #include "lldb/Utility/Scalar.h"
17 #include "lldb/Utility/Status.h"
18 #include "lldb/lldb-types.h"
19 #include "llvm/Support/ErrorHandling.h"
20 
21 #include <assert.h>
22 #include <memory>
23 
24 namespace lldb_private {
25 class ExecutionContextScope;
26 }
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,
32                                         llvm::StringRef name,
33                                         const Address &address,
34                                         lldb::TypeSP &type_sp) {
35   return (new ValueObjectMemory(exe_scope, name, address, type_sp))->GetSP();
36 }
37 
38 ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope,
39                                         llvm::StringRef name,
40                                         const Address &address,
41                                         const CompilerType &ast_type) {
42   return (new ValueObjectMemory(exe_scope, name, address, ast_type))->GetSP();
43 }
44 
45 ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,
46                                      llvm::StringRef name,
47                                      const Address &address,
48                                      lldb::TypeSP &type_sp)
49     : ValueObject(exe_scope), m_address(address), m_type_sp(type_sp),
50       m_compiler_type() {
51   // Do not attempt to construct one of these objects with no variable!
52   assert(m_type_sp.get() != nullptr);
53   SetName(ConstString(name));
54   m_value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
55   TargetSP target_sp(GetTargetSP());
56   lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
57   if (load_address != LLDB_INVALID_ADDRESS) {
58     m_value.SetValueType(Value::eValueTypeLoadAddress);
59     m_value.GetScalar() = load_address;
60   } else {
61     lldb::addr_t file_address = m_address.GetFileAddress();
62     if (file_address != LLDB_INVALID_ADDRESS) {
63       m_value.SetValueType(Value::eValueTypeFileAddress);
64       m_value.GetScalar() = file_address;
65     } else {
66       m_value.GetScalar() = m_address.GetOffset();
67       m_value.SetValueType(Value::eValueTypeScalar);
68     }
69   }
70 }
71 
72 ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope,
73                                      llvm::StringRef name,
74                                      const Address &address,
75                                      const CompilerType &ast_type)
76     : ValueObject(exe_scope), m_address(address), m_type_sp(),
77       m_compiler_type(ast_type) {
78   // Do not attempt to construct one of these objects with no variable!
79   assert(m_compiler_type.GetTypeSystem());
80   assert(m_compiler_type.GetOpaqueQualType());
81 
82   TargetSP target_sp(GetTargetSP());
83 
84   SetName(ConstString(name));
85   m_value.SetCompilerType(m_compiler_type);
86   lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
87   if (load_address != LLDB_INVALID_ADDRESS) {
88     m_value.SetValueType(Value::eValueTypeLoadAddress);
89     m_value.GetScalar() = load_address;
90   } else {
91     lldb::addr_t file_address = m_address.GetFileAddress();
92     if (file_address != LLDB_INVALID_ADDRESS) {
93       m_value.SetValueType(Value::eValueTypeFileAddress);
94       m_value.GetScalar() = file_address;
95     } else {
96       m_value.GetScalar() = m_address.GetOffset();
97       m_value.SetValueType(Value::eValueTypeScalar);
98     }
99   }
100 }
101 
102 ValueObjectMemory::~ValueObjectMemory() {}
103 
104 CompilerType ValueObjectMemory::GetCompilerTypeImpl() {
105   if (m_type_sp)
106     return m_type_sp->GetForwardCompilerType();
107   return m_compiler_type;
108 }
109 
110 ConstString ValueObjectMemory::GetTypeName() {
111   if (m_type_sp)
112     return m_type_sp->GetName();
113   return m_compiler_type.GetConstTypeName();
114 }
115 
116 ConstString ValueObjectMemory::GetDisplayTypeName() {
117   if (m_type_sp)
118     return m_type_sp->GetForwardCompilerType().GetDisplayTypeName();
119   return m_compiler_type.GetDisplayTypeName();
120 }
121 
122 size_t ValueObjectMemory::CalculateNumChildren(uint32_t max) {
123   if (m_type_sp) {
124     auto child_count = m_type_sp->GetNumChildren(true);
125     return child_count <= max ? child_count : max;
126   }
127 
128   ExecutionContext exe_ctx(GetExecutionContextRef());
129   const bool omit_empty_base_classes = true;
130   auto child_count =
131       m_compiler_type.GetNumChildren(omit_empty_base_classes, &exe_ctx);
132   return child_count <= max ? child_count : max;
133 }
134 
135 uint64_t ValueObjectMemory::GetByteSize() {
136   if (m_type_sp)
137     return m_type_sp->GetByteSize().getValueOr(0);
138   return m_compiler_type.GetByteSize(nullptr).getValueOr(0);
139 }
140 
141 lldb::ValueType ValueObjectMemory::GetValueType() const {
142   // RETHINK: Should this be inherited from somewhere?
143   return lldb::eValueTypeVariableGlobal;
144 }
145 
146 bool ValueObjectMemory::UpdateValue() {
147   SetValueIsValid(false);
148   m_error.Clear();
149 
150   ExecutionContext exe_ctx(GetExecutionContextRef());
151 
152   Target *target = exe_ctx.GetTargetPtr();
153   if (target) {
154     m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
155     m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
156   }
157 
158   Value old_value(m_value);
159   if (m_address.IsValid()) {
160     Value::ValueType value_type = m_value.GetValueType();
161 
162     switch (value_type) {
163     default:
164       llvm_unreachable("Unhandled expression result value kind...");
165 
166     case Value::eValueTypeScalar:
167       // The variable value is in the Scalar value inside the m_value. We can
168       // point our m_data right to it.
169       m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
170       break;
171 
172     case Value::eValueTypeFileAddress:
173     case Value::eValueTypeLoadAddress:
174     case Value::eValueTypeHostAddress:
175       // The DWARF expression result was an address in the inferior process. If
176       // this variable is an aggregate type, we just need the address as the
177       // main value as all child variable objects will rely upon this location
178       // and add an offset and then read their own values as needed. If this
179       // variable is a simple type, we read all data for it into m_data. Make
180       // sure this type has a value before we try and read it
181 
182       // If we have a file address, convert it to a load address if we can.
183       if (value_type == Value::eValueTypeFileAddress &&
184           exe_ctx.GetProcessPtr()) {
185         lldb::addr_t load_addr = m_address.GetLoadAddress(target);
186         if (load_addr != LLDB_INVALID_ADDRESS) {
187           m_value.SetValueType(Value::eValueTypeLoadAddress);
188           m_value.GetScalar() = load_addr;
189         }
190       }
191 
192       if (!CanProvideValue()) {
193         // this value object represents an aggregate type whose children have
194         // values, but this object does not. So we say we are changed if our
195         // location has changed.
196         SetValueDidChange(value_type != old_value.GetValueType() ||
197                           m_value.GetScalar() != old_value.GetScalar());
198       } else {
199         // Copy the Value and set the context to use our Variable so it can
200         // extract read its value into m_data appropriately
201         Value value(m_value);
202         if (m_type_sp)
203           value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
204         else {
205           value.SetCompilerType(m_compiler_type);
206         }
207 
208         m_error = value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
209       }
210       break;
211     }
212 
213     SetValueIsValid(m_error.Success());
214   }
215   return m_error.Success();
216 }
217 
218 bool ValueObjectMemory::IsInScope() {
219   // FIXME: Maybe try to read the memory address, and if that works, then
220   // we are in scope?
221   return true;
222 }
223 
224 lldb::ModuleSP ValueObjectMemory::GetModule() { return m_address.GetModule(); }
225