Tanner Bennett лет назад: 7
Родитель
Сommit
1d937777c0

+ 95 - 15
Classes/GlobalStateExplorers/FLEXGlobalsTableViewController.m

@@ -8,6 +8,7 @@
 
 #import "FLEXGlobalsTableViewController.h"
 #import "FLEXUtility.h"
+#import "FLEXRuntimeUtility.h"
 #import "FLEXLibrariesTableViewController.h"
 #import "FLEXClassesTableViewController.h"
 #import "FLEXObjectExplorerViewController.h"
@@ -26,6 +27,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     FLEXGlobalsRowNetworkHistory,
     FLEXGlobalsRowSystemLog,
     FLEXGlobalsRowLiveObjects,
+    FLEXGlobalsRowAddressInspector,
     FLEXGlobalsRowFileBrowser,
     FLEXGlobalsCookies,    
     FLEXGlobalsRowSystemLibraries,
@@ -56,6 +58,7 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     for (FLEXGlobalsRow defaultRowIndex = 0; defaultRowIndex < FLEXGlobalsRowCount; defaultRowIndex++) {
         FLEXGlobalsTableViewControllerEntryNameFuture titleFuture = nil;
         FLEXGlobalsTableViewControllerViewControllerFuture viewControllerFuture = nil;
+        FLEXGlobalsTableViewControllerRowAction rowAction = nil;
 
         switch (defaultRowIndex) {
             case FLEXGlobalsRowAppClasses:
@@ -69,6 +72,49 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                     return classesViewController;
                 };
                 break;
+                
+            case FLEXGlobalsRowAddressInspector:
+                titleFuture = ^NSString *{
+                    return @"🔎 Address Explorer";
+                };
+                
+                rowAction = ^(FLEXGlobalsTableViewController *host) {
+                    NSString *title = @"Explore Object at Address";
+                    NSString *message = @"Paste a hexadecimal address below, starting with '0x'. "
+                    "Use the unsafe option if you need to bypass pointer validation, "
+                    "but know that it may crash the app if the address is invalid.";
+
+                    UIAlertController *addressInput = [UIAlertController alertControllerWithTitle:title
+                                                                                          message:message
+                                                                                   preferredStyle:UIAlertControllerStyleAlert];
+                    void (^handler)(UIAlertAction *) = ^(UIAlertAction *action) {
+                        if (action.style == UIAlertActionStyleCancel) {
+                            [host deselectSelectedRow]; return;
+                        }
+                        NSString *address = addressInput.textFields.firstObject.text;
+                        [host tryExploreAddress:address safely:action.style == UIAlertActionStyleDefault];
+                    };
+                    [addressInput addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+                        NSString *copied = [UIPasteboard generalPasteboard].string;
+                        textField.placeholder = @"0x00000070deadbeef";
+                        // Go ahead and paste our clipboard if we have an address copied
+                        if ([copied hasPrefix:@"0x"]) {
+                            textField.text = copied;
+                            [textField selectAll:nil];
+                        }
+                    }];
+                    [addressInput addAction:[UIAlertAction actionWithTitle:@"Explore"
+                                                                     style:UIAlertActionStyleDefault
+                                                                   handler:handler]];
+                    [addressInput addAction:[UIAlertAction actionWithTitle:@"Unsafe Explore"
+                                                                     style:UIAlertActionStyleDestructive
+                                                                   handler:handler]];
+                    [addressInput addAction:[UIAlertAction actionWithTitle:@"Cancel"
+                                                                     style:UIAlertActionStyleCancel
+                                                                   handler:handler]];
+                    [host presentViewController:addressInput animated:YES completion:nil];
+                };
+                break;
 
             case FLEXGlobalsRowSystemLibraries: {
                 NSString *titleString = @"📚  System Libraries";
@@ -212,10 +258,18 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
                 break;
         }
 
-        NSParameterAssert(titleFuture);
-        NSParameterAssert(viewControllerFuture);
+        NSAssert(viewControllerFuture || rowAction, @"The switch-case above must assign one of these");
+
+        if (viewControllerFuture) {
+            [defaultGlobalEntries addObject:[FLEXGlobalsTableViewControllerEntry
+                                             entryWithNameFuture:titleFuture
+                                             viewControllerFuture:viewControllerFuture]];
+        } else {
+            [defaultGlobalEntries addObject:[FLEXGlobalsTableViewControllerEntry
+                                             entryWithNameFuture:titleFuture
+                                             action:rowAction]];
+        }
 
-        [defaultGlobalEntries addObject:[FLEXGlobalsTableViewControllerEntry entryWithNameFuture:titleFuture viewControllerFuture:viewControllerFuture]];
     }
 
     return defaultGlobalEntries;
@@ -231,6 +285,11 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     return self;
 }
 
+- (void)deselectSelectedRow {
+    NSIndexPath *selected = self.tableView.indexPathForSelectedRow;
+    [self.tableView deselectRowAtIndexPath:selected animated:YES];
+}
+
 #pragma mark - Public
 
 + (void)setApplicationWindow:(UIWindow *)applicationWindow
@@ -247,13 +306,39 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed:)];
 }
 
-#pragma mark -
+#pragma mark - Misc
 
 - (void)donePressed:(id)sender
 {
     [self.delegate globalsViewControllerDidFinish:self];
 }
 
+- (void)tryExploreAddress:(NSString *)addressString safely:(BOOL)safely {
+    NSScanner *scanner = [NSScanner scannerWithString:addressString];
+    unsigned long long hexValue = 0;
+    BOOL didParseAddress = [scanner scanHexLongLong:&hexValue];
+    const void *pointerValue = (void *)hexValue;
+
+    NSString *error = nil;
+
+    if (didParseAddress) {
+        if (safely && ![FLEXRuntimeUtility pointerIsValidObjcObject:pointerValue]) {
+            error = @"The given address is unlikely to be a valid object.";
+        }
+    } else {
+        error = @"Malformed address. Make sure it's not too long and starts with '0x'.";
+    }
+
+    if (!error) {
+        id object = (__bridge id)pointerValue;
+        FLEXObjectExplorerViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:object];
+        [self.navigationController pushViewController:explorer animated:YES];
+    } else {
+        [FLEXUtility alert:@"Uh-oh" message:error from:self];
+        [self deselectSelectedRow];
+    }
+}
+
 #pragma mark - Table Data Helpers
 
 - (FLEXGlobalsTableViewControllerEntry *)globalEntryAtIndexPath:(NSIndexPath *)indexPath
@@ -268,13 +353,6 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     return entry.entryNameFuture();
 }
 
-- (UIViewController *)viewControllerToPushForRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    FLEXGlobalsTableViewControllerEntry *entry = [self globalEntryAtIndexPath:indexPath];
-
-    return entry.viewControllerFuture();
-}
-
 #pragma mark - Table View Data Source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
@@ -302,14 +380,16 @@ typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) {
     return cell;
 }
 
-
 #pragma mark - Table View Delegate
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    UIViewController *viewControllerToPush = [self viewControllerToPushForRowAtIndexPath:indexPath];
-
-    [self.navigationController pushViewController:viewControllerToPush animated:YES];
+    FLEXGlobalsTableViewControllerEntry *entry = [self globalEntryAtIndexPath:indexPath];
+    if (entry.viewControllerFuture) {
+        [self.navigationController pushViewController:entry.viewControllerFuture() animated:YES];
+    } else {
+        entry.rowAction(self);
+    }
 }
 
 @end

+ 7 - 1
Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.h

@@ -6,17 +6,23 @@
 //  Copyright (c) 2014 f. All rights reserved.
 //
 
-#import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
+@class FLEXGlobalsTableViewController;
 
 typedef NSString *(^FLEXGlobalsTableViewControllerEntryNameFuture)(void);
+/// Simply return a view controller to be pushed on the navigation stack
 typedef UIViewController *(^FLEXGlobalsTableViewControllerViewControllerFuture)(void);
+/// Do something like present an alert, then use the host
+/// view controller to present or push another view controller.
+typedef void (^FLEXGlobalsTableViewControllerRowAction)(FLEXGlobalsTableViewController *host);
 
 @interface FLEXGlobalsTableViewControllerEntry : NSObject
 
 @property (nonatomic, readonly, copy) FLEXGlobalsTableViewControllerEntryNameFuture entryNameFuture;
 @property (nonatomic, readonly, copy) FLEXGlobalsTableViewControllerViewControllerFuture viewControllerFuture;
+@property (nonatomic, readonly, copy) FLEXGlobalsTableViewControllerRowAction rowAction;
 
 + (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture;
++ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture action:(FLEXGlobalsTableViewControllerRowAction)rowSelectedAction;
 
 @end

+ 15 - 1
Classes/ObjectExplorers/Controllers/FLEXGlobalsTableViewControllerEntry.m

@@ -10,7 +10,8 @@
 
 @implementation FLEXGlobalsTableViewControllerEntry
 
-+ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture
++ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture
+               viewControllerFuture:(FLEXGlobalsTableViewControllerViewControllerFuture)viewControllerFuture
 {
     NSParameterAssert(nameFuture);
     NSParameterAssert(viewControllerFuture);
@@ -22,4 +23,17 @@
     return entry;
 }
 
++ (instancetype)entryWithNameFuture:(FLEXGlobalsTableViewControllerEntryNameFuture)nameFuture
+                             action:(FLEXGlobalsTableViewControllerRowAction)rowSelectedAction
+{
+    NSParameterAssert(nameFuture);
+    NSParameterAssert(rowSelectedAction);
+
+    FLEXGlobalsTableViewControllerEntry *entry = [[self alloc] init];
+    entry->_entryNameFuture = [nameFuture copy];
+    entry->_rowAction = [rowSelectedAction copy];
+
+    return entry;
+}
+
 @end

+ 1 - 0
Classes/Utility/FLEXObjcInternal.mm

@@ -285,6 +285,7 @@ static BOOL FLEXPointerIsReadable(const void *inPtr)
     // Read the memory
     vm_offset_t readMem = 0;
     mach_msg_type_number_t size = 0;
+    address = (vm_address_t)inPtr;
     error = vm_read(mach_task_self(), address, sizeof(uintptr_t), &readMem, &size);
     if (error != KERN_SUCCESS) {
         // vm_read returned an error