forked from OSchip/llvm-project
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
This commit is contained in:
parent
4efa445f3c
commit
1782783095
|
@ -34,6 +34,7 @@ namespace clang
|
|||
class CodeGenOptions;
|
||||
class CodeGenerator;
|
||||
class CompilerInstance;
|
||||
class CompoundStmt;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXBoolLiteralExpr;
|
||||
class CXXFunctionalCastExpr;
|
||||
|
|
|
@ -122,13 +122,32 @@ private:
|
|||
//----------------------------------------------------------------------
|
||||
void TransformTopLevelDecl(clang::Decl *D);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Process an Objective-C method and produce the result variable and
|
||||
/// initialization
|
||||
///
|
||||
/// @param[in] MethodDecl
|
||||
/// The method to process.
|
||||
//----------------------------------------------------------------------
|
||||
bool SynthesizeObjCMethodResult(clang::ObjCMethodDecl *MethodDecl);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Process a function and produce the result variable and initialization
|
||||
///
|
||||
/// @param[in] FunDecl
|
||||
/// The function to process.
|
||||
//----------------------------------------------------------------------
|
||||
bool SynthesizeResult(clang::FunctionDecl *FunDecl);
|
||||
bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// Process a functionbody and produce the result variable and
|
||||
/// initialization
|
||||
///
|
||||
/// @param[in] Body
|
||||
/// The body of the function.
|
||||
//----------------------------------------------------------------------
|
||||
bool SynthesizeBodyResult(clang::CompoundStmt *Body,
|
||||
clang::DeclContext *DC);
|
||||
|
||||
clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types.
|
||||
clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer.
|
||||
|
|
|
@ -291,6 +291,10 @@ public:
|
|||
/// @param[out] object_ptr
|
||||
/// The this pointer.
|
||||
///
|
||||
/// @param[in] object_name
|
||||
/// The name of the object pointer -- "this," "self," or similar
|
||||
/// depending on language
|
||||
///
|
||||
/// @param[in] exe_ctx
|
||||
/// The execution context at which to dump the struct.
|
||||
///
|
||||
|
@ -302,6 +306,7 @@ public:
|
|||
/// True on success; false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool GetObjectPointer(lldb::addr_t &object_ptr,
|
||||
ConstString &object_name,
|
||||
ExecutionContext &exe_ctx,
|
||||
Error &error);
|
||||
|
||||
|
|
|
@ -423,8 +423,13 @@ public:
|
|||
/// True if the thread plan may simply be discarded if an error occurs.
|
||||
///
|
||||
/// @param[in] this_arg
|
||||
/// If non-NULL, the function is invoked like a C++ method, with the
|
||||
/// value pointed to by the pointer as its 'this' argument.
|
||||
/// If non-NULL (and cmd_arg is NULL), the function is invoked like a C++
|
||||
/// method, with the value pointed to by the pointer as its 'this'
|
||||
/// argument.
|
||||
///
|
||||
/// @param[in] cmd_arg
|
||||
/// If non-NULL, the function is invoked like an Objective-C method, with
|
||||
/// this_arg in the 'self' slot and cmd_arg in the '_cmd' slot
|
||||
///
|
||||
/// @return
|
||||
/// A ThreadPlan for executing the function.
|
||||
|
@ -436,7 +441,8 @@ public:
|
|||
Stream &errors,
|
||||
bool stop_others,
|
||||
bool discard_on_error,
|
||||
lldb::addr_t *this_arg = 0);
|
||||
lldb::addr_t *this_arg = 0,
|
||||
lldb::addr_t *cmd_arg = 0);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Get a thread plan to run the function this ClangFunction was created with.
|
||||
|
|
|
@ -162,6 +162,12 @@ public:
|
|||
DumpTypeDescription (clang::ASTContext *ast_context,
|
||||
lldb::clang_type_t opaque_clang_qual_type,
|
||||
Stream *s);
|
||||
|
||||
void DumpTypeCode (Stream *s);
|
||||
|
||||
static void
|
||||
DumpTypeCode (void *type,
|
||||
Stream *s);
|
||||
|
||||
lldb::Encoding
|
||||
GetEncoding (uint32_t &count);
|
||||
|
|
|
@ -35,7 +35,8 @@ public:
|
|||
lldb::addr_t functionAddress,
|
||||
lldb::addr_t returnAddress,
|
||||
lldb::addr_t arg,
|
||||
lldb::addr_t *this_arg) const = 0;
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) const = 0;
|
||||
|
||||
virtual bool
|
||||
GetArgumentValues (Thread &thread,
|
||||
|
|
|
@ -28,7 +28,8 @@ public:
|
|||
lldb::addr_t arg,
|
||||
bool stop_other_threads,
|
||||
bool discard_on_error = true,
|
||||
lldb::addr_t *this_arg = 0);
|
||||
lldb::addr_t *this_arg = 0,
|
||||
lldb::addr_t *cmd_arg = 0);
|
||||
|
||||
virtual
|
||||
~ThreadPlanCallFunction ();
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
bool stop_other_threads,
|
||||
bool discard_on_error,
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg,
|
||||
ClangUserExpression::ClangUserExpressionSP &user_expression_sp);
|
||||
|
||||
virtual
|
||||
|
|
|
@ -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 @@ ASTResultSynthesizer::Initialize(ASTContext &Context)
|
|||
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 @@ ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
|
|||
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 @@ ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
|
|||
}
|
||||
|
||||
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 @@ ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
|
|||
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 @@ ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
|
|||
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 @@ ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
|
|||
if (!result_decl)
|
||||
return false;
|
||||
|
||||
function_decl->addDecl(result_decl);
|
||||
DC->addDecl(result_decl);
|
||||
|
||||
///////////////////////////////
|
||||
// call AddInitializerToDecl
|
||||
|
@ -210,18 +306,6 @@ ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
|
|||
|
||||
*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;
|
||||
}
|
||||
|
||||
|
|
|
@ -227,6 +227,14 @@ clang::NamedDecl *NameSearchContext::AddTypeDecl(void *type)
|
|||
|
||||
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;
|
||||
|
|
|
@ -371,6 +371,7 @@ bool
|
|||
ClangExpressionDeclMap::GetObjectPointer
|
||||
(
|
||||
lldb::addr_t &object_ptr,
|
||||
ConstString &object_name,
|
||||
ExecutionContext &exe_ctx,
|
||||
Error &err
|
||||
)
|
||||
|
@ -389,12 +390,11 @@ ClangExpressionDeclMap::GetObjectPointer
|
|||
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 @@ ClangExpressionDeclMap::GetObjectPointer
|
|||
|
||||
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 @@ ClangExpressionDeclMap::GetObjectPointer
|
|||
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 @@ ClangExpressionDeclMap::GetObjectPointer
|
|||
|
||||
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 @@ ClangExpressionDeclMap::GetObjectPointer
|
|||
}
|
||||
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 @@ ClangExpressionDeclMap::GetDecls (NameSearchContext &context, const ConstString
|
|||
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)
|
||||
|
|
|
@ -372,7 +372,8 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
|
|||
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 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,27 @@ ClangUserExpression::Parse (Stream &error_stream,
|
|||
|
||||
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 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
|
||||
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 @@ ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream,
|
|||
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 @@ ClangUserExpression::Execute (Stream &error_stream,
|
|||
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;
|
||||
|
||||
|
|
|
@ -899,7 +899,7 @@ IRForTarget::MaybeHandleVariable (Module &llvm_module, Value *llvm_value_ptr)
|
|||
|
||||
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 @@ IRForTarget::MaybeHandleVariable (Module &llvm_module, Value *llvm_value_ptr)
|
|||
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 @@ IRForTarget::ReplaceVariables (Module &llvm_module, Function &llvm_function)
|
|||
|
||||
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 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
//
|
||||
|
||||
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 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
}
|
||||
|
||||
if (!RewriteObjCConstStrings(llvm_module, *function))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("RewriteObjCConstStrings() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
@ -1472,16 +1497,32 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
++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 @@ IRForTarget::runOnModule (Module &llvm_module)
|
|||
//
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -58,7 +58,8 @@ ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
|
|||
lldb::addr_t functionAddress,
|
||||
lldb::addr_t returnAddress,
|
||||
lldb::addr_t arg,
|
||||
lldb::addr_t *this_arg) const
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) const
|
||||
{
|
||||
RegisterContext *reg_ctx = thread.GetRegisterContext();
|
||||
if (!reg_ctx)
|
||||
|
@ -73,7 +74,9 @@ ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
|
|||
|
||||
// Make room for the argument(s) on the stack
|
||||
|
||||
if (this_arg)
|
||||
if (this_arg && cmd_arg)
|
||||
sp -= 12;
|
||||
else if (this_arg)
|
||||
sp -= 8;
|
||||
else
|
||||
sp -= 4;
|
||||
|
@ -86,6 +89,19 @@ ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
|
|||
|
||||
Error error;
|
||||
|
||||
if (this_arg && cmd_arg)
|
||||
{
|
||||
uint32_t cmd_argU32 = *cmd_arg & 0xffffffffull;
|
||||
uint32_t this_argU32 = *this_arg & 0xffffffffull;
|
||||
uint32_t argU32 = arg & 0xffffffffull;
|
||||
|
||||
if (thread.GetProcess().WriteMemory(sp, &this_argU32, sizeof(this_argU32), error) != sizeof(this_argU32))
|
||||
return false;
|
||||
if (thread.GetProcess().WriteMemory(sp, &cmd_argU32, sizeof(cmd_argU32), error) != sizeof(cmd_argU32))
|
||||
return false;
|
||||
if (thread.GetProcess().WriteMemory(sp + 4, &argU32, sizeof(argU32), error) != sizeof(argU32))
|
||||
return false;
|
||||
}
|
||||
if (this_arg)
|
||||
{
|
||||
uint32_t this_argU32 = *this_arg & 0xffffffffull;
|
||||
|
|
|
@ -35,7 +35,8 @@ namespace lldb_private {
|
|||
lldb::addr_t functionAddress,
|
||||
lldb::addr_t returnAddress,
|
||||
lldb::addr_t arg,
|
||||
lldb::addr_t *this_arg) const;
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) const;
|
||||
|
||||
virtual bool
|
||||
PrepareNormalCall (Thread &thread,
|
||||
|
|
|
@ -59,18 +59,22 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
|
|||
lldb::addr_t functionAddress,
|
||||
lldb::addr_t returnAddress,
|
||||
lldb::addr_t arg,
|
||||
lldb::addr_t *this_arg) const
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) const
|
||||
{
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
||||
|
||||
if (log)
|
||||
log->Printf("ABISysV_x86_64::PrepareTrivialCall\n(\n thread = %p\n sp = 0x%llx\n functionAddress = 0x%llx\n returnAddress = 0x%llx\n arg = 0x%llx\n this_arg = %p(0x%llx)\n)",
|
||||
log->Printf("ABISysV_x86_64::PrepareTrivialCall\n(\n thread = %p\n sp = 0x%llx\n functionAddress = 0x%llx\n returnAddress = 0x%llx\n arg = 0x%llx\n this_arg = %p(0x%llx)\n cmd_arg = %p(0x%llx)\n)",
|
||||
(void*)&thread,
|
||||
(uint64_t)sp,
|
||||
(uint64_t)functionAddress,
|
||||
(uint64_t)returnAddress,
|
||||
(void*)arg,
|
||||
this_arg ? (uint64_t)*this_arg : (uint64_t)0);
|
||||
this_arg,
|
||||
this_arg ? (uint64_t)*this_arg : (uint64_t)0,
|
||||
cmd_arg,
|
||||
cmd_arg ? (uint64_t)*cmd_arg : (uint64_t)0);
|
||||
|
||||
RegisterContext *reg_ctx = thread.GetRegisterContext();
|
||||
if (!reg_ctx)
|
||||
|
@ -88,6 +92,31 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
|
|||
|
||||
// The argument is in %rdi, and not on the stack.
|
||||
|
||||
if (cmd_arg)
|
||||
{
|
||||
if (log)
|
||||
log->PutCString("The trivial call has a self and a _cmd pointer");
|
||||
|
||||
uint32_t rsiID = reg_ctx->GetRegisterInfoByName("rsi", 0)->kinds[eRegisterKindLLDB];
|
||||
uint32_t rdxID = reg_ctx->GetRegisterInfoByName("rdx", 0)->kinds[eRegisterKindLLDB];
|
||||
|
||||
if (log)
|
||||
log->Printf("About to write 'self' (0x%llx) into RDI", (uint64_t)*this_arg);
|
||||
|
||||
if (!reg_ctx->WriteRegisterFromUnsigned(rdiID, *this_arg))
|
||||
return false;
|
||||
|
||||
if (log)
|
||||
log->Printf("About to write '_cmd' (0x%llx) into RSI", (uint64_t)*cmd_arg);
|
||||
|
||||
if (!reg_ctx->WriteRegisterFromUnsigned(rsiID, *this_arg))
|
||||
return false;
|
||||
|
||||
if (log)
|
||||
log->Printf("About to write the argument (0x%llx) into RDX", (uint64_t)arg);
|
||||
|
||||
if (!reg_ctx->WriteRegisterFromUnsigned(rdxID, arg))
|
||||
return false; }
|
||||
if (this_arg)
|
||||
{
|
||||
if (log)
|
||||
|
|
|
@ -34,7 +34,8 @@ public:
|
|||
lldb::addr_t functionAddress,
|
||||
lldb::addr_t returnAddress,
|
||||
lldb::addr_t arg,
|
||||
lldb::addr_t *this_arg) const;
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) const;
|
||||
|
||||
virtual bool
|
||||
PrepareNormalCall (Thread &thread,
|
||||
|
|
|
@ -928,6 +928,20 @@ ClangASTType::DumpTypeDescription (clang::ASTContext *ast_context, clang_type_t
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClangASTType::DumpTypeCode (Stream *s)
|
||||
{
|
||||
DumpTypeCode(m_type, s);
|
||||
}
|
||||
|
||||
void
|
||||
ClangASTType::DumpTypeCode (void *type,
|
||||
Stream *s)
|
||||
{
|
||||
clang::QualType qual_type(clang::QualType::getFromOpaquePtr(type));
|
||||
s->PutCString(qual_type.getAsString().c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTType::GetValueAsScalar
|
||||
(
|
||||
|
|
|
@ -40,7 +40,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
|
|||
lldb::addr_t arg,
|
||||
bool stop_other_threads,
|
||||
bool discard_on_error,
|
||||
lldb::addr_t *this_arg) :
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg) :
|
||||
ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
|
||||
m_valid (false),
|
||||
m_stop_other_threads (stop_other_threads),
|
||||
|
@ -86,7 +87,8 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
|
|||
FunctionLoadAddr,
|
||||
StartLoadAddr,
|
||||
m_arg_addr,
|
||||
this_arg))
|
||||
this_arg,
|
||||
cmd_arg))
|
||||
return;
|
||||
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
|
||||
|
|
|
@ -42,8 +42,9 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread,
|
|||
bool stop_other_threads,
|
||||
bool discard_on_error,
|
||||
lldb::addr_t *this_arg,
|
||||
lldb::addr_t *cmd_arg,
|
||||
ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
|
||||
ThreadPlanCallFunction (thread, function, arg, stop_other_threads, discard_on_error, this_arg),
|
||||
ThreadPlanCallFunction (thread, function, arg, stop_other_threads, discard_on_error, this_arg, cmd_arg),
|
||||
m_user_expression_sp (user_expression_sp)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue