ClangExpressionDeclMap.cpp revision f328c9ffe0bb00f48601027ec86dbdf238b42c2a
1//===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "lldb/Expression/ClangExpressionDeclMap.h" 11 12// C Includes 13// C++ Includes 14// Other libraries and framework includes 15// Project includes 16#include "lldb/lldb-private.h" 17#include "lldb/Core/Address.h" 18#include "lldb/Core/Error.h" 19#include "lldb/Core/Log.h" 20#include "lldb/Core/Module.h" 21#include "lldb/Expression/ClangASTSource.h" 22#include "lldb/Symbol/ClangASTContext.h" 23#include "lldb/Symbol/CompileUnit.h" 24#include "lldb/Symbol/Function.h" 25#include "lldb/Symbol/ObjectFile.h" 26#include "lldb/Symbol/SymbolContext.h" 27#include "lldb/Symbol/Type.h" 28#include "lldb/Symbol/TypeList.h" 29#include "lldb/Symbol/Variable.h" 30#include "lldb/Symbol/VariableList.h" 31#include "lldb/Target/ExecutionContext.h" 32#include "lldb/Target/Process.h" 33#include "lldb/Target/StackFrame.h" 34#include "lldb/Target/Target.h" 35 36using namespace lldb_private; 37using namespace clang; 38 39ClangExpressionDeclMap::ClangExpressionDeclMap(ExecutionContext *exe_ctx) : 40 m_exe_ctx(exe_ctx), 41 m_struct_laid_out(false), 42 m_materialized_location(0) 43{ 44 if (exe_ctx && exe_ctx->frame) 45 m_sym_ctx = new SymbolContext(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything)); 46 else 47 m_sym_ctx = NULL; 48} 49 50ClangExpressionDeclMap::~ClangExpressionDeclMap() 51{ 52 uint32_t num_tuples = m_tuples.size (); 53 uint32_t tuple_index; 54 55 for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index) 56 delete m_tuples[tuple_index].m_value; 57 58 if (m_sym_ctx) 59 delete m_sym_ctx; 60} 61 62bool 63ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index, 64 const clang::Decl *decl) 65{ 66 uint32_t num_tuples = m_tuples.size (); 67 uint32_t tuple_index; 68 69 for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index) 70 { 71 if (m_tuples[tuple_index].m_decl == decl) 72 { 73 index = tuple_index; 74 return true; 75 } 76 } 77 78 return false; 79} 80 81// Interface for IRForTarget 82 83bool 84ClangExpressionDeclMap::AddValueToStruct (llvm::Value *value, 85 const clang::NamedDecl *decl, 86 std::string &name, 87 void *parser_type, 88 clang::ASTContext *parser_ast_context, 89 size_t size, 90 off_t alignment) 91{ 92 m_struct_laid_out = false; 93 94 StructMemberIterator iter; 95 96 for (iter = m_members.begin(); 97 iter != m_members.end(); 98 ++iter) 99 { 100 if (iter->m_decl == decl) 101 return true; 102 } 103 104 StructMember member; 105 106 member.m_value = value; 107 member.m_decl = decl; 108 member.m_name = name; 109 member.m_parser_type = TypeFromParser(parser_type, parser_ast_context); 110 member.m_offset = 0; 111 member.m_size = size; 112 member.m_alignment = alignment; 113 114 m_members.push_back(member); 115 116 return true; 117} 118 119bool 120ClangExpressionDeclMap::DoStructLayout () 121{ 122 if (m_struct_laid_out) 123 return true; 124 125 StructMemberIterator iter; 126 127 off_t cursor = 0; 128 129 m_struct_alignment = 0; 130 m_struct_size = 0; 131 132 for (iter = m_members.begin(); 133 iter != m_members.end(); 134 ++iter) 135 { 136 if (iter == m_members.begin()) 137 m_struct_alignment = iter->m_alignment; 138 139 if (cursor % iter->m_alignment) 140 cursor += (iter->m_alignment - (cursor % iter->m_alignment)); 141 142 iter->m_offset = cursor; 143 cursor += iter->m_size; 144 } 145 146 m_struct_size = cursor; 147 148 m_struct_laid_out = true; 149 return true; 150} 151 152bool ClangExpressionDeclMap::GetStructInfo (uint32_t &num_elements, 153 size_t &size, 154 off_t &alignment) 155{ 156 if (!m_struct_laid_out) 157 return false; 158 159 num_elements = m_members.size(); 160 size = m_struct_size; 161 alignment = m_struct_alignment; 162 163 return true; 164} 165 166bool 167ClangExpressionDeclMap::GetStructElement (const clang::NamedDecl *&decl, 168 llvm::Value *&value, 169 off_t &offset, 170 uint32_t index) 171{ 172 if (!m_struct_laid_out) 173 return false; 174 175 if (index >= m_members.size()) 176 return false; 177 178 decl = m_members[index].m_decl; 179 value = m_members[index].m_value; 180 offset = m_members[index].m_offset; 181 182 return true; 183} 184 185// Interface for DwarfExpression 186lldb_private::Value 187*ClangExpressionDeclMap::GetValueForIndex (uint32_t index) 188{ 189 if (index >= m_tuples.size ()) 190 return NULL; 191 192 return m_tuples[index].m_value; 193} 194 195// Interface for CommandObjectExpression 196 197bool 198ClangExpressionDeclMap::Materialize (ExecutionContext *exe_ctx, 199 lldb::addr_t &struct_address, 200 Error &err) 201{ 202 bool result = DoMaterialize(false, exe_ctx, NULL, err); 203 204 if (result) 205 struct_address = m_materialized_location; 206 207 return result; 208} 209 210bool 211ClangExpressionDeclMap::Dematerialize (ExecutionContext *exe_ctx, 212 lldb_private::Value &result_value, 213 Error &err) 214{ 215 return DoMaterialize(true, exe_ctx, &result_value, err); 216} 217 218bool 219ClangExpressionDeclMap::DoMaterialize (bool dematerialize, 220 ExecutionContext *exe_ctx, 221 lldb_private::Value *result_value, 222 Error &err) 223{ 224 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 225 226 if (!m_struct_laid_out) 227 { 228 err.SetErrorString("Structure hasn't been laid out yet"); 229 return LLDB_INVALID_ADDRESS; 230 } 231 232 if (!exe_ctx) 233 { 234 err.SetErrorString("Received null execution context"); 235 return LLDB_INVALID_ADDRESS; 236 } 237 238 const SymbolContext &sym_ctx(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything)); 239 240 if (!dematerialize) 241 { 242 if (m_materialized_location) 243 { 244 exe_ctx->process->DeallocateMemory(m_materialized_location); 245 m_materialized_location = 0; 246 } 247 248 lldb::addr_t mem = exe_ctx->process->AllocateMemory(m_struct_alignment + m_struct_size, 249 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 250 err); 251 252 if (mem == LLDB_INVALID_ADDRESS) 253 return false; 254 255 m_allocated_area = mem; 256 } 257 258 m_materialized_location = m_allocated_area; 259 260 if (m_materialized_location % m_struct_alignment) 261 { 262 m_materialized_location += (m_struct_alignment - (m_materialized_location % m_struct_alignment)); 263 } 264 265 StructMemberIterator iter; 266 267 for (iter = m_members.begin(); 268 iter != m_members.end(); 269 ++iter) 270 { 271 uint32_t tuple_index; 272 273 if (!GetIndexForDecl(tuple_index, iter->m_decl)) 274 { 275 if (iter->m_name.find("___clang_expr_result") == std::string::npos) 276 { 277 err.SetErrorStringWithFormat("Unexpected variable %s", iter->m_name.c_str()); 278 return false; 279 } 280 281 if (log) 282 log->Printf("Found special result variable %s", iter->m_name.c_str()); 283 284 if (dematerialize) 285 { 286 clang::ASTContext *context(exe_ctx->target->GetScratchClangASTContext()->getASTContext()); 287 288 if (!context) 289 { 290 err.SetErrorString("Couldn't find a scratch AST context to put the result type into"); 291 } 292 293 TypeFromUser copied_type(ClangASTContext::CopyType(context, 294 iter->m_parser_type.GetASTContext(), 295 iter->m_parser_type.GetType()), 296 context); 297 298 result_value->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type.GetType()); 299 } 300 301 continue; 302 } 303 304 Tuple &tuple(m_tuples[tuple_index]); 305 306 if (!DoMaterializeOneVariable(dematerialize, *exe_ctx, sym_ctx, iter->m_name.c_str(), tuple.m_user_type, m_materialized_location + iter->m_offset, err)) 307 return false; 308 } 309 310 return true; 311} 312 313bool 314ClangExpressionDeclMap::DoMaterializeOneVariable(bool dematerialize, 315 ExecutionContext &exe_ctx, 316 const SymbolContext &sym_ctx, 317 const char *name, 318 TypeFromUser type, 319 lldb::addr_t addr, 320 Error &err) 321{ 322 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 323 324 Variable *var = FindVariableInScope(sym_ctx, name, &type); 325 326 if (!var) 327 { 328 err.SetErrorStringWithFormat("Couldn't find %s with appropriate type", name); 329 return false; 330 } 331 332 log->Printf("%s %s with type %p", (dematerialize ? "Dematerializing" : "Materializing"), name, type.GetType()); 333 334 std::auto_ptr<lldb_private::Value> location_value(GetVariableValue(exe_ctx, 335 var, 336 type.GetASTContext())); 337 338 if (!location_value.get()) 339 { 340 err.SetErrorStringWithFormat("Couldn't get value for %s", name); 341 return false; 342 } 343 344 if (location_value->GetValueType() == Value::eValueTypeLoadAddress) 345 { 346 lldb::addr_t value_addr = location_value->GetScalar().ULongLong(); 347 348 size_t bit_size = ClangASTContext::GetTypeBitSize(type.GetASTContext(), type.GetType()); 349 size_t byte_size = bit_size % 8 ? ((bit_size + 8) / 8) : (bit_size / 8); 350 351 DataBufferHeap data; 352 data.SetByteSize(byte_size); 353 354 lldb::addr_t src_addr; 355 lldb::addr_t dest_addr; 356 357 if (dematerialize) 358 { 359 src_addr = addr; 360 dest_addr = value_addr; 361 } 362 else 363 { 364 src_addr = value_addr; 365 dest_addr = addr; 366 } 367 368 Error error; 369 if (exe_ctx.process->ReadMemory (src_addr, data.GetBytes(), byte_size, error) != byte_size) 370 { 371 err.SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString()); 372 return false; 373 } 374 375 if (exe_ctx.process->WriteMemory (dest_addr, data.GetBytes(), byte_size, error) != byte_size) 376 { 377 err.SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString()); 378 return false; 379 } 380 381 if (log) 382 log->Printf("Copied from 0x%llx to 0x%llx", (uint64_t)src_addr, (uint64_t)addr); 383 } 384 else 385 { 386 StreamString ss; 387 388 location_value->Dump(&ss); 389 390 err.SetErrorStringWithFormat("%s has a value of unhandled type: %s", name, ss.GetString().c_str()); 391 } 392 393 return true; 394} 395 396Variable* 397ClangExpressionDeclMap::FindVariableInScope(const SymbolContext &sym_ctx, 398 const char *name, 399 TypeFromUser *type) 400{ 401 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 402 403 Function *function(m_sym_ctx->function); 404 Block *block(m_sym_ctx->block); 405 406 if (!function || !block) 407 { 408 if (log) 409 log->Printf("function = %p, block = %p", function, block); 410 return NULL; 411 } 412 413 BlockList& blocks(function->GetBlocks(true)); 414 415 ConstString name_cs(name); 416 417 lldb::user_id_t current_block_id; 418 419 for (current_block_id = block->GetID(); 420 current_block_id != Block::InvalidID; 421 current_block_id = blocks.GetParent(current_block_id)) 422 { 423 Block *current_block(blocks.GetBlockByID(current_block_id)); 424 425 lldb::VariableListSP var_list = current_block->GetVariableList(false, true); 426 427 if (!var_list) 428 continue; 429 430 lldb::VariableSP var = var_list->FindVariable(name_cs); 431 432 if (!var) 433 continue; 434 435 // var->GetType()->GetClangAST() is the program's AST context and holds 436 // var->GetType()->GetOpaqueClangQualType(). 437 438 // type is m_type for one of the struct members, which was added by 439 // AddValueToStruct. That type was extracted from the AST context of 440 // the compiler in IRForTarget. The original for the type was copied 441 // out of the program's AST context by AddOneVariable. 442 443 // So that we can compare these two without having to copy back 444 // something we already had in the original AST context, we maintain 445 // m_orig_type and m_ast_context (which are passed into 446 // MaterializeOneVariable by Materialize) for each variable. 447 448 if (!type) 449 return var.get(); 450 451 if (type->GetASTContext() == var->GetType()->GetClangAST()) 452 { 453 if (!ClangASTContext::AreTypesSame(type->GetASTContext(), type, var->GetType()->GetOpaqueClangQualType())) 454 continue; 455 } 456 else 457 { 458 if (log) 459 log->PutCString("Skipping a candidate variable because of different AST contexts"); 460 continue; 461 } 462 463 return var.get(); 464 } 465 466 { 467 CompileUnit *compile_unit = m_sym_ctx->comp_unit; 468 469 if (!compile_unit) 470 { 471 if (log) 472 log->Printf("compile_unit = %p", compile_unit); 473 return NULL; 474 } 475 476 lldb::VariableListSP var_list = compile_unit->GetVariableList(true); 477 478 if (!var_list) 479 return NULL; 480 481 lldb::VariableSP var = var_list->FindVariable(name_cs); 482 483 if (!var) 484 return NULL; 485 486 if (!type) 487 return var.get(); 488 489 if (type->GetASTContext() == var->GetType()->GetClangAST()) 490 { 491 if (!ClangASTContext::AreTypesSame(type->GetASTContext(), type->GetType(), var->GetType()->GetOpaqueClangQualType())) 492 return NULL; 493 } 494 else 495 { 496 if (log) 497 log->PutCString("Skipping a candidate variable because of different AST contexts"); 498 return NULL; 499 } 500 501 return var.get(); 502 } 503 504 return NULL; 505} 506 507// Interface for ClangASTSource 508void 509ClangExpressionDeclMap::GetDecls(NameSearchContext &context, 510 const char *name) 511{ 512 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 513 514 if (log) 515 log->Printf("Hunting for a definition for %s", name); 516 517 // Back out in all cases where we're not fully initialized 518 if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx) 519 return; 520 521 Function *function = m_sym_ctx->function; 522 523 if (!function) 524 { 525 if (log) 526 log->Printf("Can't evaluate an expression when not in a function"); 527 return; 528 } 529 530 ConstString name_cs(name); 531 532 Function *fn = m_sym_ctx->FindFunctionByName(name_cs.GetCString()); 533 534 if (fn) 535 AddOneFunction(context, fn); 536 537 Variable *var = FindVariableInScope(*m_sym_ctx, name); 538 539 if (var) 540 AddOneVariable(context, var); 541} 542 543Value * 544ClangExpressionDeclMap::GetVariableValue(ExecutionContext &exe_ctx, 545 Variable *var, 546 clang::ASTContext *parser_ast_context, 547 TypeFromUser *user_type, 548 TypeFromParser *parser_type) 549{ 550 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 551 552 Type *var_type = var->GetType(); 553 554 if (!var_type) 555 { 556 if (log) 557 log->PutCString("Skipped a definition because it has no type"); 558 return NULL; 559 } 560 561 void *var_opaque_type = var_type->GetOpaqueClangQualType(); 562 563 if (!var_opaque_type) 564 { 565 if (log) 566 log->PutCString("Skipped a definition because it has no Clang type"); 567 return NULL; 568 } 569 570 TypeList *type_list = var_type->GetTypeList(); 571 572 if (!type_list) 573 { 574 if (log) 575 log->PutCString("Skipped a definition because the type has no associated type list"); 576 return NULL; 577 } 578 579 clang::ASTContext *exe_ast_ctx = type_list->GetClangASTContext().getASTContext(); 580 581 if (!exe_ast_ctx) 582 { 583 if (log) 584 log->PutCString("There is no AST context for the current execution context"); 585 return NULL; 586 } 587 588 DWARFExpression &var_location_expr = var->LocationExpression(); 589 590 std::auto_ptr<Value> var_location(new Value); 591 592 Error err; 593 594 if (!var_location_expr.Evaluate(&exe_ctx, exe_ast_ctx, NULL, *var_location.get(), &err)) 595 { 596 if (log) 597 log->Printf("Error evaluating location: %s", err.AsCString()); 598 return NULL; 599 } 600 601 clang::ASTContext *var_ast_context = type_list->GetClangASTContext().getASTContext(); 602 603 void *type_to_use; 604 605 if (parser_ast_context) 606 { 607 type_to_use = ClangASTContext::CopyType(parser_ast_context, var_ast_context, var_opaque_type); 608 609 if (parser_type) 610 *parser_type = TypeFromParser(type_to_use, parser_ast_context); 611 } 612 else 613 type_to_use = var_opaque_type; 614 615 if (var_location.get()->GetContextType() == Value::eContextTypeInvalid) 616 var_location.get()->SetContext(Value::eContextTypeOpaqueClangQualType, type_to_use); 617 618 if (var_location.get()->GetValueType() == Value::eValueTypeFileAddress) 619 { 620 SymbolContext var_sc; 621 var->CalculateSymbolContext(&var_sc); 622 623 if (!var_sc.module_sp) 624 return NULL; 625 626 ObjectFile *object_file = var_sc.module_sp->GetObjectFile(); 627 628 if (!object_file) 629 return NULL; 630 631 Address so_addr(var_location->GetScalar().ULongLong(), object_file->GetSectionList()); 632 633 lldb::addr_t load_addr = so_addr.GetLoadAddress(m_exe_ctx->process); 634 635 var_location->GetScalar() = load_addr; 636 var_location->SetValueType(Value::eValueTypeLoadAddress); 637 } 638 639 if (user_type) 640 *user_type = TypeFromUser(var_opaque_type, var_ast_context); 641 642 return var_location.release(); 643} 644 645void 646ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, 647 Variable* var) 648{ 649 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 650 651 TypeFromUser ut; 652 TypeFromParser pt; 653 654 Value *var_location = GetVariableValue(*m_exe_ctx, 655 var, 656 context.GetASTContext(), 657 &ut, 658 &pt); 659 660 NamedDecl *var_decl = context.AddVarDecl(pt.GetType()); 661 662 Tuple tuple; 663 664 tuple.m_decl = var_decl; 665 tuple.m_value = var_location; 666 tuple.m_user_type = ut; 667 tuple.m_parser_type = pt; 668 669 m_tuples.push_back(tuple); 670 671 if (log) 672 log->PutCString("Found variable"); 673} 674 675void 676ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, 677 Function* fun) 678{ 679 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); 680 681 Type *fun_type = fun->GetType(); 682 683 if (!fun_type) 684 { 685 if (log) 686 log->PutCString("Skipped a function because it has no type"); 687 return; 688 } 689 690 void *fun_opaque_type = fun_type->GetOpaqueClangQualType(); 691 692 if (!fun_opaque_type) 693 { 694 if (log) 695 log->PutCString("Skipped a function because it has no Clang type"); 696 return; 697 } 698 699 std::auto_ptr<Value> fun_location(new Value); 700 701 const Address &fun_address = fun->GetAddressRange().GetBaseAddress(); 702 lldb::addr_t load_addr = fun_address.GetLoadAddress(m_exe_ctx->process); 703 fun_location->SetValueType(Value::eValueTypeLoadAddress); 704 fun_location->GetScalar() = load_addr; 705 706 TypeList *type_list = fun_type->GetTypeList(); 707 clang::ASTContext *fun_ast_context = type_list->GetClangASTContext().getASTContext(); 708 void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), fun_ast_context, fun_opaque_type); 709 710 NamedDecl *fun_decl = context.AddFunDecl(copied_type); 711 712 Tuple tuple; 713 714 tuple.m_decl = fun_decl; 715 tuple.m_value = fun_location.release(); 716 tuple.m_user_type = TypeFromUser(fun_opaque_type, fun_ast_context); 717 718 m_tuples.push_back(tuple); 719 720 if (log) 721 log->PutCString("Found function"); 722} 723