How can I automate setting a breakpoint on all methods in an Objective C class using lldb?
This is useful for learning the behavior of a complicated legacy class. I am using Xcode (includes lldb) for iOS development, and it is cumbersome to manually go through the (large) file in Xcode and click the gutter next to each method to set breakpoints.
One option is to use regex breakpoints.
breakpoint set -r '\[ClassName .*\]$'
You can play around with the regexp to suit your needs.
The command will create a breakpoint that stops on all methods implemented by that class. However, there will be no breakpoints on methods inherited from superclasses.
To get methods on the superclass, you'll have to use a conditional breakpoint. For example, if the superclass is UIViewController, you could do something like:
br s -r '\[UIViewController .*\]$' -c '(BOOL)[(id)$arg1 isKindOfClass:[CustomVC class]]'
For x86 change (id)$arg1 to *(id*)($ebp+8).
Finally, if you really want to learn about the control flow through various classes, check out dtrace. It's probably more suited to this than a debugger.
br se -f FooViewController.m -p '^#property|^ *- *\('
"br se" is short for "breakpoint set", pass your own filename to the -f argument, and the -p argument is a crude regex for properties and methods in Objective C.
Caveats: This doesn't seem to work for .h files, so if you have properties declared in the header that you want to watch then you may need to set watchpoints on their backing instance variables.
This is the best solution I have found so far, please post alternative solutions if you think they will be helpful.
Related
I have a well advanced project in Swift on Xcode. After a while I decided to add a custom property (to catch a UIColor) to UIButton Class by subclassing it. But I already have a whole bunch of buttons in my Interface Builder set and programmatically in my project itself.
Is there a clean way to change each instances of my old UIButton Class, in IB and in the project files, to my new one at once without messing everything ? Hope I have been clear... ;) Thanks a lot
I would do this outside of Xcode with the help of some shell scripting.
First, do a backup.
Then something like:
for f in `find . -name \*.storyboard -o -name \*.xib` ; do
cp $f $f.orig
sed 's/<button/<button customClass="MyButton" customModule="MyModule" customModuleProvider="target"/g' $f.orig > $f
done
Check if everything still works in Xcode (if not, you still have a backup in the .orig files)
Lastly you might also want to change some classes in your Code from UIButton to MyButton, but this cannot be automated since your code might reference some framework classes that sill will remain UIButtons.
Actually not pretty clear but note that if you looking for clean way to effect for all instances is using Type properties like static and class will be good idea
I'm looking for a way to cause the XCode debugger to break programmatically from Swift code if my iOS program is running in the debugger. This would be similar to the way System.Diagnostics.Debugger.Break() works in the Visual Studio environment. Is this possible? The point would be for any developer that hits a particular section of code to break, but not to have a fatal error that causes code execution to stop permanently.
Edit: This is a little different than the user asking to "enable" a breakpoint (though the answer provided in that question is really what I was looking for). I'm also still looking for something that can be done in Swift without interop, bridging headers, and such.
For Swift, raise(SIGINT) works for me.
I have this function:
func fail(desc: String) {
#if DEBUG
print("assertFail:\(desc)")
raise(SIGINT)
#endif
}
For DEBUG macro setup see here: In absence of preprocessor macros, is there a way to define practical scheme specific flags at project level in Xcode project
Putting asm("svc 0") in your code will stop your running application if debugging through xcode. See: https://stackoverflow.com/a/34078247/215400
I'm not 100% positive there isn't a built in one - but you can create what you want yourself using Symbolic Breakpoints in the XCode UI.
1) Create a new class to represent your Debugger Break.
#interface MYDebuggerBreak : NSObject
+(void)fireUpDebugger;
#end
#implementation MyDebuggerBreak
+(void)fireUpDebugger {
// Do Nothing
}
#end
2) Add a Symbolic Breakpoint to a method on that Class
[MYDebuggerBreak fireUpDebugger]
This is a bit roundabout, you could also put a breakpoint directly into the line "fireUpDebugger" since you control the code. Symbolic Breakpoints are more useful if you want to stop on a method call for something you don't control.
I'm using CocoaLumberjack (https://github.com/CocoaLumberjack/CocoaLumberjack) in my application.
It has a couple of different log macros that I use for example:
DDLogInfo
DDLogVerbose
DDLogWarn
DDLogError
These are defined as macros. I want to create a symbolic breakpoint that will break on all DDLogError. How do I do that?
In short, you don't. Macros are precompiler directives. By the time your program is compiled and running, macros are gone.
Symbolic breakpoints break on specific instance methods and function calls.
The best you might be able to do is to create a dummy method and edit the definition of your DDLogError macro to call that method. Then you could set a breakpoint (symbolic or actual) on that method.
lldb has a "source regular expression breakpoint" that might help out with this. It will search the text of your source files for some pattern and if the pattern matches set a breakpoint on that source line. You say:
(lldb) break set -p "DDLog"
It isn't as convenient for you maybe, because with no arguments it just looks in the current source file, and you can specify any number of files like:
(lldb) break set -p "DDLog" -f foo.c -f bar.c
but there's no way currently to say "all source files" so you might get tired typing all your files in. But if you only need to set these macro breakpoint in a few files, this might come in handy.
Here is a quotation from the other post:
I'm working in a iOS project that includes a static library created by another company. The library include an old version of AFNeworking and I don't have any source files.
Now i need to use a more recent (and less bugged) version of afneworking, but i cannot include the same class twice in the project (of course) because all the "duplicate symbols"
My problem is that I'm preparing an iOS framework and I want to avoid this kind of situation in the future. I'm not talking about AFNetworking, but other quite popular iOS framework. In addition I applied some custom changes in the original framework code.
The one way to avoid "duplicate symbols" and "Class X is implemented in both Y and Z. One of the two will be used" that comes to my mind is to add some prefix to the original framework classes, but is this the right solution?
UPDATE 1:
I tried to apply John's solution but no joy. I have created a simplified project (here is the link to the repo) with two classes FrameworkClass which is present in framework target only, and SharedClass which is present in both framework and application targets, so maybe you can see if I'm doing something wrong. After application did launch I'm still getting:
objc[96426]: Class SharedClass is implemented in both .../TestFramework.framework/TestFramework and .../SymbolsVisibilityTest.app/SymbolsVisibilityTest. One of the two will be used. Which one is undefined
UPDATE 2:
Here is my output from nm based on the provided sample project's framework-output:
0000000000007e14 t -[FrameworkClass doFramework]
0000000000007e68 t -[SharedClass doShared]
U _NSLog
U _NSStringFromSelector
00000000000081f0 s _OBJC_CLASS_$_FrameworkClass
U _OBJC_CLASS_$_NSObject
0000000000008240 s _OBJC_CLASS_$_SharedClass
00000000000081c8 s _OBJC_METACLASS_$_FrameworkClass
U _OBJC_METACLASS_$_NSObject
0000000000008218 s _OBJC_METACLASS_$_SharedClass
0000000000007fb0 s _TestFrameworkVersionNumber
0000000000007f70 s _TestFrameworkVersionString
U ___CFConstantStringClassReference
U __objc_empty_cache
U _objc_release
U _objc_retainAutoreleasedReturnValue
U dyld_stub_binder`
UPDATE 3:
I did manage to "hide" SharedClass symbols by applying the solution by #bleater and my output from nm is now:
U _NSLog
U _NSStringFromSelector
00001114 S _OBJC_CLASS_$_FrameworkClass
U _OBJC_CLASS_$_NSObject
00001100 S _OBJC_METACLASS_$_FrameworkClass
U _OBJC_METACLASS_$_NSObject
U ___CFConstantStringClassReference
U __objc_empty_cache
U _objc_release
U _objc_retainAutoreleasedReturnValue
U dyld_stub_binder`
But I'm still getting double implementation warning in Xcode.
You should limit the visibility of symbols in any framework or library you are developing. Set the default visibility to hidden, and then explicitly mark all the functions in the public interface as visible.
This avoids all the problems you have described. You can then include any version of any public library (AFNetworking, SQLite, etc.), without fear of future conflict because anything linking to your framework or library won't be able to "see" those symbols.
To set the default visibility to hidden you can go into the project settings and set "Symbols Hidden by Default" to YES. It is set to NO unless you change it.
There are at least a couple of ways to mark the symbols from your public interface as "Visible". One is by using an exports file, another is to go through and explicitly mark certain functions as visible:
#define EXPORT __attribute__((visibility("default")))
EXPORT int MyFunction1();
The define is obviously just for convenience. You define EXPORT once and then just add EXPORT to all of your public symbols.
You can find official apple documentation on this here:
Runtime Environment Programming Guide
Update:
I took a look at your sample project, and it looks like I pointed you in the wrong direction. It appears that you can only truly hide C and C++ symbols. So if your were having this problem with a C lib (like sqlite), setting the default visibility to hidden would work. It looks like the nature of the Objective C runtime prevents you from truly making the symbols invisible. You CAN mark the visibility on these symbols, but with Objective-C it appears that is just a way to have the linker enforce what you should or shouldn't be able to use from the library (while still leaving them visible).
So if you redefine a Objective-C symbol in different compilation unit with the same name (by perhaps compiling in a new version of a popular open source library), then you will still have a conflict.
I think your only solution at this point is to do what you first suggested and prefix the symbols you are including into your framework with a unique identifier. It isn't a very elegant solution, but with the limits of the objective C runtime I believe it is probably the best solution available.
So the blog post by Kamil Burczyk was a good starting point, thanks for the hint MichaĆ Ciuba! It has covered most of the symbols, but it didn't cope with categories and class clusters. You can see what category methods are still exposed without any change by invoking nm with parameter list sth like:
nm MyLibrary | grep \( | grep -v "\[LIBRARYPREFIX" | grep -v \(MyLibrary | grep -v ") prefix_"
When it comes to categories we have 3 groups of categories, and they all require a specific, different approach:
Categories on classes that has been renamed by NamespacedDependencies.h
Categories on classes not renamed by NamespacedDependencies.h
Categories on class clusters like NSString, NSArray...
Ad 1.
Everything is ok - class name will be prefixed so category will exist on prefixed sumbol in object file
Ad 2.
This problem occours whenever inside of the dependency we have category on a class like NSObject. It would be exposed without any change in object file, thus would cause a conflict. My approach was to internally rename NSObject to PREFIX_NSObject, this ofcourse requires me also to create and add the PREFIX_NSObject class implementation to the project (empty implementation, just a subclass of original NSObject)
#import "PREFIX_NSObject.h"
#ifndef NSValueTransformer
#define NSValueTransformer __NS_SYMBOL(NSObject)
#endif
Ad 3.
We cannot apply Ad 2. approach here. Actual objects created by let's say PREFIX_NSArray class methods are still of type that wont derive from my presumable PREFIX_NSArray class, so this doesn't make sense as category methods defined on PREFIX_NSArray won't be visible on NSArray derived objects. I ended up by manually prefixing methods of those categories in source code.
It's kind of crazy workflow, but at least gives warranty that everything will be 'invisible' and won't cause a conflict.
It's always good idea to run nm to check if all category symbols are hidden:
nm MyLibrary | grep \( | grep -v "\[LIBRARYPREFIX" | grep -v \(MyLibrary | grep -v ") prefix_"
I finished writing a class' .h and .m files in objective c in XCode and want to see if all the class functions are implemented correctly. I have not set up anything in the storyboard file yet but would like to test and debug the code. I'm looking to simply declare an object of the class type and to run some of the functions on it similar to using the command line with Python.
If there's no way to simply debug code using command line commands, what would be the easiest way to set up the storyboard?
You can use the XCTest to test your classes.
You can find all the information you need in the Apple documentation is actually pretty easy to use.
https://developer.apple.com/Library/ios/documentation/DeveloperTools/Conceptual/testing_with_xcode/testing_2_testing_basics/testing_2_testing_basics.html#//apple_ref/doc/uid/TP40014132-CH3-SW1
If you want you can check this tutorial as well.
http://rshankar.com/test-driven-development-in-ios-beginners-tutorial-part-1/
If you want you can set break points as well and check that your code is executing properly. Sometimes when I just want to proof-test small classes I do it just setting a couple of break points instead of the XCTest classes but it all depends on your study case. If you have a decent amount of classes I would suggest to use XCTest to check that the classes are actually doing what is expected setting your assertions and the other conditions that XCTest offers as a framework.
Another way you can do your testing if applicable is using NSLog to print in console lines or values of interest at each stage of your code execution.
You mentioned the command line. If you set breakpoints you can use po objName to print the value or print varName to check values of objects and primitive variables correspondingly. po stands for print object and print well... There's different options if you feel comfortable using the console just set NSLogs at certain point of your code or set the break points and print the values using po or print commands in the console.
Here you can check the string format specifiers for NSLog which are the same ones used for NSString
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Strings/Articles/formatSpecifiers.html