diff --git a/lldb/include/lldb/Symbol/Block.h b/lldb/include/lldb/Symbol/Block.h index 8eb8dd311d0f..0ca8547a1362 100644 --- a/lldb/include/lldb/Symbol/Block.h +++ b/lldb/include/lldb/Symbol/Block.h @@ -262,6 +262,22 @@ public: return m_children.front().get(); } + //------------------------------------------------------------------ + /// Get the variable list for this block only. + /// + /// @param[in] can_create + /// If \b true, the variables can be parsed if they already + /// haven't been, else the current state of the block will be + /// returned. + /// + /// @return + /// A variable list shared pointer that contains all variables + /// for this block. + //------------------------------------------------------------------ + lldb::VariableListSP + GetBlockVariableList (bool can_create); + + //------------------------------------------------------------------ /// Get the variable list for this block and optionally all child /// blocks if \a get_child_variables is \b true. @@ -278,7 +294,7 @@ public: /// point. /// /// @param[in] add_inline_child_block_variables - /// If this is \b false, no child variables of child blocks + /// If this is \b false, no child variables of child blocks /// that are inlined functions will be gotten. If \b true then /// all child variables will be added regardless of whether they /// come from inlined functions or not. @@ -287,10 +303,6 @@ public: /// A variable list shared pointer that contains all variables /// for this block. //------------------------------------------------------------------ - lldb::VariableListSP - GetBlockVariableList (bool can_create); - - uint32_t AppendBlockVariables (bool can_create, bool get_child_block_variables, @@ -345,7 +357,7 @@ public: } clang::DeclContext * - GetClangDeclContextForInlinedFunction(); + GetClangDeclContext(); //------------------------------------------------------------------ /// Get the memory cost of this object. diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index 11b67c364048..c88043b68039 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -237,6 +237,12 @@ public: return GetTranslationUnitDecl (getASTContext()); } + static bool + GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx, + lldb::LanguageType &language, + bool &is_instance_method, + ConstString &language_object_name); + static lldb::clang_type_t CopyType(clang::ASTContext *dest_context, clang::ASTContext *source_context, diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h index 5d2181d87fb5..f8ff2d03d7de 100644 --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/lldb/include/lldb/Symbol/SymbolContext.h @@ -220,6 +220,56 @@ public: uint32_t GetResolvedMask () const; + + //------------------------------------------------------------------ + /// Find a block that defines the function represented by this + /// symbol context. + /// + /// If this symbol context points to a block that is an inlined + /// function, or is contained within an inlined function, the block + /// that defines the inlined function is returned. + /// + /// If this symbol context has no block in it, or the block is not + /// itself an inlined function block or contained within one, we + /// return the top level function block. + /// + /// This is a handy function to call when you want to get the block + /// whose variable list will include the arguments for the function + /// that is represented by this symbol context (whether the function + /// is an inline function or not). + /// + /// @return + /// The block object pointer that defines the function that is + /// represented by this symbol context object, NULL otherwise. + //------------------------------------------------------------------ + Block * + GetFunctionBlock (); + + + //------------------------------------------------------------------ + /// If this symbol context represents a function that is a method, + /// return true and provide information about the method. + /// + /// @param[out] language + /// If \b true is returned, the language for the method. + /// + /// @param[out] is_instance_method + /// If \b true is returned, \b true if this is a instance method, + /// \b false if this is a static/class function. + /// + /// @param[out] language_object_name + /// If \b true is returned, the name of the artificial variable + /// for the language ("this" for C++, "self" for ObjC). + /// + /// @return + /// \b True if this symbol context represents a function that + /// is a method of a class, \b false otherwise. + //------------------------------------------------------------------ + bool + GetFunctionMethodInfo (lldb::LanguageType &language, + bool &is_instance_method, + ConstString &language_object_name); + //------------------------------------------------------------------ /// Find a name of the innermost function for the symbol context. /// diff --git a/lldb/include/lldb/Symbol/VariableList.h b/lldb/include/lldb/Symbol/VariableList.h index 21f37e4fc9f0..27d6b2872ccb 100644 --- a/lldb/include/lldb/Symbol/VariableList.h +++ b/lldb/include/lldb/Symbol/VariableList.h @@ -50,6 +50,11 @@ public: lldb::VariableSP FindVariable (const ConstString& name); + // Find the argument variable that represents the language specific + // object pointer ("this" in C++, or "self" in Objective C). + lldb::VariableSP + FindArtificialObjectVariable (lldb::LanguageType language) const; + uint32_t FindVariableIndex (const lldb::VariableSP &var_sp); diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index 7d87699b22a3..84f0e5be182d 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -36,7 +36,8 @@ public: eExpressionPathOptionCheckPtrVsMember = (1u << 0), eExpressionPathOptionsNoFragileObjcIvar = (1u << 1), eExpressionPathOptionsNoSyntheticChildren = (1u << 2), - eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3) + eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3), + eExpressionPathOptionsAllowDirectIVarAccess = (1u << 4) }; //------------------------------------------------------------------ // Constructors and Destructors diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 01510741663d..040412036b37 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -534,7 +534,7 @@ SBFrame::GetValueForVariablePath (const char *var_path, DynamicValueType use_dyn Error error; ValueObjectSP value_sp (frame->GetValueForVariableExpressionPath (var_path, use_dynamic, - StackFrame::eExpressionPathOptionCheckPtrVsMember, + StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp, error)); sb_value.SetSP(value_sp); diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index ab22919ec8d7..4a2663d1e9d5 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -483,7 +483,8 @@ protected: else // No regex, either exact variable names or variable expressions. { Error error; - uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember; + uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; lldb::VariableSP var_sp; valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, m_varobj_options.use_dynamic, diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index ee4b6b963172..bb7ce45eeaf1 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -1015,7 +1015,8 @@ protected: // Things have checked out ok... Error error; - uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember; + uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; valobj_sp = frame->GetValueForVariableExpressionPath (command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index a25b789f1d4d..3e3b0cb1aeab 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -987,48 +987,6 @@ ScanBracketedRange (const char* var_name_begin, return true; } - -static ValueObjectSP -ExpandExpressionPath (ValueObject* valobj, - StackFrame* frame, - bool* do_deref_pointer, - const char* var_name_begin, - const char* var_name_final, - Error& error) -{ - LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - StreamString sstring; - VariableSP var_sp; - - if (*do_deref_pointer) - { - if (log) - log->Printf("been told to deref_pointer by caller"); - sstring.PutChar('*'); - } - else if (valobj->IsDereferenceOfParent() && ClangASTContext::IsPointerType(valobj->GetParent()->GetClangType()) && !valobj->IsArrayItemForPointer()) - { - if (log) - log->Printf("decided to deref_pointer myself"); - sstring.PutChar('*'); - *do_deref_pointer = true; - } - - valobj->GetExpressionPath(sstring, true, ValueObject::eGetExpressionPathFormatHonorPointers); - if (log) - log->Printf("expression path to expand in phase 0: %s",sstring.GetData()); - sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3); - if (log) - log->Printf("expression path to expand in phase 1: %s",sstring.GetData()); - std::string name = std::string(sstring.GetData()); - ValueObjectSP target = frame->GetValueForVariableExpressionPath (name.c_str(), - eNoDynamicValues, - 0, - var_sp, - error); - return target; -} - static ValueObjectSP ExpandIndexedExpression (ValueObject* valobj, uint32_t index, diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index ca0f2ddde043..e85239d01590 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -2443,12 +2443,13 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, if (!sym_ctx.function) return; - clang::DeclContext *decl_context; - - if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo()) - decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction(); - else - decl_context = sym_ctx.function->GetClangDeclContext(); + // Get the block that defines the function + Block *function_block = sym_ctx.GetFunctionBlock(); + + if (!function_block) + return; + + clang::DeclContext *decl_context = function_block->GetClangDeclContext(); if (!decl_context) return; @@ -2501,12 +2502,13 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, if (!sym_ctx.function) return; - clang::DeclContext *decl_context; + // Get the block that defines the function + Block *function_block = sym_ctx.GetFunctionBlock(); - if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo()) - decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction(); - else - decl_context = sym_ctx.function->GetClangDeclContext(); + if (!function_block) + return; + + clang::DeclContext *decl_context = function_block->GetClangDeclContext(); if (!decl_context) return; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 4c64db372c15..4fed8413b566 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -115,13 +115,14 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) if (!sym_ctx.function) return; - clang::DeclContext *decl_context; + // Find the block that defines the function represented by "sym_ctx" + Block *function_block = sym_ctx.GetFunctionBlock(); - if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo()) - decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction(); - else - decl_context = sym_ctx.function->GetClangDeclContext(); - + if (!function_block) + return; + + clang::DeclContext *decl_context = function_block->GetClangDeclContext(); + if (!decl_context) return; @@ -131,24 +132,22 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) { if (m_enforce_valid_object) { - VariableList *vars = frame->GetVariableList(false); + lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true)); const char *thisErrorString = "Stopped in a C++ method, but 'this' isn't available; pretending we are in a generic context"; - if (!vars) + if (!variable_list_sp) { - err.SetErrorToGenericError(); err.SetErrorString(thisErrorString); return; } - lldb::VariableSP this_var = vars->FindVariable(ConstString("this")); + lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this"))); - if (!this_var || - !this_var->IsInScope(frame) || - !this_var->LocationIsValidForFrame (frame)) + if (!this_var_sp || + !this_var_sp->IsInScope(frame) || + !this_var_sp->LocationIsValidForFrame (frame)) { - err.SetErrorToGenericError(); err.SetErrorString(thisErrorString); return; } @@ -164,24 +163,22 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) { if (m_enforce_valid_object) { - VariableList *vars = frame->GetVariableList(false); + lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true)); const char *selfErrorString = "Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context"; - if (!vars) + if (!variable_list_sp) { - err.SetErrorToGenericError(); err.SetErrorString(selfErrorString); return; } - lldb::VariableSP self_var = vars->FindVariable(ConstString("self")); + lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self")); - if (!self_var || - !self_var->IsInScope(frame) || - !self_var->LocationIsValidForFrame (frame)) + if (!self_variable_sp || + !self_variable_sp->IsInScope(frame) || + !self_variable_sp->LocationIsValidForFrame (frame)) { - err.SetErrorToGenericError(); err.SetErrorString(selfErrorString); return; } diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp index 627a5d4d4ffb..fef56b17bfd4 100644 --- a/lldb/source/Symbol/Block.cpp +++ b/lldb/source/Symbol/Block.cpp @@ -542,7 +542,7 @@ Block::AppendVariables } clang::DeclContext * -Block::GetClangDeclContextForInlinedFunction() +Block::GetClangDeclContext() { SymbolContext sc; diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index 6f03dfdd220d..54fd53c74d13 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -6330,3 +6330,49 @@ ClangASTContext::GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl) return llvm::dyn_cast(objc_method_decl); } + +bool +ClangASTContext::GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx, + lldb::LanguageType &language, + bool &is_instance_method, + ConstString &language_object_name) +{ + language_object_name.Clear(); + language = eLanguageTypeUnknown; + is_instance_method = false; + + if (decl_ctx) + { + if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast(decl_ctx)) + { + if (method_decl->isStatic()) + { + is_instance_method = false; + } + else + { + language_object_name.SetCString("this"); + is_instance_method = true; + } + language = eLanguageTypeC_plus_plus; + return true; + } + else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast(decl_ctx)) + { + // Both static and instance methods have a "self" object in objective C + language_object_name.SetCString("self"); + if (method_decl->isInstanceMethod()) + { + is_instance_method = true; + } + else + { + is_instance_method = false; + } + language = eLanguageTypeObjC; + return true; + } + } + return false; +} + diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 4291b0c7197d..b2bb97fd30bb 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -13,6 +13,8 @@ #include "lldb/Core/Module.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" @@ -535,7 +537,61 @@ SymbolContext::GetParentOfInlinedScope (const Address &curr_frame_pc, return false; } -ConstString +Block * +SymbolContext::GetFunctionBlock () +{ + if (function) + { + if (block) + { + // If this symbol context has a block, check to see if this block + // is itself, or is contained within a block with inlined function + // information. If so, then the inlined block is the block that + // defines the function. + Block *inlined_block = block->GetContainingInlinedBlock(); + if (inlined_block) + return inlined_block; + + // The block in this symbol context is not inside an inlined + // block, so the block that defines the function is the function's + // top level block, which is returned below. + } + + // There is no block information in this symbol context, so we must + // assume that the block that is desired is the top level block of + // the function itself. + return &function->GetBlock(true); + } + return NULL; +} + +bool +SymbolContext::GetFunctionMethodInfo (lldb::LanguageType &language, + bool &is_instance_method, + ConstString &language_object_name) + + +{ + Block *function_block = GetFunctionBlock (); + if (function_block) + { + clang::DeclContext *decl_context = function_block->GetClangDeclContext(); + + if (decl_context) + { + return ClangASTContext::GetClassMethodInfoForDeclContext (decl_context, + language, + is_instance_method, + language_object_name); + } + } + language = eLanguageTypeUnknown; + is_instance_method = false; + language_object_name.Clear(); + return false; +} + +ConstString SymbolContext::GetFunctionName (Mangled::NamePreference preference) { if (function) diff --git a/lldb/source/Symbol/VariableList.cpp b/lldb/source/Symbol/VariableList.cpp index 1c2bb0d19b91..ad47c6017ff4 100644 --- a/lldb/source/Symbol/VariableList.cpp +++ b/lldb/source/Symbol/VariableList.cpp @@ -176,3 +176,40 @@ VariableList::Dump(Stream *s, bool show_context) const } } +lldb::VariableSP +VariableList::FindArtificialObjectVariable (lldb::LanguageType language) const +{ + lldb::VariableSP object_variable_sp; + ConstString object_variable_name; + switch (language) + { + case eLanguageTypeC_plus_plus: + object_variable_name.SetCString("this"); + break; + + case eLanguageTypeObjC: + case eLanguageTypeObjC_plus_plus: + object_variable_name.SetCString("self"); + break; + + default: + break; + } + if (object_variable_name) + { + const_iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + { + Variable *variable = pos->get(); + if (variable->IsArtificial() && + variable->GetScope() == eValueTypeVariableArgument && + variable->GetName() == object_variable_name) + { + object_variable_sp = *pos; + break; + } + } + } + return object_variable_sp; +} + diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index d9c9eb252f96..6bfddf63e8f1 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -513,7 +513,7 @@ StackFrame::GetInScopeVariableList (bool get_file_globals) ValueObjectSP -StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, +StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, DynamicValueType use_dynamic, uint32_t options, VariableSP &var_sp, @@ -562,13 +562,42 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx); var_sp = variable_list->FindVariable(name_const_string); + + bool synthetically_added_instance_object = false; + + if (var_sp) + { + var_path.erase (0, name_const_string.GetLength ()); + } + else if (options & eExpressionPathOptionsAllowDirectIVarAccess) + { + // Check for direct ivars access which helps us with implicit + // access to ivars with the "this->" or "self->" + GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock); + lldb::LanguageType method_language = eLanguageTypeUnknown; + bool is_instance_method = false; + ConstString method_object_name; + if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name)) + { + if (is_instance_method && method_object_name) + { + var_sp = variable_list->FindVariable(method_object_name); + if (var_sp) + { + separator_idx = 0; + var_path.insert(0, "->"); + synthetically_added_instance_object = true; + } + } + } + } + if (var_sp) { valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic); if (!valobj_sp) return valobj_sp; - var_path.erase (0, name_const_string.GetLength ()); // We are dumping at least one child while (separator_idx != std::string::npos) { @@ -651,23 +680,35 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, if (no_synth_child || !child_valobj_sp) { // No child member with name "child_name" - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - if (child_name) + if (synthetically_added_instance_object) { - error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"", - child_name.GetCString(), - valobj_sp->GetTypeName().AsCString(""), - var_expr_path_strm.GetString().c_str()); + // We added a "this->" or "self->" to the beginning of the expression + // and this is the first pointer ivar access, so just return the normal + // error + error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame", + name_const_string.GetCString()); } else { - error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"", - var_expr_path_strm.GetString().c_str(), - var_expr_cstr); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + if (child_name) + { + error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"", + child_name.GetCString(), + valobj_sp->GetTypeName().AsCString(""), + var_expr_path_strm.GetString().c_str()); + } + else + { + error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), + var_expr_cstr); + } } return ValueObjectSP(); } } + synthetically_added_instance_object = false; // Remove the child name from the path var_path.erase(0, child_name.GetLength()); if (use_dynamic != eNoDynamicValues)