├── locus ├── .DS_Store ├── LocusDemo │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── LCUSViewController.h │ ├── LCUSTableView.h │ ├── AppDelegate.h │ ├── LCUSTableViewCell.h │ ├── main.m │ ├── LCUSTableView.m │ ├── LCUSTableViewCell.m │ ├── Info.plist │ ├── LCUSViewController.m │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ └── AppDelegate.m ├── locus.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── locus.xcscheme │ └── project.pbxproj ├── locus │ ├── LocusArgPrinter.h │ ├── LocusRes.h │ ├── LocusView.h │ ├── LocusSettingViewController.h │ ├── Locus.h │ ├── locusImpl.h │ ├── Locus+Config.h │ ├── Locus+Config.m │ ├── LocusArgPrinter.m │ ├── fishhook.h │ ├── LocusView.m │ ├── LocusSettingViewController.m │ ├── Locus.m │ ├── LocusRes.m │ ├── locusImpl.c │ └── fishhook.c └── locus copy-Info.plist ├── locus.podspec ├── LICENSE ├── README.md └── .gitignore /locus/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzfanfei/locus/HEAD/locus/.DS_Store -------------------------------------------------------------------------------- /locus/LocusDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /locus/locus.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /locus/locus/LocusArgPrinter.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocusArgPrinter.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/27. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | void printArgs(char *class_name, char* sel, va_list argp); 9 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSViewController.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LCUSViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /locus/locus.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /locus/locus/LocusRes.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocusRes.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/28. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSString* LocusIconRecordStart; 12 | extern NSString* LocusIconRecordEnd; 13 | extern NSString* LocusIconSetting; 14 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSTableView.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface LCUSTableView : UITableView 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /locus/LocusDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /locus/locus/LocusView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocusView.h 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface LocusView : UIView 14 | 15 | - (instancetype)initWithFrame:(CGRect)frame; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /locus/locus/LocusSettingViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocusSettingViewController.h 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface LocusSettingViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSTableViewCell.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface LCUSTableViewCell : UITableViewCell 14 | 15 | - (void)decorate; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /locus/LocusDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSTableView.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LCUSTableView.h" 10 | 11 | @implementation LCUSTableView 12 | 13 | /* 14 | // Only override drawRect: if you perform custom drawing. 15 | // An empty implementation adversely affects performance during animation. 16 | - (void)drawRect:(CGRect)rect { 17 | // Drawing code 18 | } 19 | */ 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /locus/locus/Locus.h: -------------------------------------------------------------------------------- 1 | // 2 | // Locus.h 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/26. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import 10 | #include "locusImpl.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface Locus : NSObject 15 | 16 | + (void)start; 17 | 18 | + (void)stopPrint; 19 | 20 | + (void)resumePrint; 21 | 22 | + (void)showUI; 23 | 24 | + (void)hideUI; 25 | 26 | // performance start 27 | + (void)startTestPerformance:(long)ms; 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /locus/locus/locusImpl.h: -------------------------------------------------------------------------------- 1 | // 2 | // hookObjcSend.h 3 | // fishhookdemo 4 | // 5 | // Created by FanFamily on 2018/7/21. 6 | // Copyright © 2018年 Family Fan. All rights reserved. 7 | // 8 | 9 | #ifndef hookObjcSend_h 10 | #define hookObjcSend_h 11 | 12 | typedef int(^LCSFilterBlock)(char* className, char* selName); 13 | 14 | void lcs_start(LCSFilterBlock block); 15 | void lcs_stop_print(void); 16 | void lcs_resume_print(void); 17 | void lcs_update_filter(LCSFilterBlock filter); 18 | 19 | void lcs_start_performance(long ms, char* log_path); 20 | 21 | #endif /* hookObjcSend_h */ 22 | -------------------------------------------------------------------------------- /locus/locus/Locus+Config.h: -------------------------------------------------------------------------------- 1 | // 2 | // Locus+UserDefaults.h 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import "Locus.h" 10 | 11 | #define LOCUS_PRINT_SYSTEM_CLASS @"print system class" 12 | #define LOCUS_PRINT_CUSTOM_CLASS @"print custom class" 13 | #define LOCUS_PRINT_SUPER_METHODS @"print super methods" 14 | #define LOCUS_PRINT_ARGS @"print args" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | @interface Locus (Config) 19 | 20 | + (NSMutableDictionary *)getConfig; 21 | + (void)setConfig:(NSMutableDictionary *)config; 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSTableViewCell.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LCUSTableViewCell.h" 10 | 11 | @implementation LCUSTableViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | // Initialization code 16 | } 17 | 18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 19 | [super setSelected:selected animated:animated]; 20 | 21 | } 22 | 23 | - (void)decorate 24 | { 25 | int R = (arc4random() % 256) ; 26 | int G = (arc4random() % 256) ; 27 | int B = (arc4random() % 256) ; 28 | 29 | [self.textLabel setTextColor:[UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:0.8]]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /locus/locus/Locus+Config.m: -------------------------------------------------------------------------------- 1 | // 2 | // Locus+UserDefaults.m 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import "Locus+Config.h" 10 | 11 | static NSDictionary* config_cache = nil; 12 | 13 | @implementation Locus (Config) 14 | 15 | + (NSDictionary *)getConfig 16 | { 17 | if (config_cache) { 18 | return [config_cache copy]; 19 | } 20 | 21 | NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:@"locus"]; 22 | config_cache = [defaults objectForKey:@"config"]; 23 | if (config_cache == nil) { 24 | config_cache = @{}; 25 | } 26 | id result = (NSDictionary *)[defaults objectForKey:@"config"]; 27 | return result; 28 | } 29 | 30 | + (void)setConfig:(NSDictionary *)config 31 | { 32 | NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:@"locus"]; 33 | [defaults setObject:config forKey:@"config"]; 34 | config_cache = config; 35 | [defaults synchronize]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /locus.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint locus.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "locus" 12 | s.version = "1.5" 13 | s.summary = "track your code on debug" 14 | s.platform = :ios, "7.0" 15 | 16 | s.description = %{ 17 | track your code on debug 18 | } 19 | 20 | s.homepage = "https://github.com/hzfanfei/locus.git" 21 | s.license = { :type => "MIT", :file => "LICENSE" } 22 | s.author = { "fanfei" => "hzfanfei@163.com" } 23 | s.source = { :git => "https://github.com/hzfanfei/locus.git", :tag => s.version } 24 | s.source_files = "locus/locus/*.{h,m,c}" 25 | s.public_header_files = "locus/locus/*.h" 26 | s.requires_arc = true 27 | 28 | end 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 fan fei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://images.gitee.com/uploads/images/2019/0105/152220_3c77fcbf_1941860.png "在这里输入图片标题") 2 | 3 | 4 | ![home page](https://images.gitee.com/uploads/images/2019/0101/174701_5bd8e5e2_1941860.png "在这里输入图片标题") 5 | 6 | 当滑动列表的时候,控制会打印LCUS为前缀的所有调用,可以看到滑动的过程中究竟调用了哪些方法 7 | 8 | When the list is swiped, the control prints all calls that are prefixed by LCUS, and you can see which methods were called during the sliding process. 9 | 10 | ![console](https://images.gitee.com/uploads/images/2019/0101/174841_4d296b8d_1941860.png "在这里输入图片标题") 11 | 12 | #### 介绍 13 | objective-c行为记录器,跟踪objc_msgSend 14 | 15 | Objective-c behavior recorder, tracking objc_msgSend 16 | 17 | #### 使用说明 18 | 19 | * 模拟器使用, 勾选hook_objc_msgSend_x86.s参与编译 (Use by the simulator, check hook_objc_msgSend_x86.s to compile) 20 | * 真机使用5s以上机型,勾选hook_objc_msgSend.s参与编译 (Real machine use 5s or more models, check hook_objc_msgSend.s to compile) 21 | 22 | 23 | #### 注意事项 24 | 25 | * 过滤器LCSFilterBlock中不能再次调用objc_send, 也就是调用oc方法(包括NSLog),会导致无限循环。( 26 | The objc_send cannot be called again in the filter LCSFilterBlock, that is, calling the oc method (including NSLog) will result in an infinite loop.) 27 | * 目前此实现目的仅用于调试,不要用于线上代码。( 28 | Currently this implementation is only for debugging purposes, not for online code.) 29 | #### 大家使用有问题,欢迎提issues (There is a problem with everyone, welcome to mention issues) 30 | -------------------------------------------------------------------------------- /locus/LocusDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /locus/locus copy-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /locus/LocusDemo/LCUSViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCUSViewController.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LCUSViewController.h" 10 | #import "LCUSTableView.h" 11 | #import "LCUSTableViewCell.h" 12 | 13 | static NSString* kLCUSTableViewCellIdentifier = @"kLCUSTableViewCellIdentifier"; 14 | 15 | @interface LCUSViewController () 16 | 17 | @property (nonatomic) LCUSTableView* tableView; 18 | @property (nonatomic) BOOL isShowLocus; 19 | 20 | @end 21 | 22 | @implementation LCUSViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.tableView = [[LCUSTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 28 | self.tableView.delegate = self; 29 | self.tableView.dataSource = self; 30 | [self.tableView registerClass:[LCUSTableViewCell class] forCellReuseIdentifier:kLCUSTableViewCellIdentifier]; 31 | [self.view addSubview:self.tableView]; 32 | } 33 | 34 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 35 | { 36 | return 25; 37 | } 38 | 39 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 40 | { 41 | return 100; 42 | } 43 | 44 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 45 | { 46 | LCUSTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kLCUSTableViewCellIdentifier forIndexPath:indexPath]; 47 | [cell.textLabel setText:[NSString stringWithFormat:@"locus ~~ %ld", indexPath.row + 1]]; 48 | 49 | [cell decorate]; 50 | 51 | return cell; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /locus/LocusDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | *.DS_Store 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | # CocoaPods 33 | # 34 | # We recommend against adding the Pods directory to your .gitignore. However 35 | # you should judge for yourself, the pros and cons are mentioned at: 36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 37 | # 38 | # Pods/ 39 | # 40 | # Add this line if you want to avoid checking in source code from the Xcode workspace 41 | # *.xcworkspace 42 | 43 | # Carthage 44 | # 45 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 46 | # Carthage/Checkouts 47 | 48 | Carthage/Build 49 | 50 | # fastlane 51 | # 52 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 53 | # screenshots whenever they are needed. 54 | # For more information about the recommended setup visit: 55 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 56 | 57 | fastlane/report.xml 58 | fastlane/Preview.html 59 | fastlane/screenshots/**/*.png 60 | fastlane/test_output 61 | 62 | # Code Injection 63 | # 64 | # After new code Injection tools there's a generated folder /iOSInjectionProject 65 | # https://github.com/johnno1962/injectionforxcode 66 | 67 | iOSInjectionProject/ 68 | -------------------------------------------------------------------------------- /locus/LocusDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /locus/LocusDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /locus/LocusDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/1. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @property (nonatomic) id block; 14 | 15 | @end 16 | 17 | @implementation AppDelegate 18 | 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 21 | 22 | return YES; 23 | } 24 | 25 | 26 | - (void)applicationWillResignActive:(UIApplication *)application { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 29 | } 30 | 31 | 32 | - (void)applicationDidEnterBackground:(UIApplication *)application { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | 38 | - (void)applicationWillEnterForeground:(UIApplication *)application { 39 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | 43 | - (void)applicationDidBecomeActive:(UIApplication *)application { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | 48 | - (void)applicationWillTerminate:(UIApplication *)application { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /locus/locus/LocusArgPrinter.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocusArgPrinter.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/27. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | #import 9 | #import "LocusArgPrinter.h" 10 | 11 | char lcs_getTypeFromTypeDescription(const char *typeDescription) 12 | { 13 | char type = typeDescription[0]; 14 | switch (type) { 15 | case 'r': 16 | case 'n': 17 | case 'N': 18 | case 'o': 19 | case 'O': 20 | case 'R': 21 | case 'V': 22 | type = typeDescription[1]; 23 | break; 24 | } 25 | return type; 26 | } 27 | 28 | void printArgs(char *class_name, char* sel, va_list argp) 29 | { 30 | NSString* sClass = [NSString stringWithUTF8String:class_name]; 31 | NSString* sSelector = [NSString stringWithUTF8String:sel]; 32 | Class cls = NSClassFromString(sClass); 33 | SEL selector = NSSelectorFromString(sSelector); 34 | NSMethodSignature *signature = [cls instanceMethodSignatureForSelector:selector]; 35 | if ([signature numberOfArguments] > 2) { 36 | for (NSInteger i = 0; i < [signature numberOfArguments] - 2; i++) { 37 | const char* typeDescription = [signature getArgumentTypeAtIndex:i + 2]; 38 | char type = lcs_getTypeFromTypeDescription(typeDescription); 39 | BOOL isSupport = YES; 40 | switch (type) { 41 | case '@': 42 | { 43 | id obj = va_arg(argp, id); 44 | printf("———— arg%ld: %p\n", i+1, (__bridge void *)obj); 45 | } 46 | break; 47 | case 'B': 48 | printf("———— arg%ld: %d\n", i+1, va_arg(argp, int)); 49 | break; 50 | case 'i': 51 | printf("———— arg%ld: %d\n", i+1, va_arg(argp, int)); 52 | break; 53 | case 'l': 54 | printf("———— arg%ld: %ld\n", i+1, va_arg(argp, long)); 55 | break; 56 | case 'q': 57 | printf("———— arg%ld: %llu\n", i+1, va_arg(argp, long long)); 58 | break; 59 | case 'Q': 60 | printf("———— arg%ld: %llu\n", i+1, va_arg(argp, unsigned long long)); 61 | break; 62 | case 'f': 63 | case 'd': 64 | printf("———— arg%ld: %lf\n", i+1, va_arg(argp, double)); 65 | break; 66 | case ':': 67 | printf("———— arg%ld: %s\n", i+1, va_arg(argp, char *)); 68 | break; 69 | default: 70 | printf("———— arg%ld: %s not support\n", i+1, typeDescription); 71 | isSupport = NO; 72 | break; 73 | } 74 | if (!isSupport) { 75 | break; 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /locus/locus/fishhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #ifndef fishhook_h 25 | #define fishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; 46 | void *replacement; 47 | void **replaced; 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | FISHHOOK_VISIBILITY 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | FISHHOOK_VISIBILITY 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif //fishhook_h 76 | 77 | -------------------------------------------------------------------------------- /locus/locus.xcodeproj/xcshareddata/xcschemes/locus.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /locus/locus/LocusView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocusView.m 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LocusView.h" 10 | #import "Locus.h" 11 | #import "LocusSettingViewController.h" 12 | #import "LocusRes.h" 13 | 14 | @interface LocusView () 15 | 16 | @property (nonatomic) UILabel* titleLabel; 17 | @property (nonatomic) UIButton* closeButton; 18 | @property (nonatomic) UIButton* recordButton; 19 | @property (nonatomic) UIButton* settingButton; 20 | @property (nonatomic) BOOL isRecording; 21 | 22 | @end 23 | 24 | @implementation LocusView 25 | 26 | - (UIImage *)imageWithBase64String:(NSString *)base64 27 | { 28 | NSData* data = [[NSData alloc] initWithBase64EncodedString:base64 options:NSDataBase64DecodingIgnoreUnknownCharacters]; 29 | return [UIImage imageWithData:data]; 30 | } 31 | 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | self = [super initWithFrame:frame]; 36 | if (self) { 37 | 38 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 1, 1)]; 39 | [self.titleLabel setFont:[UIFont systemFontOfSize:8]]; 40 | [self.titleLabel setText:@"Locus"]; 41 | [self.titleLabel sizeToFit]; 42 | 43 | self.closeButton = [[UIButton alloc] initWithFrame:CGRectMake(frame.size.width - 5 - 8, 5, 8, 8)]; 44 | self.closeButton.titleLabel.font = [UIFont systemFontOfSize:8]; 45 | [self.closeButton setTitle:@"x" forState:UIControlStateNormal]; 46 | [self.closeButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 47 | 48 | self.recordButton = [[UIButton alloc] initWithFrame:CGRectMake(5, 5 + 13, 20, 20)]; 49 | [self.recordButton setImage:[self imageWithBase64String:LocusIconRecordStart] forState:UIControlStateNormal]; 50 | self.settingButton = [[UIButton alloc] initWithFrame:CGRectMake(frame.size.width - 5 - (frame.size.width - 15)/2, 5 + 13, 20, 20)]; 51 | [self.settingButton setImage:[self imageWithBase64String:LocusIconSetting] forState:UIControlStateNormal]; 52 | 53 | [self addSubview:self.titleLabel]; 54 | [self addSubview:self.closeButton]; 55 | [self addSubview:self.recordButton]; 56 | [self addSubview:self.settingButton]; 57 | 58 | [self.closeButton addTarget:self action:@selector(close:) forControlEvents:UIControlEventTouchUpInside]; 59 | [self.recordButton addTarget:self action:@selector(record:) forControlEvents:UIControlEventTouchUpInside]; 60 | [self.settingButton addTarget:self action:@selector(setting:) forControlEvents:UIControlEventTouchUpInside]; 61 | } 62 | return self; 63 | } 64 | 65 | - (void)stopPrint 66 | { 67 | [self.recordButton setImage:[self imageWithBase64String:LocusIconRecordStart] forState:UIControlStateNormal]; 68 | [Locus stopPrint]; 69 | self.isRecording = NO; 70 | } 71 | 72 | - (void)resumePrint 73 | { 74 | [self.recordButton setImage:[self imageWithBase64String:LocusIconRecordEnd] forState:UIControlStateNormal]; 75 | [Locus resumePrint]; 76 | self.isRecording = YES; 77 | } 78 | 79 | - (void)record:(id)sender 80 | { 81 | if (self.isRecording) { 82 | [self stopPrint]; 83 | } else { 84 | [self resumePrint]; 85 | } 86 | } 87 | 88 | - (void)setting:(id)sender 89 | { 90 | [self stopPrint]; 91 | UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:[LocusSettingViewController new]]; 92 | [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:navController animated:YES completion:nil]; 93 | } 94 | 95 | - (void)close:(id)sender 96 | { 97 | [self stopPrint]; 98 | [Locus hideUI]; 99 | } 100 | 101 | 102 | 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /locus/locus/LocusSettingViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocusSettingViewController.m 3 | // locus 4 | // 5 | // Created by Family Fan on 2019/1/28. 6 | // Copyright © 2019 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LocusSettingViewController.h" 10 | #import "Locus+Config.h" 11 | 12 | static NSString* kLocusSettingTableViewCellIdentifier = @"kLocusSettingTableViewCellIdentifier"; 13 | 14 | @interface LocusSettingViewController () 15 | 16 | @property (nonatomic) UITableView* tableView; 17 | @property (nonatomic) NSMutableDictionary* switchJson; 18 | @property (nonatomic) NSArray* switchList; 19 | 20 | @end 21 | 22 | @implementation LocusSettingViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.tableView = [[UITableView alloc] initWithFrame:self.view.frame]; 28 | [self.view addSubview:self.tableView]; 29 | self.tableView.backgroundColor = [UIColor whiteColor]; 30 | 31 | self.tableView.delegate = self; 32 | self.tableView.dataSource = self; 33 | 34 | self.switchList = @[LOCUS_PRINT_SYSTEM_CLASS, LOCUS_PRINT_CUSTOM_CLASS, LOCUS_PRINT_SUPER_METHODS, LOCUS_PRINT_ARGS]; 35 | 36 | NSDictionary* switchJson = [Locus getConfig]; 37 | if (switchJson) { 38 | self.switchJson = [switchJson mutableCopy]; 39 | } else { 40 | self.switchJson = [@{LOCUS_PRINT_SYSTEM_CLASS: @NO, LOCUS_PRINT_CUSTOM_CLASS: @YES, LOCUS_PRINT_SUPER_METHODS: @NO, LOCUS_PRINT_ARGS: @YES} mutableCopy]; 41 | } 42 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kLocusSettingTableViewCellIdentifier]; 43 | 44 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(back)]; 45 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Default" style:UIBarButtonItemStyleDone target:self action:@selector(defaultConfig)]; 46 | } 47 | 48 | - (void)back 49 | { 50 | [Locus setConfig:self.switchJson]; 51 | if ([[self.switchJson objectForKey:LOCUS_PRINT_SYSTEM_CLASS] boolValue] || [[self.switchJson objectForKey:LOCUS_PRINT_SUPER_METHODS] boolValue]) { 52 | [self.switchJson setObject:@NO forKey:LOCUS_PRINT_ARGS]; 53 | } 54 | 55 | [self dismissViewControllerAnimated:YES completion:nil]; 56 | } 57 | 58 | - (void)defaultConfig 59 | { 60 | self.switchJson = [@{LOCUS_PRINT_SYSTEM_CLASS: @NO, LOCUS_PRINT_CUSTOM_CLASS: @YES, LOCUS_PRINT_SUPER_METHODS: @NO, LOCUS_PRINT_ARGS: @YES} mutableCopy]; 61 | [self.tableView reloadData]; 62 | } 63 | 64 | #pragma mark UITableViewDelegate 65 | 66 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 67 | { 68 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kLocusSettingTableViewCellIdentifier forIndexPath:indexPath]; 69 | NSString* title = [self.switchList objectAtIndex:indexPath.row]; 70 | if ([[self.switchJson objectForKey:title] boolValue]) { 71 | cell.accessoryType = UITableViewCellAccessoryCheckmark; 72 | } else { 73 | cell.accessoryType = UITableViewCellAccessoryNone; 74 | } 75 | [cell.textLabel setText:[self.switchList objectAtIndex:indexPath.row]]; 76 | return cell; 77 | } 78 | 79 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 80 | { 81 | UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath]; 82 | if (cell.accessoryType == UIAccessibilityTraitNone) { 83 | cell.accessoryType = UITableViewCellAccessoryCheckmark; 84 | [self.switchJson setObject:@YES forKey:cell.textLabel.text]; 85 | } else { 86 | cell.accessoryType = UITableViewCellAccessoryNone; 87 | [self.switchJson setObject:@NO forKey:cell.textLabel.text]; 88 | } 89 | } 90 | 91 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 92 | { 93 | return self.switchList.count; 94 | } 95 | 96 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 97 | { 98 | return 50; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /locus/locus/Locus.m: -------------------------------------------------------------------------------- 1 | // 2 | // Locus.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/26. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "Locus.h" 10 | #import "LocusView.h" 11 | #import "Locus+Config.h" 12 | #import 13 | #import 14 | 15 | static id filerBlockHolder = nil; 16 | 17 | @implementation Locus 18 | 19 | + (NSArray *)getClassNamesFromBundle { 20 | NSMutableArray* classNames = [NSMutableArray array]; 21 | unsigned int count = 0; 22 | const char** classes = objc_copyClassNamesForImage([[[NSBundle mainBundle] executablePath] UTF8String], &count); 23 | for(unsigned int i=0;i 0) { 62 | BOOL system = [[config objectForKey:LOCUS_PRINT_SYSTEM_CLASS] boolValue]; 63 | BOOL custom = [[config objectForKey:LOCUS_PRINT_CUSTOM_CLASS] boolValue]; 64 | BOOL super_methods = [[config objectForKey:LOCUS_PRINT_SUPER_METHODS] boolValue]; 65 | BOOL args = [[config objectForKey:LOCUS_PRINT_ARGS] boolValue]; 66 | 67 | int result = 0; 68 | if (!system && !custom) { 69 | return 0; 70 | } else if (system && custom) { 71 | result = 1; 72 | } else { 73 | if (system) { 74 | result = ![classNames containsObject:sClass]; 75 | } else { 76 | result = [classNames containsObject:sClass]; 77 | } 78 | } 79 | 80 | if (result == 0) { 81 | return 0; 82 | } 83 | 84 | if (!super_methods) { 85 | result = reality(klass, NSSelectorFromString(sSelector)); 86 | if (result == 0) { 87 | return 0; 88 | } 89 | } 90 | 91 | if (args) { 92 | result = 2; 93 | } else { 94 | result = 1; 95 | } 96 | return result; 97 | } else { 98 | if ([classNames containsObject:sClass] 99 | && reality(klass, NSSelectorFromString(sSelector))){ 100 | return 2; 101 | } 102 | return 0; 103 | } 104 | }; 105 | filerBlockHolder = filter; 106 | lcs_start(filerBlockHolder); 107 | } 108 | 109 | + (void)startTestPerformance:(long)ms 110 | { 111 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 112 | NSString *documentsDirectory = [paths objectAtIndex:0]; 113 | NSString *path = [documentsDirectory stringByAppendingPathComponent:@"locus.log"]; 114 | 115 | lcs_start_performance(ms, (char* )path.UTF8String); 116 | } 117 | 118 | + (void)stopPrint 119 | { 120 | lcs_stop_print(); 121 | } 122 | 123 | + (void)resumePrint 124 | { 125 | lcs_resume_print(); 126 | } 127 | 128 | static UIView* _locusView = nil; 129 | static UIPanGestureRecognizer* _gesture = nil; 130 | static double _viewWidth = 55.0; 131 | static double _viewHeight = 43.0; 132 | 133 | + (NSInteger)safeAreaTop 134 | { 135 | NSInteger top = 0; 136 | if (@available(iOS 11.0, *)) { 137 | if ([[UIApplication sharedApplication] keyWindow].safeAreaInsets.top > 0.0) { 138 | top = [[UIApplication sharedApplication] keyWindow].safeAreaInsets.top; 139 | } 140 | } 141 | return top; 142 | } 143 | 144 | + (UIPanGestureRecognizer *)gesture 145 | { 146 | if (!_gesture) { 147 | _gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; 148 | } 149 | 150 | return _gesture; 151 | } 152 | 153 | + (UIView *)windowView 154 | { 155 | return [UIApplication sharedApplication].keyWindow.rootViewController.view; 156 | } 157 | 158 | + (void)handlePanGesture:(UIPanGestureRecognizer *)sender 159 | { 160 | if (sender.state == UIGestureRecognizerStateEnded) { 161 | CGPoint point = [sender translationInView:[self windowView]]; 162 | sender.view.center = CGPointMake(sender.view.center.x + point.x, sender.view.center.y+point.y); 163 | [UIView animateWithDuration:0.3 animations:^{ 164 | CGRect frame = sender.view.frame; 165 | 166 | if (frame.origin.x < 0) { 167 | frame.origin.x = 5; 168 | } 169 | 170 | if (frame.origin.y < 0) { 171 | frame.origin.y = 5; 172 | } 173 | 174 | NSInteger screenWidth = [UIScreen mainScreen].bounds.size.width; 175 | NSInteger screenHeight = [UIScreen mainScreen].bounds.size.height; 176 | 177 | if (frame.origin.x + frame.size.width > screenWidth) { 178 | frame.origin.x = screenWidth - frame.size.width - 5; 179 | } 180 | 181 | if (frame.origin.y + frame.size.height > screenHeight) { 182 | frame.origin.y = screenHeight - frame.size.height - 5; 183 | } 184 | sender.view.frame = frame; 185 | }]; 186 | } else { 187 | CGPoint point = [sender translationInView:[self windowView]]; 188 | sender.view.center = CGPointMake(sender.view.center.x + point.x, sender.view.center.y+point.y); 189 | [sender setTranslation:CGPointMake(0, 0) inView:[self windowView]]; 190 | } 191 | } 192 | 193 | static BOOL _isShowLocus = NO; 194 | 195 | + (void)showUI 196 | { 197 | static dispatch_once_t onceToken; 198 | dispatch_once(&onceToken, ^{ 199 | [Locus start]; 200 | }); 201 | 202 | _locusView = [[LocusView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - _viewWidth - 5, [Locus safeAreaTop], _viewWidth, _viewHeight)]; 203 | _locusView.backgroundColor = [UIColor whiteColor]; 204 | [[UIApplication sharedApplication].keyWindow.rootViewController.view addSubview:_locusView]; 205 | [_locusView addGestureRecognizer:[self gesture]]; 206 | 207 | _locusView.layer.cornerRadius = 5; 208 | _locusView.layer.masksToBounds = YES; 209 | _locusView.layer.borderWidth = 1; 210 | 211 | _isShowLocus = YES; 212 | } 213 | 214 | + (void)hideUI 215 | { 216 | if (_locusView) { 217 | [_locusView removeFromSuperview]; 218 | } 219 | _isShowLocus = NO; 220 | } 221 | 222 | @end 223 | 224 | @interface UIWindow (Locus) 225 | 226 | @end 227 | 228 | @implementation UIWindow (Locus) 229 | 230 | - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { 231 | if (_isShowLocus) { 232 | [Locus hideUI]; 233 | } else { 234 | [Locus showUI]; 235 | } 236 | return; 237 | } 238 | 239 | @end 240 | -------------------------------------------------------------------------------- /locus/locus/LocusRes.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocusRes.m 3 | // locus 4 | // 5 | // Created by FanFamily on 2019/1/28. 6 | // Copyright © 2019年 niuniu. All rights reserved. 7 | // 8 | 9 | #import "LocusRes.h" 10 | 11 | NSString* LocusIconRecordStart = @"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"; 12 | 13 | NSString* LocusIconRecordEnd = @"iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAYAAAAe2bNZAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH4wEcDRccYvFJkQAAB6FJREFUWMO1WF1sFNcV/s6ZmfViG7u7Jv6hwXJwwEUVDWDWTRUcL9gutiISRAlqkYCERjSVGhLoA4EqqaymiDwESnmISCIkSFPEj4siIxnHYBacpsJrE0KiCuxCEFCz62S92Mb2/szc04dZwM5iszTmSvMw0p3zfXPu+fnuoaoqLwMgjLMMQ5OWlrPK653LoVB/gYj8BMATAGYCyAOQBiAKIAigE8A5ZvoqJye7+9NPv1QLFsxm07TGxQAgVFXl1cYiQ0TweH5k+XyfO2Mxs0xEfgGgEkARAB3AEIBBAGbiPQNAeuL9CoATRFTvcOhtXu/ciN9/QRORByfjcBiilMK33/aVicgrAJYAYADtAE4RUQeAa0ToA8gERBdBNoBCEZkHwAugFIACcJSIdk6Zku1nZsRi8Xv9vGjTpxclHZPLNVkFg72ZAwND6wHsAvBjAPVE9Lqua9uXLato+vDD+gurVi0JEPHNzMxJ/VOmZN+cN2/mjUOHGi6sX7/S19l57R8i8CWO8DkAy4eGIhKNxs7n57ujkUgsiVCSZ/Ly3Kqr61quZamtANYAOENEdU6nw9faeiBaW/uClsL5Q9c1aWz8yCovX5YWicQWisgbAJ4EsI+Zt5SUFAYDgRCP9MzIF7hck28T2ZUgsoeZV/j9/qb0dKdZXb1KT4UIAJimRdXVv9TT052m3+8/xswrAOwBsFoptevixat5LtdkdU/POByG9Pb2Z8Tj5l8SRHYYhl5XXDx1MBgMcyoExlu5uS51+XJ3Rjxu/hHABgD7DEN71e3OHkzEkOiAnTVKKcTj5su3PWIYel1+vnswGAxzcfFUa/fuv49Kgz17/kz79x8flR1EhHXrnrWef37DqL0vvfQrunLlhpaf7x4MBEJ18biVDWBtPG79Wym1nYggIrZnyspmqU8+8T8pIh8D+A8zr5g589HuYDDMzCy9vf0e2DXltlsJQNDpdJyaNCnNEhEQEYaHo1okEquAXXtuE2IAF93urHalFOXmulRX1/UCpdRBAI8T0XNVVfPPtLdfYN0wNPH5Pncm0ncSEdW1tbVdr65eqAOAw6FDRNYAeHkEAAHwmab1L2YasiwhZhLTtBwishl2Wo/c+25amt4+PBxDT0+Y29ra/uvxeP4kIodFZP3p0+d+nZWVEeWWlrMqFjPLYNeReqfT4Vu8uFIb4+gJdzNvrEDm++1dvLhSczodJwHUA1gSi5meY8dOKfZ653KisjIR7WttPRBVSt35mGhc4AdYd00opai19WCUiPYCYBFZXlNTwRwK9RfALvHtmsYdtbUvaGMZ+Z5rVFDX1q7RNI07AHQAqAyF+go40fSKAJxaunRB/3frSCJbJEXA1FwDuw4988zP+gH4ABSJYDbD7r46EXVs3rx9IkBTcQwA4M03dwoRnQWgi8gchp2yQwCubdr0m+R+YQfNRMRMEpstW35LAK4m8Gcy7JowSIS+K1cCY4E+FI9dutRNdtfHIIA8ht1VTYDMeNxMZiETxiPpRxN4ZuJJY9gKTQdENwwtZUMTsQxDh40NHUCUYUvFDBFkFxUVJLkhETMTsZJsFxdPlYQgywAQZNiaNR1A4dtv75YxbDyUmNm69V0BUJjA72QA5wCYIjJv27bfJ7lh4kJGkmy/9dYGSkhUkwhfMBF9BVs8e48cac3Sde1e8BPaDgBbCTY0/DMLdlP9mojOc05OdjeAEwBKLUuVNjZ+ZI0y8ZBiprHxY8uyVCls0d7idmfd4M8++1IRUT0AJSJrysuXpTHznQ/HaQf/N0tmlvLyn6eJyGoAiogONzW1KH7qqdnscOhtAI4CWBaJxBY2NZ2wxrAjI4ipcfZ8d6+I3I2ZpqYTViQSWwRgOYAGh0P319RU8kil99ORSm/GjEdv9PTcUXrzYbeNkYIpVaVHALrc7iy/Uory8lyqs/P6VKXUAQAziOjZ6ur5Z/z+CzYZIiJNY/nmm5sbAWwDsMcwtI35+TmDt24N82OPFVjvv79/1FEdOPAOffDB0SQNvHJllfXii38YtXfdupV0+XK3lpk5SQUCvZnxuPkOgLUANuXmunaYpkUiIqNuB6FQX4ZpWjsBrAawwzC0uunTfzjY0/P9bwd5eS516VJ3ZjxuvgFgI4C9hqG/5nZn3bkd3AGJxeJUWJh3i5m3ADgCYEM8bm3v6rpe0Nx80hwZ1A8arM3NJ83OzutTEx7ZCOAIM2+ZNi331sir7qg/DocHuKSkMMjMrwDYB2CtUuqgx+OpGRqK6M3NfzPHqENJS9c1aW5uMIeGIrrH46lNxMhaAHuZ+XclJdN6wuGBUfhJ7g8EQlxUlB80DO1VAK8DeFxEDg8PR9/zeJYuCocHMp9++gnr+HGfWVY2y8rJyVZZWRkqJydblZXNso4f95le71wrHB7I9HgWLhoeju4WkUMAZgDYZBj6a0VF+T2BQG8SdipTCI+IrMfdKUQHAF9CoV1N6BETwHhTiAYi+usjj/zAT0RjTiHuO58pLS2xTp8+54zFTI+ILEfq85mvAbQQ0WGHQ/dXVMyJtLdfvO985r6TK13X5NixU6qmpoJDob4CEZktgjkYY3JFhC+I6LzbnXWjqalF1dRUpjS5+h88dqZXS0NW6AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wMS0yOFQxMzoyMzoyOCswMDowMEaLVL8AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDEtMjhUMTM6MjM6MjgrMDA6MDA31uwDAAAAAElFTkSuQmCC"; 14 | 15 | NSString* LocusIconSetting = @"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"; 16 | -------------------------------------------------------------------------------- /locus/locus/locusImpl.c: -------------------------------------------------------------------------------- 1 | // 2 | // hookObjcSend.c 3 | // fishhookdemo 4 | // 5 | // Created by FanFamily on 2018/7/21. 6 | // Copyright © 2018年 Family Fan. All rights reserved. 7 | // 8 | 9 | #include "locusImpl.h" 10 | 11 | #include "fishhook.h" 12 | #include 13 | #import 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #import 26 | #include "LocusArgPrinter.h" 27 | 28 | static pthread_t _main_ptread; 29 | 30 | static int lcs_print = 0; 31 | static int lcs_switch_open = 1; 32 | static int lcs_switch_close = 0; 33 | static pthread_key_t _thread_lr_stack_key; 34 | static LCSFilterBlock _filter_block = NULL; 35 | static long _due = 0; 36 | static pthread_key_t _thread_switch_key; 37 | static char _log_path[1024]; 38 | static FILE * _log_file = NULL; 39 | __unused static id (*orig_objc_msgSend)(id, SEL, ...); 40 | 41 | typedef struct { 42 | void *pre; 43 | void *next; 44 | uintptr_t lr; 45 | long long time; 46 | char* obj; 47 | char* sel; 48 | long level; 49 | } thread_lr_stack; 50 | 51 | void lcs_open() 52 | { 53 | pthread_setspecific(_thread_switch_key, &lcs_switch_open); 54 | } 55 | 56 | void lcs_close() 57 | { 58 | pthread_setspecific(_thread_switch_key, &lcs_switch_close); 59 | } 60 | 61 | void before_objc_msgSend(id self, SEL sel, ...) { 62 | void* p_switch = pthread_getspecific(_thread_switch_key); 63 | int lcs_switch = 1; 64 | if (p_switch == NULL) { 65 | lcs_open(); 66 | } else { 67 | lcs_switch = *(int *)p_switch; 68 | } 69 | 70 | int (^filter_block)(void) = ^(){ 71 | if (_filter_block == NULL) { 72 | return 0; 73 | } 74 | int result = 0; 75 | lcs_close(); 76 | result = _filter_block((char *)object_getClassName(self), (char *)sel); 77 | lcs_open(); 78 | return result; 79 | }; 80 | 81 | int filter_result = 0; 82 | if (lcs_print > 0 && lcs_switch > 0) { 83 | filter_result = filter_block(); 84 | if (filter_result > 0) { 85 | printf("class %s, selector %s\n", (char *)object_getClassName(self), (char *)sel); 86 | } 87 | 88 | if (filter_result > 1) { 89 | // arm64 not support 90 | #ifndef __arm64__ 91 | lcs_close(); 92 | va_list argptr; 93 | va_start(argptr, sel); 94 | printArgs((char *)object_getClassName(self), (char *)sel, argptr); 95 | va_end(argptr); 96 | lcs_open(); 97 | #endif 98 | } 99 | } 100 | 101 | } 102 | 103 | long long lcs_getCurrentTime() { 104 | struct timeval te; 105 | gettimeofday(&te, NULL); 106 | long long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; 107 | return milliseconds; 108 | } 109 | 110 | uintptr_t save_lr(id self, SEL sel, uintptr_t lr) 111 | { 112 | thread_lr_stack* ls = pthread_getspecific(_thread_lr_stack_key); 113 | if (ls == NULL) { 114 | ls = malloc(sizeof(thread_lr_stack)); 115 | ls->pre = NULL; 116 | ls->next = NULL; 117 | ls->lr = lr; 118 | ls->obj = (char *)object_getClassName(self); 119 | ls->sel = (char *)sel; 120 | ls->time = lcs_getCurrentTime(); 121 | ls->level = 0; 122 | pthread_setspecific(_thread_lr_stack_key, (void *)ls); 123 | } else { 124 | thread_lr_stack* next = malloc(sizeof(thread_lr_stack)); 125 | ls->next = next; 126 | next->pre = ls; 127 | next->next = NULL; 128 | next->lr = lr; 129 | next->obj = (char *)object_getClassName(self); 130 | next->sel = (char *)sel; 131 | next->time = lcs_getCurrentTime(); 132 | next->level = ls->level + 1; 133 | pthread_setspecific(_thread_lr_stack_key, (void *)next); 134 | } 135 | return (uintptr_t)orig_objc_msgSend; 136 | } 137 | 138 | void write_method_due_log(char* obj, char* sel, long due, long level) { 139 | if (_main_ptread == pthread_self()) { 140 | if (level == 0) { 141 | fprintf(_log_file, "↑ due time %ld [%s %s]\n", due, obj, sel); 142 | } else { 143 | fprintf(_log_file, "due time %ld [%s %s]\n", due, obj, sel); 144 | } 145 | } 146 | } 147 | 148 | uintptr_t get_lr() { 149 | thread_lr_stack* ls = pthread_getspecific(_thread_lr_stack_key); 150 | pthread_setspecific(_thread_lr_stack_key, (void *)ls->pre); 151 | uintptr_t lr = ls->lr; 152 | long due = (long)(lcs_getCurrentTime() - ls->time); 153 | if (_due > 0 && due > _due) { 154 | write_method_due_log(ls->obj, ls->sel, due, ls->level); 155 | } 156 | free(ls); 157 | return lr; 158 | } 159 | 160 | void lcs_stop_print() { 161 | lcs_print = 0; 162 | } 163 | 164 | void lcs_resume_print() { 165 | lcs_print = 1; 166 | } 167 | 168 | extern id hook_objc_msgSend(id, SEL, ...); 169 | 170 | #ifdef __arm64__ 171 | 172 | __asm__ ( 173 | ".text\n" 174 | ".global _hook_objc_msgSend\n" 175 | 176 | "_hook_objc_msgSend:\n" 177 | 178 | "stp q6, q7, [sp, #-32]!\n" 179 | "stp q4, q5, [sp, #-32]!\n" 180 | "stp q2, q3, [sp, #-32]!\n" 181 | "stp q0, q1, [sp, #-32]!\n" 182 | 183 | "stp x6, x7, [sp, #-16]!\n" 184 | "stp x4, x5, [sp, #-16]!\n" 185 | "stp x2, x3, [sp, #-16]!\n" 186 | "stp x0, x1, [sp, #-16]!\n" 187 | "stp x8, lr, [sp, #-16]!\n" 188 | 189 | "bl _before_objc_msgSend\n" 190 | 191 | "ldp x8, lr, [sp], #16\n" 192 | "ldp x0, x1, [sp], #16\n" 193 | "stp x0, x1, [sp, #-16]!\n" 194 | "stp x8, lr, [sp, #-16]!\n" 195 | 196 | "mov x2, lr\n" 197 | 198 | "bl _save_lr\n" 199 | 200 | "mov x9, x0\n" 201 | 202 | "ldp x8, lr, [sp], #16\n" 203 | "ldp x0, x1, [sp], #16\n" 204 | "ldp x2, x3, [sp], #16\n" 205 | "ldp x4, x5, [sp], #16\n" 206 | "ldp x6, x7, [sp], #16\n" 207 | 208 | "ldp q0, q1, [sp], #32\n" 209 | "ldp q2, q3, [sp], #32\n" 210 | "ldp q4, q5, [sp], #32\n" 211 | "ldp q6, q7, [sp], #32\n" 212 | 213 | "blr x9\n" 214 | "stp x0, x1, [sp, #-16]!\n" 215 | "stp q0, q1, [sp, #-32]!\n" 216 | "bl _get_lr\n" 217 | "mov lr, x0\n" 218 | "ldp q0, q1, [sp], #32\n" 219 | "ldp x0, x1, [sp], #16\n" 220 | "ret\n" 221 | 222 | "ret\n" 223 | ); 224 | 225 | #elif __LP64__ 226 | __asm__ ( 227 | ".text\n" 228 | ".global _hook_objc_msgSend\n" 229 | 230 | "_hook_objc_msgSend:\n" 231 | "pushq %rbp\n" 232 | "movq %rsp, %rbp\n" 233 | "subq $0x210, %rsp\n" 234 | 235 | "movq %xmm15, -0x210(%rbp)\n" 236 | "movq %xmm14, -0x200(%rbp)\n" 237 | "movq %xmm13, -0x190(%rbp)\n" 238 | "movq %xmm12, -0x180(%rbp)\n" 239 | "movq %xmm11, -0x170(%rbp)\n" 240 | "movq %xmm10, -0x160(%rbp)\n" 241 | "movq %xmm9, -0x150(%rbp)\n" 242 | "movq %xmm8, -0x140(%rbp)\n" 243 | "movq %xmm7, -0x130(%rbp)\n" 244 | "movq %xmm6, -0x120(%rbp)\n" 245 | "movq %xmm5, -0x110(%rbp)\n" 246 | "movq %xmm4, -0x100(%rbp)\n" 247 | "movq %xmm3, -0x90(%rbp)\n" 248 | "movq %xmm2, -0x80(%rbp)\n" 249 | "movq %xmm1, -0x70(%rbp)\n" 250 | "movq %xmm0, -0x60(%rbp)\n" 251 | "movq %rbx, -0x58(%rbp)\n" 252 | "movq %rdi, -0x50(%rbp)\n" 253 | "movq %rsi, -0x48(%rbp)\n" 254 | "movq %rdx, -0x40(%rbp)\n" 255 | "movq %rcx, -0x38(%rbp)\n" 256 | "movq %r8, -0x30(%rbp)\n" 257 | "movq %r9, -0x28(%rbp)\n" 258 | "movq %r12, -0x20(%rbp)\n" 259 | "movq %r13, -0x18(%rbp)\n" 260 | "movq %r14, -0x10(%rbp)\n" 261 | "movq %r15, -0x8(%rbp)\n" 262 | 263 | "call _before_objc_msgSend\n" 264 | 265 | "movq -0x50(%rbp), %rdi\n" 266 | "movq -0x48(%rbp), %rsi\n" 267 | "movq 0x8(%rbp), %rdx\n" 268 | 269 | "call _save_lr\n" 270 | 271 | "movq -0x210(%rbp), %xmm15\n" 272 | "movq -0x200(%rbp), %xmm14\n" 273 | "movq -0x190(%rbp), %xmm13\n" 274 | "movq -0x180(%rbp), %xmm12\n" 275 | "movq -0x170(%rbp), %xmm11\n" 276 | "movq -0x160(%rbp), %xmm10\n" 277 | "movq -0x150(%rbp), %xmm9\n" 278 | "movq -0x140(%rbp), %xmm8\n" 279 | "movq -0x130(%rbp), %xmm7\n" 280 | "movq -0x120(%rbp), %xmm6\n" 281 | "movq -0x110(%rbp), %xmm5\n" 282 | "movq -0x100(%rbp), %xmm4\n" 283 | "movq -0x90(%rbp), %xmm3\n" 284 | "movq -0x80(%rbp), %xmm2\n" 285 | "movq -0x70(%rbp), %xmm1\n" 286 | "movq -0x60(%rbp), %xmm0\n" 287 | "movq -0x58(%rbp), %rbx\n" 288 | "movq -0x50(%rbp), %rdi\n" 289 | "movq -0x48(%rbp), %rsi\n" 290 | "movq -0x40(%rbp), %rdx\n" 291 | "movq -0x38(%rbp), %rcx\n" 292 | "movq -0x30(%rbp), %r8\n" 293 | "movq -0x28(%rbp), %r9\n" 294 | "movq -0x20(%rbp), %r12\n" 295 | "movq -0x18(%rbp), %r13\n" 296 | "movq -0x10(%rbp), %r14\n" 297 | "movq -0x8(%rbp), %r15\n" 298 | 299 | "addq $0x210, %rsp\n" 300 | 301 | "popq %rbp\n" 302 | "addq $0x8, %rsp\n" 303 | "call *%rax\n" 304 | "pushq %rax\n" 305 | "pushq %rdx\n" 306 | 307 | "subq $0x20, %rsp\n" 308 | "movq %xmm0, 0x0(%rsp)\n" 309 | "movq %xmm1, 0x10(%rsp)\n" 310 | "call _get_lr\n" 311 | "movq %rax, %r10\n" 312 | "movq 0x0(%rsp), %xmm0\n" 313 | "movq 0x10(%rsp), %xmm1\n" 314 | "addq $0x20, %rsp\n" 315 | 316 | "popq %rdx\n" 317 | "popq %rax\n" 318 | "push %r10\n" 319 | "retq\n" 320 | "ret\n" 321 | ); 322 | #else 323 | id hook_objc_msgSend(id obj, SEL sel, ...) { 324 | return nil; 325 | } 326 | #endif 327 | 328 | void lcs_start(LCSFilterBlock filter) { 329 | 330 | _filter_block = filter; 331 | 332 | lcs_resume_print(); 333 | 334 | pthread_key_create(&_thread_switch_key, NULL); 335 | pthread_key_create(&_thread_lr_stack_key, NULL); 336 | rebind_symbols((struct rebinding[1]){{"objc_msgSend", hook_objc_msgSend, (void *)&orig_objc_msgSend}}, 1); 337 | } 338 | 339 | void lcs_start_performance(long ms, char* log_path) { 340 | 341 | memset(_log_path, 0, 1024); 342 | memcpy(_log_path, log_path, strlen(log_path)); 343 | 344 | _log_file = fopen(log_path, "w"); 345 | if (_log_file == NULL) { 346 | printf("Error opening file!\n"); 347 | exit(1); 348 | } 349 | 350 | _due = ms; 351 | _main_ptread = pthread_self(); 352 | pthread_key_create(&_thread_lr_stack_key, NULL); 353 | rebind_symbols((struct rebinding[1]){{"objc_msgSend", hook_objc_msgSend, (void *)&orig_objc_msgSend}}, 1); 354 | } 355 | 356 | 357 | -------------------------------------------------------------------------------- /locus/locus/fishhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #include "fishhook.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __LP64__ 40 | typedef struct mach_header_64 mach_header_t; 41 | typedef struct segment_command_64 segment_command_t; 42 | typedef struct section_64 section_t; 43 | typedef struct nlist_64 nlist_t; 44 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 45 | #else 46 | typedef struct mach_header mach_header_t; 47 | typedef struct segment_command segment_command_t; 48 | typedef struct section section_t; 49 | typedef struct nlist nlist_t; 50 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 51 | #endif 52 | 53 | #ifndef SEG_DATA_CONST 54 | #define SEG_DATA_CONST "__DATA_CONST" 55 | #endif 56 | 57 | struct rebindings_entry { 58 | struct rebinding *rebindings; 59 | size_t rebindings_nel; 60 | struct rebindings_entry *next; 61 | }; 62 | 63 | static struct rebindings_entry *_rebindings_head; 64 | 65 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 66 | struct rebinding rebindings[], 67 | size_t nel) { 68 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 69 | if (!new_entry) { 70 | return -1; 71 | } 72 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 73 | if (!new_entry->rebindings) { 74 | free(new_entry); 75 | return -1; 76 | } 77 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 78 | new_entry->rebindings_nel = nel; 79 | new_entry->next = *rebindings_head; 80 | *rebindings_head = new_entry; 81 | return 0; 82 | } 83 | 84 | #if 0 85 | static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { 86 | mach_port_t task = mach_task_self(); 87 | vm_size_t size = 0; 88 | vm_address_t address = (vm_address_t)addr; 89 | memory_object_name_t object; 90 | #ifdef __LP64__ 91 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; 92 | vm_region_basic_info_data_64_t info; 93 | kern_return_t info_ret = vm_region_64( 94 | task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); 95 | #else 96 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; 97 | vm_region_basic_info_data_t info; 98 | kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); 99 | #endif 100 | if (info_ret == KERN_SUCCESS) { 101 | if (prot != NULL) 102 | *prot = info.protection; 103 | 104 | if (max_prot != NULL) 105 | *max_prot = info.max_protection; 106 | 107 | return 0; 108 | } 109 | 110 | return -1; 111 | } 112 | #endif 113 | 114 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 115 | section_t *section, 116 | intptr_t slide, 117 | nlist_t *symtab, 118 | char *strtab, 119 | uint32_t *indirect_symtab) { 120 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 121 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 122 | 123 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 124 | uint32_t symtab_index = indirect_symbol_indices[i]; 125 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 126 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 127 | continue; 128 | } 129 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 130 | char *symbol_name = strtab + strtab_offset; 131 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 132 | struct rebindings_entry *cur = rebindings; 133 | while (cur) { 134 | for (uint j = 0; j < cur->rebindings_nel; j++) { 135 | if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 136 | kern_return_t err; 137 | 138 | if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) 139 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 140 | 141 | /** 142 | * 1. Moved the vm protection modifying codes to here to reduce the 143 | * changing scope. 144 | * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region 145 | * API on some iOS/Mac reports mismatch vm protection attributes. 146 | * -- Lianfu Hao Jun 16th, 2021 147 | **/ 148 | err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); 149 | if (err == KERN_SUCCESS) { 150 | /** 151 | * Once we failed to change the vm protection, we 152 | * MUST NOT continue the following write actions! 153 | * iOS 15 has corrected the const segments prot. 154 | * -- Lionfore Hao Jun 11th, 2021 155 | **/ 156 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 157 | } 158 | goto symbol_loop; 159 | } 160 | } 161 | cur = cur->next; 162 | } 163 | symbol_loop:; 164 | } 165 | } 166 | 167 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 168 | const struct mach_header *header, 169 | intptr_t slide) { 170 | Dl_info info; 171 | if (dladdr(header, &info) == 0) { 172 | return; 173 | } 174 | 175 | segment_command_t *cur_seg_cmd; 176 | segment_command_t *linkedit_segment = NULL; 177 | struct symtab_command* symtab_cmd = NULL; 178 | struct dysymtab_command* dysymtab_cmd = NULL; 179 | 180 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 181 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 182 | cur_seg_cmd = (segment_command_t *)cur; 183 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 184 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 185 | linkedit_segment = cur_seg_cmd; 186 | } 187 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 188 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 189 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 190 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 191 | } 192 | } 193 | 194 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 195 | !dysymtab_cmd->nindirectsyms) { 196 | return; 197 | } 198 | 199 | // Find base symbol/string table addresses 200 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 201 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 202 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 203 | 204 | // Get indirect symbol table (array of uint32_t indices into symbol table) 205 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 206 | 207 | cur = (uintptr_t)header + sizeof(mach_header_t); 208 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 209 | cur_seg_cmd = (segment_command_t *)cur; 210 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 211 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 212 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 213 | continue; 214 | } 215 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 216 | section_t *sect = 217 | (section_t *)(cur + sizeof(segment_command_t)) + j; 218 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 219 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 220 | } 221 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 222 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 223 | } 224 | } 225 | } 226 | } 227 | } 228 | 229 | static void _rebind_symbols_for_image(const struct mach_header *header, 230 | intptr_t slide) { 231 | rebind_symbols_for_image(_rebindings_head, header, slide); 232 | } 233 | 234 | int rebind_symbols_image(void *header, 235 | intptr_t slide, 236 | struct rebinding rebindings[], 237 | size_t rebindings_nel) { 238 | struct rebindings_entry *rebindings_head = NULL; 239 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 240 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 241 | if (rebindings_head) { 242 | free(rebindings_head->rebindings); 243 | } 244 | free(rebindings_head); 245 | return retval; 246 | } 247 | 248 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 249 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 250 | if (retval < 0) { 251 | return retval; 252 | } 253 | // If this was the first call, register callback for image additions (which is also invoked for 254 | // existing images, otherwise, just run on existing images 255 | if (!_rebindings_head->next) { 256 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 257 | } else { 258 | uint32_t c = _dyld_image_count(); 259 | for (uint32_t i = 0; i < c; i++) { 260 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 261 | } 262 | } 263 | return retval; 264 | } 265 | -------------------------------------------------------------------------------- /locus/locus.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E377697921FC26CB0050B72F /* Locus.m in Sources */ = {isa = PBXBuildFile; fileRef = E377697821FC26CB0050B72F /* Locus.m */; }; 11 | E377698121FCBCEC0050B72F /* LocusArgPrinter.m in Sources */ = {isa = PBXBuildFile; fileRef = E377698021FCBCEC0050B72F /* LocusArgPrinter.m */; }; 12 | E37769DA21FF3C840050B72F /* LocusRes.m in Sources */ = {isa = PBXBuildFile; fileRef = E37769D921FF3C840050B72F /* LocusRes.m */; }; 13 | E393701F21DAF6370012235D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E393701E21DAF6370012235D /* AppDelegate.m */; }; 14 | E393702221DAF6370012235D /* LCUSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E393702121DAF6370012235D /* LCUSViewController.m */; }; 15 | E393702521DAF6370012235D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E393702321DAF6370012235D /* Main.storyboard */; }; 16 | E393702721DAF6380012235D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E393702621DAF6380012235D /* Assets.xcassets */; }; 17 | E393702A21DAF6380012235D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E393702821DAF6380012235D /* LaunchScreen.storyboard */; }; 18 | E393702D21DAF6380012235D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E393702C21DAF6380012235D /* main.m */; }; 19 | E393703521DAF7940012235D /* LCUSTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = E393703421DAF7940012235D /* LCUSTableView.m */; }; 20 | E39B1F8F21DB2355005DAD5C /* LCUSTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E39B1F8E21DB2355005DAD5C /* LCUSTableViewCell.m */; }; 21 | E39B1F9821DB263E005DAD5C /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = E39B1F9221DB263E005DAD5C /* fishhook.c */; }; 22 | E39B1F9A21DB263E005DAD5C /* locusImpl.c in Sources */ = {isa = PBXBuildFile; fileRef = E39B1F9621DB263E005DAD5C /* locusImpl.c */; }; 23 | FD00995D21FEB1B100D52D3A /* LocusView.m in Sources */ = {isa = PBXBuildFile; fileRef = FD00995C21FEB1B100D52D3A /* LocusView.m */; }; 24 | FD00997421FEE90900D52D3A /* LocusSettingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD00997321FEE90900D52D3A /* LocusSettingViewController.m */; }; 25 | FD00997821FEF5ED00D52D3A /* Locus+Config.m in Sources */ = {isa = PBXBuildFile; fileRef = FD00997721FEF5ED00D52D3A /* Locus+Config.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | E377697521FC13C10050B72F /* locus copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "locus copy-Info.plist"; path = "/Users/fanfei/work/locus/locus/locus copy-Info.plist"; sourceTree = ""; }; 30 | E377697721FC26CB0050B72F /* Locus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Locus.h; sourceTree = ""; }; 31 | E377697821FC26CB0050B72F /* Locus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Locus.m; sourceTree = ""; }; 32 | E377697F21FCBCEC0050B72F /* LocusArgPrinter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocusArgPrinter.h; sourceTree = ""; }; 33 | E377698021FCBCEC0050B72F /* LocusArgPrinter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocusArgPrinter.m; sourceTree = ""; }; 34 | E37769D821FF3C840050B72F /* LocusRes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocusRes.h; sourceTree = ""; }; 35 | E37769D921FF3C840050B72F /* LocusRes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocusRes.m; sourceTree = ""; }; 36 | E393701A21DAF6370012235D /* locus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = locus.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | E393701D21DAF6370012235D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 38 | E393701E21DAF6370012235D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 39 | E393702021DAF6370012235D /* LCUSViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LCUSViewController.h; sourceTree = ""; }; 40 | E393702121DAF6370012235D /* LCUSViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCUSViewController.m; sourceTree = ""; }; 41 | E393702421DAF6370012235D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | E393702621DAF6380012235D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | E393702921DAF6380012235D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | E393702B21DAF6380012235D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | E393702C21DAF6380012235D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 46 | E393703321DAF7940012235D /* LCUSTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LCUSTableView.h; sourceTree = ""; }; 47 | E393703421DAF7940012235D /* LCUSTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCUSTableView.m; sourceTree = ""; }; 48 | E39B1F8D21DB2355005DAD5C /* LCUSTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LCUSTableViewCell.h; sourceTree = ""; }; 49 | E39B1F8E21DB2355005DAD5C /* LCUSTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCUSTableViewCell.m; sourceTree = ""; }; 50 | E39B1F9221DB263E005DAD5C /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fishhook.c; sourceTree = ""; }; 51 | E39B1F9421DB263E005DAD5C /* locusImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locusImpl.h; sourceTree = ""; }; 52 | E39B1F9621DB263E005DAD5C /* locusImpl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locusImpl.c; sourceTree = ""; }; 53 | E39B1F9721DB263E005DAD5C /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fishhook.h; sourceTree = ""; }; 54 | FD00995B21FEB1B100D52D3A /* LocusView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocusView.h; sourceTree = ""; }; 55 | FD00995C21FEB1B100D52D3A /* LocusView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocusView.m; sourceTree = ""; }; 56 | FD00997221FEE90900D52D3A /* LocusSettingViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocusSettingViewController.h; sourceTree = ""; }; 57 | FD00997321FEE90900D52D3A /* LocusSettingViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocusSettingViewController.m; sourceTree = ""; }; 58 | FD00997621FEF5ED00D52D3A /* Locus+Config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Locus+Config.h"; sourceTree = ""; }; 59 | FD00997721FEF5ED00D52D3A /* Locus+Config.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "Locus+Config.m"; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | E393701721DAF6370012235D /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | E393701121DAF6370012235D = { 74 | isa = PBXGroup; 75 | children = ( 76 | E39B1F9121DB25BE005DAD5C /* locus */, 77 | E393701C21DAF6370012235D /* LocusDemo */, 78 | E393701B21DAF6370012235D /* Products */, 79 | E377697521FC13C10050B72F /* locus copy-Info.plist */, 80 | ); 81 | sourceTree = ""; 82 | }; 83 | E393701B21DAF6370012235D /* Products */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | E393701A21DAF6370012235D /* locus.app */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | E393701C21DAF6370012235D /* LocusDemo */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | E393701D21DAF6370012235D /* AppDelegate.h */, 95 | E393701E21DAF6370012235D /* AppDelegate.m */, 96 | E393702021DAF6370012235D /* LCUSViewController.h */, 97 | E393702121DAF6370012235D /* LCUSViewController.m */, 98 | E393703321DAF7940012235D /* LCUSTableView.h */, 99 | E393703421DAF7940012235D /* LCUSTableView.m */, 100 | E39B1F8D21DB2355005DAD5C /* LCUSTableViewCell.h */, 101 | E39B1F8E21DB2355005DAD5C /* LCUSTableViewCell.m */, 102 | E393702321DAF6370012235D /* Main.storyboard */, 103 | E393702621DAF6380012235D /* Assets.xcassets */, 104 | E393702821DAF6380012235D /* LaunchScreen.storyboard */, 105 | E393702B21DAF6380012235D /* Info.plist */, 106 | E393702C21DAF6380012235D /* main.m */, 107 | ); 108 | path = LocusDemo; 109 | sourceTree = ""; 110 | }; 111 | E39B1F9121DB25BE005DAD5C /* locus */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | E39B1F9221DB263E005DAD5C /* fishhook.c */, 115 | E39B1F9721DB263E005DAD5C /* fishhook.h */, 116 | E39B1F9621DB263E005DAD5C /* locusImpl.c */, 117 | E39B1F9421DB263E005DAD5C /* locusImpl.h */, 118 | E377697721FC26CB0050B72F /* Locus.h */, 119 | E377697821FC26CB0050B72F /* Locus.m */, 120 | FD00997621FEF5ED00D52D3A /* Locus+Config.h */, 121 | FD00997721FEF5ED00D52D3A /* Locus+Config.m */, 122 | E377697F21FCBCEC0050B72F /* LocusArgPrinter.h */, 123 | E377698021FCBCEC0050B72F /* LocusArgPrinter.m */, 124 | FD00995B21FEB1B100D52D3A /* LocusView.h */, 125 | FD00995C21FEB1B100D52D3A /* LocusView.m */, 126 | FD00997221FEE90900D52D3A /* LocusSettingViewController.h */, 127 | FD00997321FEE90900D52D3A /* LocusSettingViewController.m */, 128 | E37769D821FF3C840050B72F /* LocusRes.h */, 129 | E37769D921FF3C840050B72F /* LocusRes.m */, 130 | ); 131 | path = locus; 132 | sourceTree = ""; 133 | }; 134 | /* End PBXGroup section */ 135 | 136 | /* Begin PBXNativeTarget section */ 137 | E393701921DAF6370012235D /* locus */ = { 138 | isa = PBXNativeTarget; 139 | buildConfigurationList = E393703021DAF6380012235D /* Build configuration list for PBXNativeTarget "locus" */; 140 | buildPhases = ( 141 | E393701621DAF6370012235D /* Sources */, 142 | E393701721DAF6370012235D /* Frameworks */, 143 | E393701821DAF6370012235D /* Resources */, 144 | ); 145 | buildRules = ( 146 | ); 147 | dependencies = ( 148 | ); 149 | name = locus; 150 | productName = locus; 151 | productReference = E393701A21DAF6370012235D /* locus.app */; 152 | productType = "com.apple.product-type.application"; 153 | }; 154 | /* End PBXNativeTarget section */ 155 | 156 | /* Begin PBXProject section */ 157 | E393701221DAF6370012235D /* Project object */ = { 158 | isa = PBXProject; 159 | attributes = { 160 | LastUpgradeCheck = 1010; 161 | ORGANIZATIONNAME = niuniu; 162 | TargetAttributes = { 163 | E393701921DAF6370012235D = { 164 | CreatedOnToolsVersion = 10.1; 165 | }; 166 | }; 167 | }; 168 | buildConfigurationList = E393701521DAF6370012235D /* Build configuration list for PBXProject "locus" */; 169 | compatibilityVersion = "Xcode 9.3"; 170 | developmentRegion = en; 171 | hasScannedForEncodings = 0; 172 | knownRegions = ( 173 | en, 174 | Base, 175 | ); 176 | mainGroup = E393701121DAF6370012235D; 177 | productRefGroup = E393701B21DAF6370012235D /* Products */; 178 | projectDirPath = ""; 179 | projectRoot = ""; 180 | targets = ( 181 | E393701921DAF6370012235D /* locus */, 182 | ); 183 | }; 184 | /* End PBXProject section */ 185 | 186 | /* Begin PBXResourcesBuildPhase section */ 187 | E393701821DAF6370012235D /* Resources */ = { 188 | isa = PBXResourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | E393702A21DAF6380012235D /* LaunchScreen.storyboard in Resources */, 192 | E393702721DAF6380012235D /* Assets.xcassets in Resources */, 193 | E393702521DAF6370012235D /* Main.storyboard in Resources */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | /* End PBXResourcesBuildPhase section */ 198 | 199 | /* Begin PBXSourcesBuildPhase section */ 200 | E393701621DAF6370012235D /* Sources */ = { 201 | isa = PBXSourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | E39B1F9A21DB263E005DAD5C /* locusImpl.c in Sources */, 205 | E393703521DAF7940012235D /* LCUSTableView.m in Sources */, 206 | FD00997421FEE90900D52D3A /* LocusSettingViewController.m in Sources */, 207 | E37769DA21FF3C840050B72F /* LocusRes.m in Sources */, 208 | E377698121FCBCEC0050B72F /* LocusArgPrinter.m in Sources */, 209 | FD00995D21FEB1B100D52D3A /* LocusView.m in Sources */, 210 | E393702221DAF6370012235D /* LCUSViewController.m in Sources */, 211 | FD00997821FEF5ED00D52D3A /* Locus+Config.m in Sources */, 212 | E393702D21DAF6380012235D /* main.m in Sources */, 213 | E39B1F8F21DB2355005DAD5C /* LCUSTableViewCell.m in Sources */, 214 | E377697921FC26CB0050B72F /* Locus.m in Sources */, 215 | E39B1F9821DB263E005DAD5C /* fishhook.c in Sources */, 216 | E393701F21DAF6370012235D /* AppDelegate.m in Sources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXSourcesBuildPhase section */ 221 | 222 | /* Begin PBXVariantGroup section */ 223 | E393702321DAF6370012235D /* Main.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | E393702421DAF6370012235D /* Base */, 227 | ); 228 | name = Main.storyboard; 229 | sourceTree = ""; 230 | }; 231 | E393702821DAF6380012235D /* LaunchScreen.storyboard */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | E393702921DAF6380012235D /* Base */, 235 | ); 236 | name = LaunchScreen.storyboard; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXVariantGroup section */ 240 | 241 | /* Begin XCBuildConfiguration section */ 242 | E393702E21DAF6380012235D /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_ANALYZER_NONNULL = YES; 247 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 249 | CLANG_CXX_LIBRARY = "libc++"; 250 | CLANG_ENABLE_MODULES = YES; 251 | CLANG_ENABLE_OBJC_ARC = YES; 252 | CLANG_ENABLE_OBJC_WEAK = YES; 253 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 254 | CLANG_WARN_BOOL_CONVERSION = YES; 255 | CLANG_WARN_COMMA = YES; 256 | CLANG_WARN_CONSTANT_CONVERSION = YES; 257 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 259 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 260 | CLANG_WARN_EMPTY_BODY = YES; 261 | CLANG_WARN_ENUM_CONVERSION = YES; 262 | CLANG_WARN_INFINITE_RECURSION = YES; 263 | CLANG_WARN_INT_CONVERSION = YES; 264 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 266 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 269 | CLANG_WARN_STRICT_PROTOTYPES = YES; 270 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 271 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | CODE_SIGN_IDENTITY = "iPhone Developer"; 275 | COPY_PHASE_STRIP = NO; 276 | DEBUG_INFORMATION_FORMAT = dwarf; 277 | ENABLE_STRICT_OBJC_MSGSEND = YES; 278 | ENABLE_TESTABILITY = YES; 279 | GCC_C_LANGUAGE_STANDARD = gnu11; 280 | GCC_DYNAMIC_NO_PIC = NO; 281 | GCC_NO_COMMON_BLOCKS = YES; 282 | GCC_OPTIMIZATION_LEVEL = 0; 283 | GCC_PREPROCESSOR_DEFINITIONS = ( 284 | "DEBUG=1", 285 | "$(inherited)", 286 | ); 287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 288 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 289 | GCC_WARN_UNDECLARED_SELECTOR = YES; 290 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 291 | GCC_WARN_UNUSED_FUNCTION = YES; 292 | GCC_WARN_UNUSED_VARIABLE = YES; 293 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 294 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 295 | MTL_FAST_MATH = YES; 296 | ONLY_ACTIVE_ARCH = YES; 297 | SDKROOT = iphoneos; 298 | }; 299 | name = Debug; 300 | }; 301 | E393702F21DAF6380012235D /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ALWAYS_SEARCH_USER_PATHS = NO; 305 | CLANG_ANALYZER_NONNULL = YES; 306 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_ENABLE_OBJC_WEAK = YES; 312 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 313 | CLANG_WARN_BOOL_CONVERSION = YES; 314 | CLANG_WARN_COMMA = YES; 315 | CLANG_WARN_CONSTANT_CONVERSION = YES; 316 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 317 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 318 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INFINITE_RECURSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 325 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 326 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 328 | CLANG_WARN_STRICT_PROTOTYPES = YES; 329 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 330 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | CODE_SIGN_IDENTITY = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu11; 339 | GCC_NO_COMMON_BLOCKS = YES; 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 347 | MTL_ENABLE_DEBUG_INFO = NO; 348 | MTL_FAST_MATH = YES; 349 | SDKROOT = iphoneos; 350 | VALIDATE_PRODUCT = YES; 351 | }; 352 | name = Release; 353 | }; 354 | E393703121DAF6380012235D /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | buildSettings = { 357 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 358 | CODE_SIGN_STYLE = Automatic; 359 | DEVELOPMENT_TEAM = 327979M4M2; 360 | INFOPLIST_FILE = locusDemo/Info.plist; 361 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | ); 366 | PRODUCT_BUNDLE_IDENTIFIER = com.niuniu.locus; 367 | PRODUCT_NAME = "$(TARGET_NAME)"; 368 | TARGETED_DEVICE_FAMILY = "1,2"; 369 | }; 370 | name = Debug; 371 | }; 372 | E393703221DAF6380012235D /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_STYLE = Automatic; 377 | DEVELOPMENT_TEAM = 327979M4M2; 378 | INFOPLIST_FILE = locusDemo/Info.plist; 379 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 380 | LD_RUNPATH_SEARCH_PATHS = ( 381 | "$(inherited)", 382 | "@executable_path/Frameworks", 383 | ); 384 | PRODUCT_BUNDLE_IDENTIFIER = com.niuniu.locus; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Release; 389 | }; 390 | /* End XCBuildConfiguration section */ 391 | 392 | /* Begin XCConfigurationList section */ 393 | E393701521DAF6370012235D /* Build configuration list for PBXProject "locus" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | E393702E21DAF6380012235D /* Debug */, 397 | E393702F21DAF6380012235D /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | E393703021DAF6380012235D /* Build configuration list for PBXNativeTarget "locus" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | E393703121DAF6380012235D /* Debug */, 406 | E393703221DAF6380012235D /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | /* End XCConfigurationList section */ 412 | }; 413 | rootObject = E393701221DAF6370012235D /* Project object */; 414 | } 415 | --------------------------------------------------------------------------------