From 167685c9d7d76bf463ede95fb83b3abefc38301a Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Wed, 11 Sep 2019 00:32:58 -0400 Subject: [PATCH] Add support for function return breakpoints. --- English.lproj/Breakpoints.xib | 11 ++++++++--- Source/Breakpoint.h | 3 ++- Source/Breakpoint.m | 18 +++++++++++++----- Source/BreakpointController.m | 21 +++++++++++++++++---- Source/DebuggerBackEnd.m | 7 +++++-- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/English.lproj/Breakpoints.xib b/English.lproj/Breakpoints.xib index 1e1ae20..667ab43 100644 --- a/English.lproj/Breakpoints.xib +++ b/English.lproj/Breakpoints.xib @@ -89,7 +89,7 @@ - + @@ -100,17 +100,22 @@ - + - + + + + + + diff --git a/Source/Breakpoint.h b/Source/Breakpoint.h index faa4df8..e79823c 100644 --- a/Source/Breakpoint.h +++ b/Source/Breakpoint.h @@ -18,6 +18,7 @@ extern NSString* const kBreakpointTypeFile; extern NSString* const kBreakpointTypeFunctionEntry; +extern NSString* const kBreakpointTypeFunctionReturn; // This represents a breakpoint at a certain file and line number. It also // maintains the identifier that the backend assigns to the breakpoint. @@ -40,7 +41,7 @@ extern NSString* const kBreakpointTypeFunctionEntry; @property (readonly) NSString* functionName; + (instancetype)breakpointAtLine:(unsigned long)line inFile:(NSString*)file; -+ (instancetype)breakpointOnFunctionNamed:(NSString*)name; ++ (instancetype)breakpointOnFunctionNamed:(NSString*)name type:(NSString*)type; // Initializer from NSUserDefaults. - (instancetype)initWithDictionary:(NSDictionary*)dict; diff --git a/Source/Breakpoint.m b/Source/Breakpoint.m index 7a7b55e..b8eb658 100644 --- a/Source/Breakpoint.m +++ b/Source/Breakpoint.m @@ -20,6 +20,7 @@ NSString* const kBreakpointTypeFile = @"line"; NSString* const kBreakpointTypeFunctionEntry = @"call"; +NSString* const kBreakpointTypeFunctionReturn = @"return"; @implementation Breakpoint { NSString* _type; // weak @@ -39,10 +40,11 @@ NSString* const kBreakpointTypeFunctionEntry = @"call"; return breakpoint; } -+ (instancetype)breakpointOnFunctionNamed:(NSString*)name ++ (instancetype)breakpointOnFunctionNamed:(NSString*)name type:(NSString*)type { Breakpoint* breakpoint = [[[Breakpoint alloc] init] autorelease]; - breakpoint->_type = kBreakpointTypeFunctionEntry; + NSAssert1(type == kBreakpointTypeFunctionEntry || type == kBreakpointTypeFunctionReturn, @"Unexpected breakpoint type: %@", type); + breakpoint->_type = type; breakpoint->_functionName = [name copy]; return breakpoint; } @@ -58,6 +60,9 @@ NSString* const kBreakpointTypeFunctionEntry = @"call"; } else if ([type isEqualToString:kBreakpointTypeFunctionEntry]) { _type = kBreakpointTypeFunctionEntry; _functionName = [[dict valueForKey:@"function"] copy]; + } else if ([type isEqualToString:kBreakpointTypeFunctionReturn]) { + _type = kBreakpointTypeFunctionReturn; + _functionName = [[dict valueForKey:@"function"] copy]; } else { [NSException raise:NSInvalidArgumentException format:@"Unknown Breakpoint type: %@", type]; @@ -80,7 +85,8 @@ NSString* const kBreakpointTypeFunctionEntry = @"call"; { if (self.type == kBreakpointTypeFile) { return [NSString stringWithFormat:@"%@:%ld", self.file, self.line]; - } else if (self.type == kBreakpointTypeFunctionEntry) { + } else if (self.type == kBreakpointTypeFunctionEntry || + self.type == kBreakpointTypeFunctionReturn) { return [NSString stringWithFormat:@"%@()", self.functionName]; } return nil; @@ -121,7 +127,8 @@ NSString* const kBreakpointTypeFunctionEntry = @"call"; if (self.type == kBreakpointTypeFile) { return [self.file isEqualToString:other.file] && self.line == other.line; - } else if (self.type == kBreakpointTypeFunctionEntry) { + } else if (self.type == kBreakpointTypeFunctionEntry || + self.type == kBreakpointTypeFunctionReturn) { return [self.functionName isEqualToString:other.functionName]; } @@ -136,7 +143,8 @@ NSString* const kBreakpointTypeFunctionEntry = @"call"; @"file" : self.file, @"line" : @(self.line) }; - } else if (self.type == kBreakpointTypeFunctionEntry) { + } else if (self.type == kBreakpointTypeFunctionEntry || + self.type == kBreakpointTypeFunctionReturn) { return @{ @"type" : self.type, @"function" : self.functionName diff --git a/Source/BreakpointController.m b/Source/BreakpointController.m index 99f495d..dcce535 100644 --- a/Source/BreakpointController.m +++ b/Source/BreakpointController.m @@ -64,18 +64,31 @@ - (IBAction)addFunctionBreakpoint:(id)sender { - [self.view.window beginSheet:self.addFunctionBreakpointWindow completionHandler:nil]; + NSUInteger tag = [sender tag]; + NSString* type; + if (tag == 'e') { + type = kBreakpointTypeFunctionEntry; + } else if (tag == 'r') { + type = kBreakpointTypeFunctionReturn; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Unexpected breakpoint type from tag %ld sender %@", tag, sender]; + } + [self.view.window beginSheet:self.addFunctionBreakpointWindow completionHandler:^(NSModalResponse returnCode) { + if (returnCode == NSModalResponseOK) { + [_manager addBreakpoint:[Breakpoint breakpointOnFunctionNamed:self.functionNameField.stringValue type:type]]; + } + }]; } - (IBAction)cancelFunctionBreakpoint:(id)sender { - [self.view.window endSheet:self.addFunctionBreakpointWindow]; + [self.view.window endSheet:self.addFunctionBreakpointWindow returnCode:NSModalResponseCancel]; } - (IBAction)saveFunctionBreakpoint:(id)sender { - [_manager addBreakpoint:[Breakpoint breakpointOnFunctionNamed:self.functionNameField.stringValue]]; - [self.view.window endSheet:self.addFunctionBreakpointWindow]; + [self.view.window endSheet:self.addFunctionBreakpointWindow returnCode:NSModalResponseOK]; } /** diff --git a/Source/DebuggerBackEnd.m b/Source/DebuggerBackEnd.m index ba51977..005fc49 100644 --- a/Source/DebuggerBackEnd.m +++ b/Source/DebuggerBackEnd.m @@ -207,8 +207,11 @@ if (bp.type == kBreakpointTypeFile) { NSString* file = [ProtocolClient escapedFilePathURI:[bp transformedPath]]; [_client sendCommandWithFormat:@"breakpoint_set -t line -f %@ -n %i" handler:handler, file, [bp line]]; - } else if (bp.type == kBreakpointTypeFunctionEntry) { - [_client sendCommandWithFormat:@"breakpoint_set -t call -m %@" handler:handler, bp.functionName]; + } else if (bp.type == kBreakpointTypeFunctionEntry || + bp.type == kBreakpointTypeFunctionReturn) { + [_client sendCommandWithFormat:@"breakpoint_set -t %@ -m %@" handler:handler, bp.type, bp.functionName]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Unknown breakpoint type %@", bp.type]; } } -- 2.22.5