Skip to content

Instantly share code, notes, and snippets.

View ANRChecker.swift
// Note that this checker is always running, even when the app is in the background (where it doesn't matter if the main thread is blocked)
// You'll have to add more code if you don't want the checker to run while the app is in the background
final class ANRChecker {
private let ANRThreshold: CFTimeInterval = 5
// This variable may be accessed from multiple threads at the same time. It won't cause issues, but if you want prevent the thread sanitizer from complaining, you can add locking around it or w/e
private lazy var lastResponseTime: CFTimeInterval = CACurrentMediaTime()
func beginChecking() {
updateLastResponseTime()
View savings.rb
#!/usr/bin/ruby
=begin
#### DIRECTIONS ####
Run `/usr/bin/ruby savings.rb <path to executable>`, and it will report the estimated savings for that executable.
*However*, the executable cannot have been downloaded from the app store (or else it will already be the encrypted version, and we can't unencrypt it to calculate the savings)
Also, it should be a binary for a specific architecture, and not a fat binary. I'd assume arm64 would be way to go.
How to get an arm64 binary that is not encrypted?
Run Product -> Archive in Xcode, then export the app Ad Hoc, and for the device to thin for, select a device with arm64 (an iPhone 5s or above)
Unzip the .ipa file that was exported, and Payload/<app name>.app/<app name> should be the executable that you want
View a.m
//Copyright (c) 2018 Michael Eisel. All rights reserved.
#import "CLRCallRecorder.h"
#import <dlfcn.h>
#import <libkern/OSAtomicQueue.h>
#import <pthread.h>
typedef struct {
void *ptr;
NSInteger number;
View a.h
//Copyright (c) 2018 Michael Eisel. All rights reserved.
#import <Foundation/Foundation.h>
// Returns all the calls that have been made, in the order that they were made. If a call is made more than once, it just records the first instance.
// Each time this function is called, it returns only the calls that have been made since the last time it was called
extern NSArray <NSString *> *CLRCollectCalls(void);
View replacer.c
#import "fishhook.h" // from https://github.com/facebook/fishhook
// Replace write and writev, the two "chokepoint" functions that writes to stderr and stdout will probably pass through
static int (*originalWritev)(int fd, const struct iovec *v, int n);
static int (*originalWrite)(int fd, const void *buf, size_t size);
void checkForBadConstraintsMessage(int fd, const char *string, size_t size) {
if (strnstr(string, "UIViewAlertForUnsatisfiableConstraints", size)) {
// Write it to the console anyways before crashing
originalWrite(fd, string, size);
View a.swift
func iterateOverViewAndSubviews(view: UIView, block: (UIView) -> Void) {
block(view)
for subview in view.subviews {
iterateOverViewAndSubviews(view: subview, block: block)
}
}
func runCheckers() {
if let keyWindow = UIApplication.shared.keyWindow {
iterateOverViewAndSubviews(view: keyWindow) { (view) in
View a.cpp
void fallback(double d, char *buffer) {
snprintf(buffer, 25, "%0.16e", d);
}
void handleUncommonCases(double d, char *buffer) {
if (std::isinf(d)) {
if (d < 0) {
(*buffer++) = '-';
}
strcpy(buffer, "Infinity");
View instrument.xml
<?xml version="1.0" encoding="UTF-8" ?>
<package>
<id>asdfasdfasd.insto</id>
<title>insto</title>
<owner>
<name>Michael Eisel</name>
</owner>
<import-schema>kdebug-strings</import-schema>
<ktrace-point-schema>
<id>com-eisel-asdf</id>
View args.txt
These are just common sets of args. For your app, it may vary. But these should cover most of the size of the __TEXT segment
For an app with just Objective-C:
-Wl,-rename_section,__TEXT,__text,__MY_TEXT,__text
-Wl,-rename_section,__TEXT,__stubs,__MY_TEXT,__stubs
-Wl,-rename_section,__TEXT,__stub_helper,__MY_TEXT,__stub_helper
-Wl,-rename_section,__TEXT,__objc_classname,__MY_TEXT,__objc_classname
-Wl,-rename_section,__TEXT,__cstring,__MY_TEXT,__cstring
-Wl,-rename_section,__TEXT,__objc_methname,__MY_TEXT,__objc_methname
View Benchmarker.swift
//Copyright (c) 2018 Michael Eisel. All rights reserved.
import Foundation
import QuartzCore
// import IkigaJSON
import ZippyJSON
import os
func dataFromFile(_ file: String) -> Data {
return try! String(contentsOfFile: Bundle.main.path(forResource: file, ofType: nil)!).data(using: .utf8)!