[lldb] Add support for calling objc_direct methods from LLDB's expression evaluator.

Summary:
D69991 introduced `__attribute__((objc_direct))` that allows directly calling methods without message passing.
This patch adds support for calling methods with this attribute to LLDB's expression evaluator.

The patch can be summarised in that LLDB just adds the same attribute to our module AST when we find a
method with `__attribute__((objc_direct))` in our debug information.

Reviewers: aprantl, shafik

Reviewed By: shafik

Subscribers: JDevlieghere, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D71196
This commit is contained in:
Raphael Isemann 2019-12-17 09:48:54 +01:00
parent 531c1161b9
commit d5b54bbfaf
7 changed files with 109 additions and 3 deletions

View File

@ -845,7 +845,7 @@ public:
// (lldb::opaque_compiler_type_t type, "-[NString
// stringWithCString:]")
const CompilerType &method_compiler_type, lldb::AccessType access,
bool is_artificial, bool is_variadic);
bool is_artificial, bool is_variadic, bool is_objc_direct_call);
static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type,
bool has_extern);

View File

@ -0,0 +1,4 @@
OBJC_SOURCES := main.m
LD_EXTRAS := -lobjc -framework Foundation
include Makefile.rules

View File

@ -0,0 +1,5 @@
from lldbsuite.test import lldbinline
from lldbsuite.test import decorators
lldbinline.MakeInlineTest(
__file__, globals(), [decorators.skipUnlessDarwin])

View File

@ -0,0 +1,79 @@
#import <Foundation/Foundation.h>
int side_effect = 0;
NSString *str = @"some string";
const char *directCallConflictingName() {
return "wrong function";
}
@interface Foo : NSObject {
int instance_var;
}
-(int) entryPoint;
@end
@implementation Foo
-(int) entryPoint
{
// Try calling directly with self. Same as in the main method otherwise.
return 0; //%self.expect("expr [self directCallNoArgs]", substrs=["called directCallNoArgs"])
//%self.expect("expr [self directCallArgs: 1111]", substrs=["= 2345"])
//%self.expect("expr side_effect = 0; [self directCallVoidReturn]; side_effect", substrs=["= 4321"])
//%self.expect("expr [self directCallNSStringArg: str]", substrs=['@"some string"'])
//%self.expect("expr [self directCallIdArg: (id)str]", substrs=['@"some string appendix"'])
//%self.expect("expr [self directCallConflictingName]", substrs=["correct function"])
}
// Declare several objc_direct functions we can test.
-(const char *) directCallNoArgs __attribute__((objc_direct))
{
return "called directCallNoArgs";
}
-(void) directCallVoidReturn __attribute__((objc_direct))
{
side_effect = 4321;
}
-(int) directCallArgs:(int)i __attribute__((objc_direct))
{
// Use the arg in some way to make sure that gets passed correctly.
return i + 1234;
}
-(NSString *) directCallNSStringArg:(NSString *)str __attribute__((objc_direct))
{
return str;
}
-(NSString *) directCallIdArg:(id)param __attribute__((objc_direct))
{
return [param stringByAppendingString:@" appendix"];
}
// We have another function with the same name above. Make sure this doesn't influence
// what we call.
-(const char *) directCallConflictingName __attribute__((objc_direct))
{
return "correct function";
}
@end
int main()
{
Foo *foo = [[Foo alloc] init];
[foo directCallNoArgs];
[foo directCallArgs: 1];
[foo directCallVoidReturn];
[foo directCallNSStringArg: str];
[foo directCallIdArg: (id)str];
[foo entryPoint]; //%self.expect("expr [foo directCallNoArgs]", substrs=["called directCallNoArgs"])
//%self.expect("expr [foo directCallArgs: 1111]", substrs=["= 2345"])
//%self.expect("expr side_effect = 0; [foo directCallVoidReturn]; side_effect", substrs=["= 4321"])
//%self.expect("expr [foo directCallNSStringArg: str]", substrs=['@"some string"'])
//%self.expect("expr [foo directCallIdArg: (id)str]", substrs=['@"some string appendix"'])
//%self.expect("expr [foo directCallConflictingName]", substrs=["correct function"])
return 0;
}

View File

@ -390,6 +390,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
is_complete_objc_class = form_value.Signed();
break;
case DW_AT_APPLE_objc_direct:
is_objc_direct_call = true;
break;
case DW_AT_APPLE_runtime_class:
class_language = (LanguageType)form_value.Signed();
break;
@ -958,7 +962,8 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
clang::ObjCMethodDecl *objc_method_decl =
m_ast.AddMethodToObjCObjectType(
class_opaque_type, attrs.name.GetCString(), clang_type,
attrs.accessibility, attrs.is_artificial, is_variadic);
attrs.accessibility, attrs.is_artificial, is_variadic,
attrs.is_objc_direct_call);
type_handled = objc_method_decl != NULL;
if (type_handled) {
LinkDeclContextToDIE(objc_method_decl, die);

View File

@ -244,6 +244,7 @@ struct ParsedDWARFTypeAttributes {
bool is_scoped_enum = false;
bool is_vector = false;
bool is_virtual = false;
bool is_objc_direct_call = false;
bool exports_symbols = false;
clang::StorageClass storage = clang::SC_None;
const char *mangled_name = nullptr;

View File

@ -7769,7 +7769,7 @@ clang::ObjCMethodDecl *ClangASTContext::AddMethodToObjCObjectType(
// (lldb::opaque_compiler_type_t type, "-[NString
// stringWithCString:]")
const CompilerType &method_clang_type, lldb::AccessType access,
bool is_artificial, bool is_variadic) {
bool is_artificial, bool is_variadic, bool is_objc_direct_call) {
if (!type || !method_clang_type.IsValid())
return nullptr;
@ -7875,6 +7875,18 @@ clang::ObjCMethodDecl *ClangASTContext::AddMethodToObjCObjectType(
llvm::ArrayRef<clang::SourceLocation>());
}
if (is_objc_direct_call) {
// Add a the objc_direct attribute to the declaration we generate that
// we generate a direct method call for this ObjCMethodDecl.
objc_method_decl->addAttr(
clang::ObjCDirectAttr::CreateImplicit(*ast, SourceLocation()));
// Usually Sema is creating implicit parameters (e.g., self) when it
// parses the method. We don't have a parsing Sema when we build our own
// AST here so we manually need to create these implicit parameters to
// make the direct call code generation happy.
objc_method_decl->createImplicitParams(*ast, class_interface_decl);
}
class_interface_decl->addDecl(objc_method_decl);
#ifdef LLDB_CONFIGURATION_DEBUG