├── 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 | 
2 |
3 |
4 | 
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 | 
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 |
--------------------------------------------------------------------------------