Skip to content

Clang added a new feature to the ObjC compiler that will translate me… #652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/ThreadPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,12 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
virtual void WillPop();

// This pushes a plan onto the plan stack of the current plan's thread.
// Also sets the plans to private and not master plans. A plan pushed by
// another thread plan is never either of the above.
void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) {
m_thread.PushPlan(thread_plan_sp);
thread_plan_sp->SetPrivate(false);
thread_plan_sp->SetIsMasterPlan(false);
}

ThreadPlanKind GetKind() const { return m_kind; }
Expand Down
6 changes: 6 additions & 0 deletions lldb/include/lldb/Target/ThreadPlanStepInRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ class ThreadPlanStepInRange : public ThreadPlanStepRange,

bool IsVirtualStep() override;

// Plans that are implementing parts of a step in might need to follow the
// behavior of this plan w.r.t. StepThrough. They can get that from here.
static uint32_t GetDefaultFlagsValue() {
return s_default_flag_values;
}

protected:
static bool DefaultShouldStopHereCallback(ThreadPlan *current_plan,
Flags &flags,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OBJC_SOURCES := stepping-tests.m
LD_EXTRAS := -lobjc -framework Foundation

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Test stepping through ObjC method dispatch in various forms."""

from __future__ import print_function


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestObjCDirectDispatchStepping(TestBase):

mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line numbers that we will step to in main:
self.main_source = lldb.SBFileSpec("stepping-tests.m")

@skipUnlessDarwin
@add_test_categories(['pyapi', 'basic_process'])
def test_with_python_api(self):
"""Test stepping through the 'direct dispatch' optimized method calls."""
self.build()

(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
"Stop here to start stepping",
self.main_source)
stop_bkpt = target.BreakpointCreateBySourceRegex("// Stop Location [0-9]+", self.main_source)
self.assertEqual(stop_bkpt.GetNumLocations(), 15)

# Here we step through all the overridden methods of OverridesALot
# The last continue will get us to the call ot OverridesInit.
for idx in range(2,16):
thread.StepInto()
func_name = thread.GetFrameAtIndex(0).GetFunctionName()
self.assertTrue("OverridesALot" in func_name, "%d'th step did not match name: %s"%(idx, func_name))
stop_threads = lldbutil.continue_to_breakpoint(process, stop_bkpt)
self.assertEqual(len(stop_threads), 1)
self.assertEqual(stop_threads[0], thread)

thread.StepInto()
func_name = thread.GetFrameAtIndex(0).GetFunctionName()
self.assertEqual(func_name, "-[OverridesInit init]", "Stopped in [OverridesInit init]")



Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#import <Foundation/Foundation.h>

@interface OverridesALot: NSObject

- (void)boring;

@end

@implementation OverridesALot

+ (id)alloc {
NSLog(@"alloc");
return [super alloc];
}

+ (id)allocWithZone: (NSZone *)z {
NSLog(@"allocWithZone:");
return [super allocWithZone: z];
}

+ (id)new {
NSLog(@"new");
return [super new];
}

- (id)init {
NSLog(@"init");
return [super init];
}

- (id)self {
NSLog(@"self");
return [super self];
}

+ (id)class {
NSLog(@"class");
return [super class];
}

- (BOOL)isKindOfClass: (Class)c {
NSLog(@"isKindOfClass:");
return [super isKindOfClass: c];
}

- (BOOL)respondsToSelector: (SEL)s {
NSLog(@"respondsToSelector:");
return [super respondsToSelector: s];
}

- (id)retain {
NSLog(@"retain");
return [super retain];
}

- (oneway void)release {
NSLog(@"release");
[super release];
}

- (id)autorelease {
NSLog(@"autorelease");
return [super autorelease];
}

- (void)boring {
NSLog(@"boring");
}

@end

@interface OverridesInit: NSObject

- (void)boring;

@end

@implementation OverridesInit

- (id)init {
NSLog(@"init");
return [super init];
}

@end

int main() {
id obj;

// First make an object of the class that overrides everything,
// and make sure we step into all the methods:

obj = [OverridesALot alloc]; // Stop here to start stepping
[obj release]; // Stop Location 2

obj = [OverridesALot allocWithZone: NULL]; // Stop Location 3
[obj release]; // Stop Location 4

obj = [OverridesALot new]; // Stop Location 5
[obj release]; // Stop Location 6

obj = [[OverridesALot alloc] init]; // Stop Location 7
[obj self]; // Stop Location 8
[obj isKindOfClass: [OverridesALot class]]; // Stop Location 9
[obj respondsToSelector: @selector(hello)]; // Stop Location 10
[obj retain]; // Stop Location 11
[obj autorelease]; // Stop Location 12
[obj boring]; // Stop Location 13
[obj release]; // Stop Location 14

// Now try a class that only overrides init but not alloc, to make
// sure we get into the second method in a combined call:

obj = [[OverridesInit alloc] init]; // Stop Location 15

return 0; // Stop Location 15
}
Loading