Skip to content

release: sync develop into master - #9

Merged
tkgstrator merged 7 commits into
masterfrom
develop
Jun 23, 2026
Merged

release: sync develop into master#9
tkgstrator merged 7 commits into
masterfrom
develop

Conversation

@tkgstrator

Copy link
Copy Markdown
Contributor

Promote develop → master, including:

🤖 Generated with Claude Code

tkgstrator and others added 7 commits June 22, 2026 10:53
Add logserver.h / logserver.m that binds 0.0.0.0:18082 in debug builds
(FINAL_RELEASE undefined). Operators can tail live logs from any PC on
the same network with `nc <device-ip> 18082` — no SSH or Files.app needed.

- logserver.h: public API (IPALogServerStart / IPALogServerPush)
- logserver.m: dispatch-queue serial server, fans out to up to
  IPA_LOG_SERVER_MAX_CLIENTS (4) simultaneous readers
- logging.m: call IPALogServerStart() in IPALoggingInit() and
  IPALogServerPush() in IPALog(), both guarded by #ifndef FINAL_RELEASE
- logging.h: document the new debug destination in the header comment

FINAL_RELEASE=1 strips the entire TCP sink at compile time, leaving
the existing NSLog / os_log / sandbox-file destinations untouched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
add nc <device-ip> 18082 tail example and note that FINAL_RELEASE compiles the stream out
…#3)

Cross-tweak reference for picking the right cave shape and wiring both
sides correctly. Until now the observer / entry split lived only as
folklore in consumer recipes (Bridge, KiouForge); writing it down here
keeps Chinlan as the canonical source for the cross-tweak contract that
the runtime's IPAChinlanResolveOrig already implies.

- docs/CAVES.md (new):
  * Kinds at a glance — capability matrix covering override return,
    register substitution, W6 clobber, shared dispatcher vs per-site
    slot.
  * Decision flow — when observer is enough and when entry is required.
  * Annotated 21-insn / 84-byte layouts side-by-side so the +0x4C
    bypass-entry contract that both kinds preserve is obvious.
  * End-to-end recipe / hook / dispatcher examples for both kinds plus
    an entry-cave argument-substitution variant.
  * Common pitfalls — W6 clobber, cave-order vs bypass-index coupling,
    bss locality requirement for entry slot tables, the
    KIOU_CALL_ORIG_RET-drops-varargs trap on chinlan builds.

- README.md: short "Cave kinds" section pointing at the new page so
  consumers landing on the repo top see the link without scrolling.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
)

Replaces the previous "single append-only <tag>.log" with a size-bounded
rotation scheme so a long-running consumer can't fill the sandbox with a
multi-GB log.

- Files now live under <base>/Logs/ (created on init), so an operator
  can grab the whole rotated set (<tag>.log + <tag>.{1..N-1}.log) by
  copying one directory instead of fishing individual files out.
  PascalCase matches iOS's own sandbox conventions (Documents/,
  Library/, etc.). Base stays the existing tmp/ or, with
  IPA_LOG_TO_DOCUMENTS=1, the Files.app-visible Documents/.
- IPALogPath samples the current size every IPA_LOG_ROTATE_CHECK_EVERY
  writes (default 64) and, once it crosses IPA_LOG_MAX_BYTES (default
  4 MiB), shifts <tag>.log -> <tag>.1.log -> ... -> <tag>.{N-1}.log,
  dropping anything past N-1. N defaults to 3 generations (so up to
  12 MiB on disk per consumer at the default ceiling).
- All three knobs (max bytes, generation count, sample interval) are
  -D overridable at build time so a noisy consumer can dial up retention
  without forking this file.

Best-effort throughout: failed mkdir falls back to writing into the
parent directory, and rotation runs without an explicit lock — the
sampling cadence already keeps two concurrent writers from both
rotating in the same window, and a stray double-rotate just produces
an empty .1.log instead of corrupting data.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Three review nits from #3 plus one extra ABI wording fix:

- Unify the ADRP/LDR placeholder names in both cave diagrams. The pair
  previously read `page(HOOK_SLOT_RVA) + lo12(SLOT)` and
  `page(entry_slot_va) + lo12(slot)`; using two names for the same
  address obscures the relocation pattern.
- Fix the inline code that was broken across a hard line wrap
  (`-Werror=unused-` / `variable`) so Markdown actually renders the
  flag as code instead of opening an unterminated backtick span.
- Tighten the AAPCS64 wording: W9 isn't an arg-9 slot. The integer
  argument sequence ends at x7, x8 is the indirect-result register,
  and x9–x15 are call-clobbered scratch — which is exactly why
  touching W9 from the entry cave is safe.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
When a client connects to the TCP log server, it now receives the last
IPA_LOG_REPLAY_BYTES (default 100 KB) of the sandbox log file before
switching to the live stream.  This avoids the race where logs written
at process startup — including login-time crashes — are lost because no
nc session was open yet.

Implementation:
- ls_replay_to(fd): opens the log file, seeks to max(0, size - 100KB),
  skips to the next newline to avoid a partial first line, then streams
  the remainder synchronously before the client is admitted to g_clients[].
- IPALogServerSetReplayPath(NSString *): dispatched onto g_queue so
  g_replayPath access stays single-threaded.
- IPALoggingInit() calls IPALogServerSetReplayPath(g_logSandbox) once
  the path is finalised (after IPALogServerStart, before first IPALog).
- Knob: -D IPA_LOG_REPLAY_BYTES=N to override at build time.
- No change to FINAL_RELEASE builds (replay code compiled out with the
  rest of logserver).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 23, 2026 16:50
@tkgstrator
tkgstrator merged commit a43499b into master Jun 23, 2026
7 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Promotes develop into master, bringing in recent runtime logging improvements, new cave-layout documentation, and a CI guard to enforce the develop→master release flow.

Changes:

  • Add a debug-only LAN TCP log streaming server with optional “replay tail on connect”.
  • Update sandbox file logging to write under a Logs/ subdirectory and rotate files by size.
  • Add master-PR source-branch guard in CI and expand documentation (README + new docs/CAVES.md).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
README.md Documents the new TCP log stream + cave kinds and build flags.
logserver.m Implements the debug-only TCP log streaming server with client fanout and replay.
logserver.h Declares the debug-only logserver API (compiled out under FINAL_RELEASE).
logging.m Adds log rotation + Logs/ subdir handling and forwards logs to the TCP stream in non-final builds.
logging.h Documents the debug-only TCP stream behavior.
docs/CAVES.md Adds detailed documentation for observer vs entry cave shapes and wiring.
.github/workflows/integration.yaml Adds CI job rejecting PRs to master unless the source branch is develop.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md
Comment on lines 147 to +149
| `IPA_JAILED` | `hookengine.h` uses Dobby (statically linked) instead of `libsubstrate`. |
| `IPA_LOG_TO_DOCUMENTS` | `logging.m` writes the file log to `<sandbox>/Documents/<tag>.log` instead of `tmp/`. |
| `FINAL_RELEASE` | `logging.m` / `logserver.m` remove the LAN TCP log stream entirely; only NSLog, `os_log`, and the sandbox file sink remain. |
Comment thread README.md
Comment on lines +64 to +68
every log line to NSLog, `os_log` (subsystem-scoped), an append-only
file inside the app sandbox, and — when `FINAL_RELEASE` is not defined —
a LAN-visible TCP log stream on `0.0.0.0:18082`. `IPA_LOG_TO_DOCUMENTS=1`
at build time routes the file destination to `<sandbox>/Documents/` so
Files.app can read it on a non-jailbroken device. The TCP stream can be
Comment thread logging.m
Comment on lines +112 to +115
static void IPAMaybeRotate(NSString *path) {
unsigned n = atomic_fetch_add_explicit(&g_writeCount, 1, memory_order_relaxed);
if ((n % IPA_LOG_ROTATE_CHECK_EVERY) != 0) return;

Comment thread logserver.m
Comment on lines +83 to +96
// Send all bytes to fd. Returns NO and closes fd on any error.
static BOOL ls_send_all(int fd, const uint8_t *buf, size_t len) {
size_t off = 0;
while (off < len) {
ssize_t n = send(fd, buf + off, len - off, 0);
if (n < 0) {
if (errno == EINTR) continue;
return NO;
}
if (n == 0) return NO;
off += (size_t)n;
}
return YES;
}
Comment thread logserver.m
Comment on lines +217 to +221
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
IPALog([NSString stringWithFormat:@"[LOGSVR] socket errno=%d", errno]);
return;
}
Comment thread logserver.m
Comment on lines +230 to +235
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
IPALog([NSString stringWithFormat:@"[LOGSVR] bind errno=%d port=%u",
errno, (unsigned)port]);
close(s);
return;
}
Comment thread logserver.m
Comment on lines +236 to +240
if (listen(s, IPA_LOG_SERVER_MAX_CLIENTS) < 0) {
IPALog([NSString stringWithFormat:@"[LOGSVR] listen errno=%d", errno]);
close(s);
return;
}
tkgstrator added a commit that referenced this pull request Jul 27, 2026
release: sync develop into master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants