Added support for generating expressions that have
access to the members of the Objective-C self object.
The approach we take is to generate the method as a
@category on top of the self object, and to pass the
"self" pointer to it. (_cmd is currently NULL.)
Most changes are in ClangExpressionDeclMap, but the
change that adds support to the ABIs to pass _cmd
touches a fair amount of code.
llvm-svn: 121722
diff --git a/lldb/source/Expression/ASTResultSynthesizer.cpp b/lldb/source/Expression/ASTResultSynthesizer.cpp
index bcabfe3..36f78b3 100644
--- a/lldb/source/Expression/ASTResultSynthesizer.cpp
+++ b/lldb/source/Expression/ASTResultSynthesizer.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
@@ -54,9 +55,23 @@
void
ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
{
- LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
+ {
+ if (log)
+ {
+ if (named_decl->getIdentifier())
+ log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
+ log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
+ else
+ log->Printf("TransformTopLevelDecl(<complex>)");
+ }
+
+ }
- if (linkage_spec_decl)
+ if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
{
RecordDecl::decl_iterator decl_iterator;
@@ -67,14 +82,21 @@
TransformTopLevelDecl(*decl_iterator);
}
}
-
- FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
-
- if (m_ast_context &&
- function_decl &&
- !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
{
- SynthesizeResult(function_decl);
+ if (m_ast_context &&
+ !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
+ {
+ SynthesizeObjCMethodResult(method_decl);
+ }
+ }
+ else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
+ {
+ if (m_ast_context &&
+ !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
+ {
+ SynthesizeFunctionResult(function_decl);
+ }
}
}
@@ -97,15 +119,15 @@
}
bool
-ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
+ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
{
- ASTContext &Ctx(*m_ast_context);
-
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ ASTContext &Ctx(*m_ast_context);
+
if (!m_sema)
return false;
-
+
FunctionDecl *function_decl = FunDecl;
if (!function_decl)
@@ -126,6 +148,80 @@
Stmt *function_body = function_decl->getBody();
CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
+ bool ret = SynthesizeBodyResult (compound_stmt,
+ function_decl);
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ function_decl->print(os);
+
+ os.flush();
+
+ log->Printf("Transformed function AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
+{
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ASTContext &Ctx(*m_ast_context);
+
+ if (!m_sema)
+ return false;
+
+ if (!MethodDecl)
+ return false;
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ Ctx.getTranslationUnitDecl()->print(os);
+
+ os.flush();
+
+ log->Printf("AST context before transforming:\n%s", s.c_str());
+ }
+
+ Stmt *method_body = MethodDecl->getBody();
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
+
+ bool ret = SynthesizeBodyResult (compound_stmt,
+ MethodDecl);
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ MethodDecl->print(os);
+
+ os.flush();
+
+ log->Printf("Transformed function AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
+ DeclContext *DC)
+{
+ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ASTContext &Ctx(*m_ast_context);
+
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(Body);
+
if (!compound_stmt)
return false;
@@ -169,7 +265,7 @@
IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
clang::VarDecl *result_decl = VarDecl::Create(Ctx,
- function_decl,
+ DC,
SourceLocation(),
&result_id,
expr_qual_type,
@@ -180,7 +276,7 @@
if (!result_decl)
return false;
- function_decl->addDecl(result_decl);
+ DC->addDecl(result_decl);
///////////////////////////////
// call AddInitializerToDecl
@@ -210,18 +306,6 @@
*last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());
- if (log)
- {
- std::string s;
- raw_string_ostream os(s);
-
- function_decl->print(os);
-
- os.flush();
-
- log->Printf("Transformed function AST:\n%s", s.c_str());
- }
-
return true;
}
diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp
index 09d6ed0..34103a6 100644
--- a/lldb/source/Expression/ClangASTSource.cpp
+++ b/lldb/source/Expression/ClangASTSource.cpp
@@ -227,6 +227,14 @@
return tag_decl;
}
+ else if (ObjCObjectType *objc_object_type = dyn_cast<clang::ObjCObjectType>(qual_type))
+ {
+ ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
+
+ m_decls.push_back((NamedDecl*)interface_decl);
+
+ return (NamedDecl*)interface_decl;
+ }
else
{
return NULL;
diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp
index a93ff17..449db41 100644
--- a/lldb/source/Expression/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp
@@ -371,6 +371,7 @@
ClangExpressionDeclMap::GetObjectPointer
(
lldb::addr_t &object_ptr,
+ ConstString &object_name,
ExecutionContext &exe_ctx,
Error &err
)
@@ -389,12 +390,11 @@
return false;
}
- static ConstString g_this_const_str ("this");
- Variable *object_ptr_var = FindVariableInScope (*exe_ctx.frame, g_this_const_str, &m_struct_vars->m_object_pointer_type);
+ Variable *object_ptr_var = FindVariableInScope (*exe_ctx.frame, object_name, &m_struct_vars->m_object_pointer_type);
if (!object_ptr_var)
{
- err.SetErrorString("Couldn't find 'this' with appropriate type in scope");
+ err.SetErrorStringWithFormat("Couldn't find '%s' with appropriate type in scope", object_name.GetCString());
return false;
}
@@ -404,7 +404,7 @@
if (!location_value.get())
{
- err.SetErrorString("Couldn't get the location for 'this'");
+ err.SetErrorStringWithFormat("Couldn't get the location for '%s'", object_name.GetCString());
return false;
}
@@ -417,7 +417,7 @@
if (ClangASTType::GetClangTypeBitWidth(m_struct_vars->m_object_pointer_type.GetASTContext(),
m_struct_vars->m_object_pointer_type.GetOpaqueQualType()) != address_byte_size * 8)
{
- err.SetErrorStringWithFormat("'this' is not of an expected pointer size");
+ err.SetErrorStringWithFormat("'%s' is not of an expected pointer size", object_name.GetCString());
return false;
}
@@ -427,7 +427,7 @@
if (exe_ctx.process->ReadMemory (value_addr, data.GetBytes(), address_byte_size, read_error) != address_byte_size)
{
- err.SetErrorStringWithFormat("Coldn't read 'this' from the target: %s", read_error.AsCString());
+ err.SetErrorStringWithFormat("Coldn't read '%s' from the target: %s", object_name.GetCString(), read_error.AsCString());
return false;
}
@@ -441,7 +441,7 @@
}
else
{
- err.SetErrorString("'this' is not in memory; LLDB must be extended to handle registers");
+ err.SetErrorStringWithFormat("'%s' is not in memory; LLDB must be extended to handle registers", object_name.GetCString());
return false;
}
}
@@ -1250,11 +1250,66 @@
TypeFromUser class_user_type(pointer_target_type,
this_type->GetClangAST());
+ if (log)
+ {
+ StreamString type_stream;
+ class_user_type.DumpTypeCode(&type_stream);
+ type_stream.Flush();
+ log->Printf("Adding type for $__lldb_class: %s", type_stream.GetString().c_str());
+ }
+
AddOneType(context, class_user_type, true);
return;
}
+ static ConstString g_lldb_objc_class_name ("$__lldb_objc_class");
+ if (name == g_lldb_objc_class_name)
+ {
+ // Clang is looking for the type of "*self"
+
+ VariableList *vars = m_parser_vars->m_exe_ctx->frame->GetVariableList(false);
+
+ if (!vars)
+ return;
+
+ lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
+
+ if (!self_var)
+ return;
+
+ Type *self_type = self_var->GetType();
+
+ if (!self_type)
+ return;
+
+ TypeFromUser self_user_type(self_type->GetClangType(),
+ self_type->GetClangAST());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+
+ void *pointer_target_type;
+
+ if (!ClangASTContext::IsPointerType(self_user_type.GetOpaqueQualType(),
+ &pointer_target_type))
+ return;
+
+ TypeFromUser class_user_type(pointer_target_type,
+ self_type->GetClangAST());
+
+ if (log)
+ {
+ StreamString type_stream;
+ class_user_type.DumpTypeCode(&type_stream);
+ type_stream.Flush();
+ log->Printf("Adding type for $__lldb_objc_class: %s", type_stream.GetString().c_str());
+ }
+
+ AddOneType(context, class_user_type, false);
+
+ return;
+ }
+
ClangExpressionVariable *pvar(m_parser_vars->m_persistent_vars->GetVariable(name));
if (pvar)
diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp
index 3dc31ec..3eac429 100644
--- a/lldb/source/Expression/ClangFunction.cpp
+++ b/lldb/source/Expression/ClangFunction.cpp
@@ -372,7 +372,8 @@
Stream &errors,
bool stop_others,
bool discard_on_error,
- lldb::addr_t *this_arg)
+ lldb::addr_t *this_arg,
+ lldb::addr_t *cmd_arg)
{
// FIXME: Use the errors Stream for better error reporting.
@@ -388,11 +389,12 @@
Address wrapper_address (NULL, func_addr);
ThreadPlan *new_plan = new ThreadPlanCallFunction (*exe_ctx.thread,
- wrapper_address,
- args_addr,
- stop_others,
- discard_on_error,
- this_arg);
+ wrapper_address,
+ args_addr,
+ stop_others,
+ discard_on_error,
+ this_arg,
+ cmd_arg);
return new_plan;
}
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp
index 366b10e..8669666 100644
--- a/lldb/source/Expression/ClangUserExpression.cpp
+++ b/lldb/source/Expression/ClangUserExpression.cpp
@@ -174,6 +174,27 @@
m_needs_object_ptr = true;
}
+ else if(m_objectivec)
+ {
+ const char *function_name = FunctionName();
+
+ m_transformed_stream.Printf("%s \n"
+ "@interface $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg; \n"
+ "@end \n"
+ "@implementation $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg \n"
+ "{ \n"
+ " %s; \n"
+ "} \n"
+ "@end \n",
+ m_expr_prefix.c_str(),
+ function_name,
+ function_name,
+ m_expr_text.c_str());
+
+ m_needs_object_ptr = true;
+ }
else
{
m_transformed_stream.Printf("%s \n"
@@ -297,14 +318,31 @@
if (m_jit_addr != LLDB_INVALID_ADDRESS)
{
-
Error materialize_error;
-
- if (m_needs_object_ptr && !(m_expr_decl_map->GetObjectPointer(object_ptr, exe_ctx, materialize_error)))
+ if (m_needs_object_ptr)
{
- error_stream.Printf("Couldn't get required object pointer: %s\n", materialize_error.AsCString());
- return false;
+ ConstString object_name;
+
+ if (m_cplusplus)
+ {
+ object_name.SetCString("this");
+ }
+ else if (m_objectivec)
+ {
+ object_name.SetCString("self");
+ }
+ else
+ {
+ error_stream.Printf("Need object pointer but don't know the language\n");
+ return false;
+ }
+
+ if (!(m_expr_decl_map->GetObjectPointer(object_ptr, object_name, exe_ctx, materialize_error)))
+ {
+ error_stream.Printf("Couldn't get required object pointer: %s\n", materialize_error.AsCString());
+ return false;
+ }
}
if (!m_expr_decl_map->Materialize(exe_ctx, struct_address, materialize_error))
@@ -351,19 +389,22 @@
lldb::addr_t struct_address;
lldb::addr_t object_ptr = NULL;
+ lldb::addr_t cmd_ptr = NULL;
PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr);
// FIXME: This should really return a ThreadPlanCallUserExpression, in order to make sure that we don't release the
// ClangUserExpression resources before the thread plan finishes execution in the target. But because we are
- // forcing unwind_on_error to be true here, in practical terms that can't happen.
+ // forcing unwind_on_error to be true here, in practical terms that can't happen.
+
return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
m_jit_addr,
struct_address,
error_stream,
true,
true,
- (m_needs_object_ptr ? &object_ptr : NULL));
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ (m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL);
}
bool
@@ -423,17 +464,24 @@
lldb::addr_t struct_address;
lldb::addr_t object_ptr = NULL;
+ lldb::addr_t cmd_ptr = NULL;
- PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr);
+ if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr))
+ return Process::eExecutionSetupError;
const bool stop_others = true;
const bool try_all_threads = true;
Address wrapper_address (NULL, m_jit_addr);
- lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (*(exe_ctx.thread), wrapper_address, struct_address,
- stop_others, discard_on_error,
- (m_needs_object_ptr ? &object_ptr : NULL),
- shared_ptr_to_me));
+ lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (*(exe_ctx.thread),
+ wrapper_address,
+ struct_address,
+ stop_others,
+ discard_on_error,
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
+ shared_ptr_to_me));
+
if (call_plan_sp == NULL || !call_plan_sp->ValidatePlan (NULL))
return Process::eExecutionSetupError;
diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp
index 6d730d9..34f146f 100644
--- a/lldb/source/Expression/IRForTarget.cpp
+++ b/lldb/source/Expression/IRForTarget.cpp
@@ -899,7 +899,7 @@
size_t value_size = (ast_context->getTypeSize(qual_type) + 7) / 8;
off_t value_alignment = (ast_context->getTypeAlign(qual_type) + 7) / 8;
-
+
if (log)
log->Printf("Type of \"%s\" is [clang \"%s\", lldb \"%s\"] [size %d, align %d]",
name.c_str(),
@@ -907,7 +907,7 @@
PrintType(value_type).c_str(),
value_size,
value_alignment);
-
+
if (named_decl && !m_decl_map->AddValueToStruct(named_decl,
lldb_private::ConstString (name.c_str()),
@@ -1353,6 +1353,23 @@
argument = iter;
}
+ else if (argument->getName().equals("self"))
+ {
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ return false;
+
+ if (!iter->getName().equals("_cmd"))
+ return false;
+
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ return false;
+
+ argument = iter;
+ }
if (!argument->getName().equals("$__lldb_arg"))
return false;
@@ -1430,7 +1447,11 @@
//
if (!CreateResultVariable(llvm_module, *function))
+ {
+ if (log)
+ log->Printf("CreateResultVariable() failed");
return false;
+ }
///////////////////////////////////////////////////////////////////////////////
// Fix all Objective-C constant strings to use NSStringWithCString:encoding:
@@ -1449,7 +1470,11 @@
}
if (!RewriteObjCConstStrings(llvm_module, *function))
+ {
+ if (log)
+ log->Printf("RewriteObjCConstStrings() failed");
return false;
+ }
if (log)
{
@@ -1472,16 +1497,32 @@
++bbi)
{
if (!RemoveGuards(llvm_module, *bbi))
+ {
+ if (log)
+ log->Printf("RemoveGuards() failed");
return false;
+ }
if (!RewritePersistentAllocs(llvm_module, *bbi))
+ {
+ if (log)
+ log->Printf("RewritePersistentAllocs() failed");
return false;
+ }
if (!RewriteObjCSelectors(llvm_module, *bbi))
+ {
+ if (log)
+ log->Printf("RewriteObjCSelectors() failed");
return false;
+ }
if (!ResolveCalls(llvm_module, *bbi))
+ {
+ if (log)
+ log->Printf("ResolveCalls() failed");
return false;
+ }
}
///////////////////////////////
@@ -1489,10 +1530,18 @@
//
if (!ResolveExternals(llvm_module, *function))
+ {
+ if (log)
+ log->Printf("ResolveExternals() failed");
return false;
+ }
if (!ReplaceVariables(llvm_module, *function))
+ {
+ if (log)
+ log->Printf("ReplaceVariables() failed");
return false;
+ }
if (log)
{