Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions StikDebug.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -448,14 +448,15 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = XXK735HX49;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/StikJIT/Sources",
"$(PROJECT_DIR)/StikJIT/idevice",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = StikJIT/Info.plist;
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
Expand Down Expand Up @@ -490,7 +491,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h";
SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/StikJIT/idevice";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -509,14 +510,15 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = XXK735HX49;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/StikJIT/Sources",
"$(PROJECT_DIR)/StikJIT/idevice",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = StikJIT/Info.plist;
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
Expand Down Expand Up @@ -551,7 +553,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "StikJIT/StikJIT-Bridging-Header.h";
SWIFT_INCLUDE_PATHS = "$(inherited) $(PROJECT_DIR)/StikJIT/idevice";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
XROS_DEPLOYMENT_TARGET = 2.2;
Expand Down
126 changes: 0 additions & 126 deletions StikJIT/JSSupport/IDeviceJSBridgeDebugProxy.m

This file was deleted.

161 changes: 161 additions & 0 deletions StikJIT/JSSupport/JSDebugSupport.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//
// JSDebugSupport.swift
// StikDebug
//
// Created by Stephen on 2026/3/30.
//

import Foundation
import JavaScriptCore
import idevice

private func jsException(_ message: String, in context: JSContext?) {
guard let context else { return }
context.exception = JSValue(object: message, in: context)
}

private func describeIdeviceError(_ ffiError: UnsafeMutablePointer<IdeviceFfiError>) -> String {
if let message = ffiError.pointee.message {
return "error code \(ffiError.pointee.code), msg \(String(cString: message))"
}
return "error code \(ffiError.pointee.code)"
}

func handleJSContextSendDebugCommand(_ context: JSContext?, _ commandStr: String, _ debugProxy: OpaquePointer?) -> String? {
guard let debugProxy else {
jsException("debug proxy is unavailable", in: context)
return nil
}

guard let command = debugserver_command_new(commandStr, nil, 0) else {
jsException("failed to allocate debugserver command", in: context)
return nil
}

var response: UnsafeMutablePointer<CChar>?
let ffiError = debug_proxy_send_command(debugProxy, command, &response)
debugserver_command_free(command)

if let ffiError {
jsException(describeIdeviceError(ffiError), in: context)
idevice_error_free(ffiError)
if let response {
idevice_string_free(response)
}
return nil
}

defer {
if let response {
idevice_string_free(response)
}
}

guard let response else { return nil }
return String(cString: response)
}

private func hexCharacter(for value: UInt8) -> UInt8 {
if value < 10 {
return value + Character("0").asciiValue!
}
return value + 87
}

private func fillAddress(into buffer: inout [UInt8], at index: Int, address: UInt64) {
let masks: [UInt64] = [
0xf00000000,
0x0f0000000,
0x00f000000,
0x000f00000,
0x0000f0000,
0x00000f000,
0x000000f00,
0x0000000f0,
0x00000000f,
]

for (offset, mask) in masks.enumerated() {
let shift = UInt64((masks.count - 1 - offset) * 4)
let nibble = UInt8((address & mask) >> shift)
buffer[index + offset] = hexCharacter(for: nibble)
}
}

private func writeChecksum(into buffer: inout [UInt8], at startIndex: Int) {
var checksum: UInt8 = 0
var index = startIndex
while buffer[index] != Character("#").asciiValue! {
checksum &+= buffer[index]
index += 1
}

buffer[index + 1] = hexCharacter(for: (checksum & 0xf0) >> 4)
buffer[index + 2] = hexCharacter(for: checksum & 0x0f)
}

private func makeBulkWriteCommands(startAddress: UInt64, pageSize: UInt64) -> [UInt8] {
let commandCount = Int(pageSize >> 14)
var buffer = [UInt8](repeating: 0, count: commandCount * 19)

var currentAddress = startAddress
for commandIndex in 0..<commandCount {
let start = commandIndex * 19
buffer[start + 0] = Character("$").asciiValue!
buffer[start + 1] = Character("M").asciiValue!
fillAddress(into: &buffer, at: start + 2, address: currentAddress)
buffer[start + 11] = Character(",").asciiValue!
buffer[start + 12] = Character("1").asciiValue!
buffer[start + 13] = Character(":").asciiValue!
buffer[start + 14] = Character("6").asciiValue!
buffer[start + 15] = Character("9").asciiValue!
buffer[start + 16] = Character("#").asciiValue!
writeChecksum(into: &buffer, at: start + 1)
currentAddress += 16_384
}

return buffer
}

func handleJITPageWrite(_ context: JSContext?, _ startAddr: UInt64, _ jitPagesSize: UInt64, _ debugProxy: OpaquePointer?) -> String? {
guard let debugProxy else {
jsException("debug proxy is unavailable", in: context)
return nil
}

let commandBuffer = makeBulkWriteCommands(startAddress: startAddr, pageSize: jitPagesSize)
let commandCount = Int(jitPagesSize >> 14)
let commandsPerBatch = 128

for batchStart in stride(from: 0, to: commandCount, by: commandsPerBatch) {
let commandsToSend = min(commandsPerBatch, commandCount - batchStart)
let byteOffset = batchStart * 19
let byteCount = commandsToSend * 19

let ffiError = commandBuffer.withUnsafeBytes { rawBuffer -> UnsafeMutablePointer<IdeviceFfiError>? in
let baseAddress = rawBuffer.bindMemory(to: UInt8.self).baseAddress!
return debug_proxy_send_raw(debugProxy, baseAddress.advanced(by: byteOffset), UInt(byteCount))
}

if let ffiError {
jsException(describeIdeviceError(ffiError), in: context)
idevice_error_free(ffiError)
return nil
}

for _ in 0..<commandsToSend {
var response: UnsafeMutablePointer<CChar>?
let ffiError = debug_proxy_read_response(debugProxy, &response)
if let response {
idevice_string_free(response)
}
if let ffiError {
jsException(describeIdeviceError(ffiError), in: context)
idevice_error_free(ffiError)
return nil
}
}
}

return "OK"
}
12 changes: 0 additions & 12 deletions StikJIT/JSSupport/JSSupport.h

This file was deleted.

Loading
Loading