diff --git a/lldb/include/lldb/Expression/ClangExpressionDeclMap.h b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h index 3e7f4ce21083..ed00a1f576de 100644 --- a/lldb/include/lldb/Expression/ClangExpressionDeclMap.h +++ b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h @@ -48,7 +48,8 @@ public: const clang::Decl *decl); // Interface for IRForTarget - bool AddPersistentVariable (const clang::NamedDecl *decl); + void GetPersistentResultName (std::string &name); + bool AddPersistentVariable (const char *name, TypeFromParser type); bool AddValueToStruct (llvm::Value *value, const clang::NamedDecl *decl, std::string &name, @@ -84,7 +85,7 @@ public: Error &error); bool Dematerialize(ExecutionContext *exe_ctx, - lldb_private::Value &result_value, + ClangPersistentVariable *&result, Error &error); // Interface for ClangASTSource @@ -127,6 +128,7 @@ private: bool m_struct_laid_out; lldb::addr_t m_allocated_area; lldb::addr_t m_materialized_location; + std::string m_result_name; Variable *FindVariableInScope(const SymbolContext &sym_ctx, const char *name, @@ -145,7 +147,7 @@ private: bool DoMaterialize (bool dematerialize, ExecutionContext *exe_ctx, - lldb_private::Value *result_value, /* must be non-NULL if D is set */ + ClangPersistentVariable **result, /* must be non-NULL if D is set */ Error &err); bool DoMaterializeOnePersistentVariable(bool dematerialize, diff --git a/lldb/include/lldb/Expression/ClangPersistentVariables.h b/lldb/include/lldb/Expression/ClangPersistentVariables.h index b60c256d5859..7bac5ccd247d 100644 --- a/lldb/include/lldb/Expression/ClangPersistentVariables.h +++ b/lldb/include/lldb/Expression/ClangPersistentVariables.h @@ -26,12 +26,14 @@ class ClangPersistentVariable friend class ClangPersistentVariables; public: ClangPersistentVariable () : + m_name(), m_user_type(), m_data() { } ClangPersistentVariable (const ClangPersistentVariable &pv) : + m_name(pv.m_name), m_user_type(pv.m_user_type), m_data(pv.m_data) { @@ -39,6 +41,7 @@ public: ClangPersistentVariable &operator=(const ClangPersistentVariable &pv) { + m_name = pv.m_name; m_user_type = pv.m_user_type; m_data = pv.m_data; return *this; @@ -58,12 +61,21 @@ public: { return m_user_type; } + + Error Print(Stream &output_stream, + ExecutionContext &exe_ctx, + lldb::Format format, + bool show_types, + bool show_summary, + bool verbose); private: - ClangPersistentVariable (TypeFromUser user_type) + ClangPersistentVariable (ConstString name, TypeFromUser user_type) { + m_name = name; m_user_type = user_type; m_data = lldb::DataBufferSP(new DataBufferHeap(Size(), 0)); } + ConstString m_name; TypeFromUser m_user_type; lldb::DataBufferSP m_data; }; @@ -72,9 +84,10 @@ class ClangPersistentVariables { public: ClangPersistentVariable *CreateVariable (ConstString name, TypeFromUser user_type); - ClangPersistentVariable *CreateResultVariable (TypeFromUser user_type); ClangPersistentVariable *GetVariable (ConstString name); + void GetNextResultName(std::string &name); + ClangPersistentVariables (); private: typedef std::map PVarMap; diff --git a/lldb/include/lldb/Expression/IRForTarget.h b/lldb/include/lldb/Expression/IRForTarget.h index e9dbc94151d0..db18e5b67151 100644 --- a/lldb/include/lldb/Expression/IRForTarget.h +++ b/lldb/include/lldb/Expression/IRForTarget.h @@ -39,6 +39,12 @@ public: llvm::PassManagerType T = llvm::PMT_ModulePassManager); llvm::PassManagerType getPotentialPassManagerType() const; private: + // pass to find the result variable created in the result synthesizer and + // make a result variable out of it (or a void variable if there is no + // result) + bool createResultVariable(llvm::Module &M, + llvm::Function &F); + // pass to rewrite Objective-C method calls to use the runtime function // sel_registerName bool RewriteObjCSelector(llvm::Instruction* selector_load, diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 7d83b2c722b0..a9cf2194fd9a 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -252,7 +252,7 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream bool canInterpret = false; clang::ASTContext *ast_context = clang_expr.GetASTContext (); - Value expr_result; + ClangPersistentVariable *expr_result = 0; Error expr_error; canInterpret = clang_expr.ConvertIRToDWARF (expr_local_vars, dwarf_opcodes); @@ -373,79 +373,32 @@ CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream if (!expr_decl_map.Dematerialize(&m_exe_ctx, expr_result, expr_error)) { - error_stream.Printf ("Couldn't dematerialize struct: %s\n", expr_error.AsCString("unknown error")); + error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); return false; } } - - /////////////////////////////////////// - // Interpret the result and print it - // - lldb::Format format = m_options.format; - - // Resolve any values that are possible - expr_result.ResolveValue (&m_exe_ctx, ast_context); - - if (expr_result.GetContextType () == Value::eContextTypeInvalid && - expr_result.GetValueType () == Value::eValueTypeScalar && - format == eFormatDefault) + if (expr_result) { - // The expression result is just a scalar with no special formatting - expr_result.GetScalar ().GetValue (&output_stream, m_options.show_types); - output_stream.EOL (); - return true; - } - - // The expression result is more complext and requires special handling - DataExtractor data; - expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0); - - if (!expr_error.Success ()) - { - error_stream.Printf ("error: couldn't resolve result value: %s\n", expr_error.AsCString ()); - return false; - } - - if (format == eFormatDefault) - format = expr_result.GetValueDefaultFormat (); - - void *clang_type = expr_result.GetValueOpaqueClangQualType (); - - if (clang_type) - { - if (m_options.show_types) - output_stream.Printf("(%s) ", ClangASTType::GetClangTypeName (clang_type).GetCString()); + StreamString ss; - ClangASTType::DumpValue (ast_context, // The ASTContext that the clang type belongs to - clang_type, // The opaque clang type we want to dump that value of - &m_exe_ctx, // The execution context for memory and variable access - &output_stream, // Stream to dump to - format, // Format to use when dumping - data, // A buffer containing the bytes for the clang type - 0, // Byte offset within "data" where value is - data.GetByteSize (), // Size in bytes of the value we are dumping - 0, // Bitfield bit size - 0, // Bitfield bit offset - m_options.show_types, // Show types? - m_options.show_summary, // Show summary? - m_options.debug, // Debug logging output? - UINT32_MAX); // Depth to dump in case this is an aggregate type + Error err = expr_result->Print (ss, + m_exe_ctx, + m_options.format, + m_options.show_types, + m_options.show_summary, + m_options.debug); + + if (err.Success()) + output_stream.PutCString(ss.GetString().c_str()); + else + error_stream.Printf ("Couldn't print result : %s\n", err.AsCString("unknown error")); } else { - data.Dump (&output_stream, // Stream to dump to - 0, // Byte offset within "data" - format, // Format to use when dumping - data.GetByteSize (), // Size in bytes of each item we are dumping - 1, // Number of items to dump - UINT32_MAX, // Number of items per line - LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context - 0, // Bitfield bit size - 0); // Bitfield bit offset + error_stream.Printf ("Expression produced no result\n"); } - output_stream.EOL(); - + return true; } diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index da4333c49c70..fb10605a36fb 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -83,22 +83,25 @@ ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index, // Interface for IRForTarget +void +ClangExpressionDeclMap::GetPersistentResultName (std::string &name) +{ + m_persistent_vars->GetNextResultName(m_result_name); + + name = m_result_name; +} + bool -ClangExpressionDeclMap::AddPersistentVariable (const clang::NamedDecl *decl) +ClangExpressionDeclMap::AddPersistentVariable (const char *name, TypeFromParser parser_type) { clang::ASTContext *context(m_exe_ctx->target->GetScratchClangASTContext()->getASTContext()); - const clang::VarDecl *var(dyn_cast(decl)); - - if (!var) - return false; - TypeFromUser user_type(ClangASTContext::CopyType(context, - &var->getASTContext(), - var->getType().getAsOpaquePtr()), + parser_type.GetASTContext(), + parser_type.GetOpaqueQualType()), context); - ConstString const_name(decl->getName().str().c_str()); + ConstString const_name(name); ClangPersistentVariable *pvar = m_persistent_vars->CreateVariable(const_name, user_type); @@ -292,10 +295,10 @@ ClangExpressionDeclMap::Materialize (ExecutionContext *exe_ctx, bool ClangExpressionDeclMap::Dematerialize (ExecutionContext *exe_ctx, - lldb_private::Value &result_value, + ClangPersistentVariable *&result, Error &err) { - return DoMaterialize(true, exe_ctx, &result_value, err); + return DoMaterialize(true, exe_ctx, &result, err); } bool @@ -366,11 +369,11 @@ ClangExpressionDeclMap::DumpMaterializedStruct(ExecutionContext *exe_ctx, bool ClangExpressionDeclMap::DoMaterialize (bool dematerialize, ExecutionContext *exe_ctx, - lldb_private::Value *result_value, + ClangPersistentVariable **result, Error &err) { Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - + if (!m_struct_laid_out) { err.SetErrorString("Structure hasn't been laid out yet"); @@ -426,36 +429,54 @@ ClangExpressionDeclMap::DoMaterialize (bool dematerialize, if (!GetIndexForDecl(tuple_index, iter->m_decl)) { + if (iter->m_name.find("___clang_expr_result") != std::string::npos) + { + if (dematerialize) + { + // Here we pick up the odd anomaly produced by + // IRForTarget::createResultVariable (and described in a comment + // there). + // + // We rename the variable to the name of the result PVar and + // incidentally drop the address of the PVar into *result + // (if it's non-NULL, of course). We then let this case fall + // through to the persistent variable handler. + + if (log) + log->PutCString("Found result member in the struct"); + + iter->m_name = m_result_name; + + if (result) + { + if (log) + log->PutCString("Returning result PVar"); + + *result = m_persistent_vars->GetVariable(ConstString(m_result_name.c_str())); + + if (!*result) + { + err.SetErrorStringWithFormat("Couldn't find persistent variable for result %s", m_result_name.c_str()); + } + } + else + { + if (log) + log->PutCString("Didn't return result PVar; pointer was NULL"); + } + } + else + { + // The result variable doesn't need to be materialized, ever. + continue; + } + } + if (iter->m_name[0] == '$') { if (!DoMaterializeOnePersistentVariable(dematerialize, *exe_ctx, iter->m_name.c_str(), m_materialized_location + iter->m_offset, err)) return false; } - else if (iter->m_name.find("___clang_expr_result") != std::string::npos) - { - if (log) - log->Printf("Found special result variable %s", iter->m_name.c_str()); - - if (dematerialize) - { - clang::ASTContext *context(exe_ctx->target->GetScratchClangASTContext()->getASTContext()); - - if (!context) - { - err.SetErrorString("Couldn't find a scratch AST context to put the result type into"); - } - - TypeFromUser copied_type(ClangASTContext::CopyType(context, - iter->m_parser_type.GetASTContext(), - iter->m_parser_type.GetOpaqueQualType()), - context); - - result_value->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type.GetOpaqueQualType()); - - result_value->SetValueType(Value::eValueTypeLoadAddress); - result_value->GetScalar() = (uintptr_t)m_materialized_location + iter->m_offset; - } - } else { err.SetErrorStringWithFormat("Unexpected variable %s", iter->m_name.c_str()); diff --git a/lldb/source/Expression/ClangPersistentVariables.cpp b/lldb/source/Expression/ClangPersistentVariables.cpp index dbeac0062503..7e1664889cc1 100644 --- a/lldb/source/Expression/ClangPersistentVariables.cpp +++ b/lldb/source/Expression/ClangPersistentVariables.cpp @@ -8,11 +8,98 @@ //===----------------------------------------------------------------------===// #include "ClangPersistentVariables.h" +#include "lldb/Core/DataExtractor.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/Value.h" using namespace lldb_private; -using namespace clang; + +Error +ClangPersistentVariable::Print (Stream &output_stream, + ExecutionContext &exe_ctx, + lldb::Format format, + bool show_types, + bool show_summary, + bool verbose) +{ + Error err; + + Value val; + + clang::ASTContext *ast_context = m_user_type.GetASTContext(); + + val.SetContext (Value::eContextTypeOpaqueClangQualType, m_user_type.GetOpaqueQualType ()); + val.SetValueType (Value::eValueTypeHostAddress); + val.GetScalar() = (uint64_t)Data (); + + val.ResolveValue (&exe_ctx, ast_context); + + if (val.GetContextType () == Value::eContextTypeInvalid && + val.GetValueType () == Value::eValueTypeScalar && + format == lldb::eFormatDefault) + { + // The expression result is just a scalar with no special formatting + val.GetScalar ().GetValue (&output_stream, show_types); + output_stream.EOL (); + return err; + } + + // The expression result is more complext and requires special handling + DataExtractor data; + Error expr_error = val.GetValueAsData (&exe_ctx, ast_context, data, 0); + + if (!expr_error.Success ()) + { + err.SetErrorToGenericError (); + err.SetErrorStringWithFormat ("Couldn't resolve result value: %s", expr_error.AsCString ()); + return err; + } + + if (format == lldb::eFormatDefault) + format = val.GetValueDefaultFormat (); + + void *clang_type = val.GetValueOpaqueClangQualType (); + + output_stream.Printf("%s = ", m_name.AsCString("")); + + if (clang_type) + { + if (show_types) + output_stream.Printf("(%s) ", ClangASTType::GetClangTypeName (clang_type).GetCString()); + + ClangASTType::DumpValue (ast_context, // The ASTContext that the clang type belongs to + clang_type, // The opaque clang type we want to dump that value of + &exe_ctx, // The execution context for memory and variable access + &output_stream, // Stream to dump to + format, // Format to use when dumping + data, // A buffer containing the bytes for the clang type + 0, // Byte offset within "data" where value is + data.GetByteSize (), // Size in bytes of the value we are dumping + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Show types? + show_summary, // Show summary? + verbose, // Debug logging output? + UINT32_MAX); // Depth to dump in case this is an aggregate type + } + else + { + data.Dump (&output_stream, // Stream to dump to + 0, // Byte offset within "data" + format, // Format to use when dumping + data.GetByteSize (), // Size in bytes of each item we are dumping + 1, // Number of items to dump + UINT32_MAX, // Number of items per line + LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context + 0, // Bitfield bit size + 0); // Bitfield bit offset + } + + output_stream.EOL(); + + return err; +} ClangPersistentVariables::ClangPersistentVariables () : m_variables(), @@ -24,7 +111,7 @@ ClangPersistentVariable * ClangPersistentVariables::CreateVariable (ConstString name, TypeFromUser user_type) { - ClangPersistentVariable new_var(user_type); + ClangPersistentVariable new_var(name, user_type); if (m_variables.find(name) != m_variables.end()) return NULL; @@ -34,21 +121,6 @@ ClangPersistentVariables::CreateVariable (ConstString name, return &m_variables[name]; } -ClangPersistentVariable * -ClangPersistentVariables::CreateResultVariable (TypeFromUser user_type) -{ - StreamString s; - s.Printf("$%llu", m_result_counter); - ConstString name(s.GetString().c_str()); - - ClangPersistentVariable *ret = CreateVariable (name, user_type); - - if (ret != NULL) - ++m_result_counter; - - return ret; -} - ClangPersistentVariable * ClangPersistentVariables::GetVariable (ConstString name) { @@ -57,3 +129,14 @@ ClangPersistentVariables::GetVariable (ConstString name) return &m_variables[name]; } + +void +ClangPersistentVariables::GetNextResultName (std::string &name) +{ + StreamString s; + s.Printf("$%llu", m_result_counter); + + m_result_counter++; + + name = s.GetString(); +} diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index 9541945eebc0..ca1aeb4327c8 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -14,6 +14,7 @@ #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Target/TargetData.h" +#include "llvm/ValueSymbolTable.h" #include "clang/AST/ASTContext.h" @@ -55,6 +56,129 @@ IRForTarget::~IRForTarget() { } +bool +IRForTarget::createResultVariable(llvm::Module &M, + llvm::Function &F) +{ + lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + // Find the result variable + + Value *result_value = M.getNamedValue("___clang_expr_result"); + + if (!result_value) + { + if (log) + log->PutCString("Couldn't find result variable"); + return false; + } + + if (log) + log->Printf("Found result in the IR: %s", PrintValue(result_value, false).c_str()); + + GlobalVariable *result_global = dyn_cast(result_value); + + if (!result_global) + { + if (log) + log->PutCString("Result variable isn't a GlobalVariable"); + return false; + } + + // Find the metadata and follow it to the VarDecl + + NamedMDNode *named_metadata = M.getNamedMetadata("clang.global.decl.ptrs"); + + if (!named_metadata) + { + if (log) + log->PutCString("No global metadata"); + + return false; + } + + unsigned num_nodes = named_metadata->getNumOperands(); + unsigned node_index; + + MDNode *metadata_node = NULL; + + for (node_index = 0; + node_index < num_nodes; + ++node_index) + { + metadata_node = named_metadata->getOperand(node_index); + + if (metadata_node->getNumOperands() != 2) + continue; + + if (metadata_node->getOperand(0) == result_global) + break; + } + + if (!metadata_node) + { + if (log) + log->PutCString("Couldn't find result metadata"); + return false; + } + + ConstantInt *constant_int = dyn_cast(metadata_node->getOperand(1)); + + uint64_t result_decl_intptr = constant_int->getZExtValue(); + + clang::VarDecl *result_decl = reinterpret_cast(result_decl_intptr); + + // Get the next available result name from m_decl_map and create the persistent + // variable for it + + lldb_private::TypeFromParser result_decl_type (result_decl->getType().getAsOpaquePtr(), + &result_decl->getASTContext()); + std::string new_result_name; + + m_decl_map->GetPersistentResultName(new_result_name); + m_decl_map->AddPersistentVariable(new_result_name.c_str(), result_decl_type); + + if (log) + log->Printf("Creating a new result global: %s", new_result_name.c_str()); + + // Construct a new result global and set up its metadata + + GlobalVariable *new_result_global = new GlobalVariable(M, + result_global->getType()->getElementType(), + false, /* not constant */ + GlobalValue::ExternalLinkage, + NULL, /* no initializer */ + new_result_name.c_str()); + + // It's too late in compilation to create a new VarDecl for this, but we don't + // need to. We point the metadata at the old VarDecl. This creates an odd + // anomaly: a variable with a Value whose name is something like $0 and a + // Decl whose name is ___clang_expr_result. This condition is handled in + // ClangExpressionDeclMap::DoMaterialize, and the name of the variable is + // fixed up. + + ConstantInt *new_constant_int = ConstantInt::get(constant_int->getType(), + result_decl_intptr, + false); + + llvm::Value* values[2]; + values[0] = new_result_global; + values[1] = new_constant_int; + + MDNode *persistent_global_md = MDNode::get(M.getContext(), values, 2); + named_metadata->addOperand(persistent_global_md); + + if (log) + log->Printf("Replacing %s with %s", + PrintValue(result_global).c_str(), + PrintValue(new_result_global).c_str()); + + result_global->replaceAllUsesWith(new_result_global); + result_global->eraseFromParent(); + + return true; +} + static bool isObjCSelectorRef(Value *V) { GlobalVariable *GV = dyn_cast(V); @@ -234,9 +358,12 @@ IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc, uintptr_t ptr = constant_int->getZExtValue(); - clang::NamedDecl *decl = reinterpret_cast(ptr); + clang::VarDecl *decl = reinterpret_cast(ptr); - if (!m_decl_map->AddPersistentVariable(decl)) + lldb_private::TypeFromParser result_decl_type (decl->getType().getAsOpaquePtr(), + &decl->getASTContext()); + + if (!m_decl_map->AddPersistentVariable(decl->getName().str().c_str(), result_decl_type)) return false; GlobalVariable *persistent_global = new GlobalVariable(M, @@ -760,7 +887,7 @@ IRForTarget::replaceVariables(Module &M, Function &F) if (log) log->Printf(" %s (%s) placed at %d", - decl->getIdentifier()->getNameStart(), + value->getName().str().c_str(), PrintValue(value, true).c_str(), offset); @@ -797,6 +924,13 @@ IRForTarget::runOnModule(Module &M) Function::iterator bbi; + //////////////////////////////////////////////////////////// + // Replace __clang_expr_result with a persistent variable + // + + if (!createResultVariable(M, *function)) + return false; + ////////////////////////////////// // Run basic-block level passes //