|
18 | 18 |
|
19 | 19 | namespace lldb_private::dil { |
20 | 20 |
|
| 21 | +static lldb::ValueObjectSP |
| 22 | +ArrayToPointerConversion(lldb::ValueObjectSP valobj, |
| 23 | + std::shared_ptr<ExecutionContextScope> ctx) { |
| 24 | + assert(valobj->IsArrayType() && |
| 25 | + "an argument to array-to-pointer conversion must be an array"); |
| 26 | + |
| 27 | + uint64_t addr = valobj->GetLoadAddress(); |
| 28 | + llvm::StringRef name = "result"; |
| 29 | + ExecutionContext exe_ctx; |
| 30 | + ctx->CalculateExecutionContext(exe_ctx); |
| 31 | + return ValueObject::CreateValueObjectFromAddress( |
| 32 | + name, addr, exe_ctx, |
| 33 | + valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(), |
| 34 | + /* do_deref */ false); |
| 35 | +} |
| 36 | + |
21 | 37 | static lldb::ValueObjectSP LookupStaticIdentifier( |
22 | 38 | VariableList &variable_list, std::shared_ptr<StackFrame> exe_scope, |
23 | 39 | llvm::StringRef name_ref, llvm::StringRef unqualified_name) { |
@@ -214,6 +230,45 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) { |
214 | 230 | return value_or_error; |
215 | 231 | } |
216 | 232 |
|
| 233 | +static CompilerType GetBasicType(std::shared_ptr<ExecutionContextScope> ctx, |
| 234 | + lldb::BasicType basic_type) { |
| 235 | + static std::unordered_map<lldb::BasicType, CompilerType> basic_types; |
| 236 | + auto type = basic_types.find(basic_type); |
| 237 | + if (type != basic_types.end()) { |
| 238 | + std::string type_name((type->second).GetTypeName().AsCString()); |
| 239 | + // Only return the found type if it's valid. |
| 240 | + if (type_name != "<invalid>") |
| 241 | + return type->second; |
| 242 | + } |
| 243 | + |
| 244 | + lldb::TargetSP target_sp = ctx->CalculateTarget(); |
| 245 | + if (target_sp) { |
| 246 | + for (auto type_system_sp : target_sp->GetScratchTypeSystems()) |
| 247 | + if (auto compiler_type = |
| 248 | + type_system_sp->GetBasicTypeFromAST(basic_type)) { |
| 249 | + basic_types.insert({basic_type, compiler_type}); |
| 250 | + return compiler_type; |
| 251 | + } |
| 252 | + } |
| 253 | + CompilerType empty_type; |
| 254 | + return empty_type; |
| 255 | +} |
| 256 | + |
| 257 | +llvm::Expected<lldb::ValueObjectSP> |
| 258 | +Interpreter::Visit(const ScalarLiteralNode *node) { |
| 259 | + CompilerType result_type = GetBasicType(m_exe_ctx_scope, node->GetType()); |
| 260 | + Scalar value = node->GetValue(); |
| 261 | + |
| 262 | + if (result_type.IsInteger() || result_type.IsNullPtrType() || |
| 263 | + result_type.IsPointerType()) { |
| 264 | + llvm::APInt val = value.GetAPSInt(); |
| 265 | + return ValueObject::CreateValueObjectFromAPInt(m_target, val, result_type, |
| 266 | + "result"); |
| 267 | + } |
| 268 | + |
| 269 | + return lldb::ValueObjectSP(); |
| 270 | +} |
| 271 | + |
217 | 272 | llvm::Expected<lldb::ValueObjectSP> |
218 | 273 | Interpreter::Visit(const IdentifierNode *node) { |
219 | 274 | lldb::DynamicValueType use_dynamic = m_default_dynamic; |
@@ -272,4 +327,108 @@ Interpreter::Visit(const UnaryOpNode *node) { |
272 | 327 | m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); |
273 | 328 | } |
274 | 329 |
|
| 330 | +lldb::ValueObjectSP Interpreter::PointerAdd(lldb::ValueObjectSP lhs, |
| 331 | + int64_t offset) { |
| 332 | + uint64_t byte_size = 0; |
| 333 | + if (auto temp = lhs->GetCompilerType().GetPointeeType().GetByteSize( |
| 334 | + lhs->GetTargetSP().get())) |
| 335 | + byte_size = *temp; |
| 336 | + uintptr_t addr = lhs->GetValueAsUnsigned(0) + offset * byte_size; |
| 337 | + |
| 338 | + llvm::StringRef name = "result"; |
| 339 | + ExecutionContext exe_ctx(m_target.get(), false); |
| 340 | + return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, |
| 341 | + lhs->GetCompilerType(), |
| 342 | + /* do_deref */ false); |
| 343 | +} |
| 344 | + |
| 345 | +llvm::Expected<lldb::ValueObjectSP> |
| 346 | +Interpreter::Visit(const ArraySubscriptNode *node) { |
| 347 | + auto lhs_or_err = Evaluate(node->lhs()); |
| 348 | + if (!lhs_or_err) { |
| 349 | + return lhs_or_err; |
| 350 | + } |
| 351 | + lldb::ValueObjectSP base = *lhs_or_err; |
| 352 | + auto rhs_or_err = Evaluate(node->rhs()); |
| 353 | + if (!rhs_or_err) { |
| 354 | + return rhs_or_err; |
| 355 | + } |
| 356 | + lldb::ValueObjectSP index = *rhs_or_err; |
| 357 | + |
| 358 | + Status error; |
| 359 | + if (base->GetCompilerType().IsReferenceType()) { |
| 360 | + base = base->Dereference(error); |
| 361 | + if (error.Fail()) |
| 362 | + return error.ToError(); |
| 363 | + } |
| 364 | + if (index->GetCompilerType().IsReferenceType()) { |
| 365 | + index = index->Dereference(error); |
| 366 | + if (error.Fail()) |
| 367 | + return error.ToError(); |
| 368 | + } |
| 369 | + |
| 370 | + auto index_type = index->GetCompilerType(); |
| 371 | + if (!index_type.IsIntegerOrUnscopedEnumerationType()) |
| 372 | + return llvm::make_error<DILDiagnosticError>( |
| 373 | + m_expr, "array subscript is not an integer", node->GetLocation()); |
| 374 | + |
| 375 | + // Check to see if 'base' has a synthetic value; if so, try using that. |
| 376 | + if (base->HasSyntheticValue()) { |
| 377 | + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); |
| 378 | + if (synthetic && synthetic != base) { |
| 379 | + uint32_t num_children = synthetic->GetNumChildrenIgnoringErrors(); |
| 380 | + // Verify that the 'index' is not out-of-range for the declared type. |
| 381 | + if (index->GetValueAsSigned(0) >= num_children) { |
| 382 | + auto message = |
| 383 | + llvm::formatv("array index {0} is not valid for \"({1}) {2}\"", |
| 384 | + index->GetValueAsSigned(0), |
| 385 | + base->GetTypeName().AsCString("<invalid type>"), |
| 386 | + base->GetName().AsCString()); |
| 387 | + return llvm::make_error<DILDiagnosticError>(m_expr, message, |
| 388 | + node->GetLocation()); |
| 389 | + } |
| 390 | + |
| 391 | + uint64_t child_idx = index->GetValueAsUnsigned(0); |
| 392 | + if (static_cast<uint32_t>(child_idx) < |
| 393 | + synthetic->GetNumChildrenIgnoringErrors()) { |
| 394 | + lldb::ValueObjectSP child_valobj_sp = |
| 395 | + synthetic->GetChildAtIndex(child_idx); |
| 396 | + if (child_valobj_sp) { |
| 397 | + return child_valobj_sp; |
| 398 | + } |
| 399 | + } |
| 400 | + } |
| 401 | + } |
| 402 | + |
| 403 | + auto base_type = base->GetCompilerType(); |
| 404 | + if (!base_type.IsPointerType() && !base_type.IsArrayType()) |
| 405 | + return llvm::make_error<DILDiagnosticError>( |
| 406 | + m_expr, "subscripted value is not an array or pointer", |
| 407 | + node->GetLocation()); |
| 408 | + if (base_type.IsPointerToVoid()) |
| 409 | + return llvm::make_error<DILDiagnosticError>( |
| 410 | + m_expr, "subscript of pointer to incomplete type 'void'", |
| 411 | + node->GetLocation()); |
| 412 | + |
| 413 | + if (base_type.IsArrayType()) |
| 414 | + base = ArrayToPointerConversion(base, m_exe_ctx_scope); |
| 415 | + |
| 416 | + CompilerType item_type = base->GetCompilerType().GetPointeeType(); |
| 417 | + lldb::addr_t base_addr = base->GetValueAsUnsigned(0); |
| 418 | + |
| 419 | + llvm::StringRef name = "result"; |
| 420 | + ExecutionContext exe_ctx(m_target.get(), false); |
| 421 | + // Create a pointer and add the index, i.e. "base + index". |
| 422 | + lldb::ValueObjectSP value = |
| 423 | + PointerAdd(ValueObject::CreateValueObjectFromAddress( |
| 424 | + name, base_addr, exe_ctx, item_type.GetPointerType(), |
| 425 | + /*do_deref=*/false), |
| 426 | + index->GetValueAsSigned(0)); |
| 427 | + |
| 428 | + lldb::ValueObjectSP val2 = value->Dereference(error); |
| 429 | + if (error.Fail()) |
| 430 | + return error.ToError(); |
| 431 | + return val2; |
| 432 | +} |
| 433 | + |
275 | 434 | } // namespace lldb_private::dil |
0 commit comments