iwa-inspector/misc/dump_registry.ts

73 lines
2.2 KiB
TypeScript
Raw Normal View History

2023-05-17 01:56:27 +00:00
#!/usr/bin/env -S deno run -A
/*! dump_registry.ts (C) 2022-present SheetJS LLC -- https://sheetjs.com */
/*
2023-09-24 19:48:44 +00:00
NOTE: this script requires a SIP-disabled Mac, Numbers, LLDB, and Deno
2023-05-17 01:56:27 +00:00
USAGE: deno run -A https://oss.sheetjs.com/notes/iwa/dump_registry.ts
*/
if(Deno.build.os != "darwin") throw `Must run in macOS!`;
2023-09-24 19:48:44 +00:00
const arch_map = {
"x86_64": "x86_64",
"aarch64": "arm64"
};
if(!arch_map[Deno.build.arch]) throw `Unsupported architecture ${Deno.build.arch}`;
const cmd = Deno?.args?.[0] || "/Applications/Numbers.app/Contents/MacOS/Numbers";
try { Deno.statSync(cmd); } catch(e) { throw `Could not find ${cmd}!`; }
/* test if SIP is disabled */
2023-05-17 01:56:27 +00:00
{
const p = Deno.run({cmd:["csrutil","status"],stdin:"piped",stdout:"piped" });
const [status, stdout] = await Promise.all([ p.status(), p.output() ]);
await p.close();
const data = new TextDecoder().decode(stdout);
2023-09-24 19:48:44 +00:00
if(!data.includes("disabled")) throw `SIP must be disabled!`;
2023-05-17 01:56:27 +00:00
}
2023-09-24 19:48:44 +00:00
/* start debugger */
const p = Deno.run({ cmd: `lldb ${cmd} -a ${arch_map[Deno.build.arch]}`.split(" "), stdin: "piped", stdout: "piped" });
2023-05-17 01:56:27 +00:00
2023-09-24 19:48:44 +00:00
/* run commands */
2023-05-17 01:56:27 +00:00
const doit = (x: string) => p?.stdin?.write(new TextEncoder().encode(x))
const cmds = [
"b -[NSApplication _sendFinishLaunchingNotification]",
"settings set auto-confirm 1",
"breakpoint command add 1.1",
"po [TSPRegistry sharedRegistry]",
"process kill",
"exit",
"DONE",
"run",
];
for(const cmd of cmds) await doit(cmd + "\n");
/* LLDB does not exit normally, setTimeout workaround */
2023-09-24 19:48:44 +00:00
setTimeout(() => p.kill("SIGKILL"), 30000)
2023-05-17 01:56:27 +00:00
2023-09-24 19:48:44 +00:00
/* wait for debugger */
2023-05-17 01:56:27 +00:00
const [status, stdout] = await Promise.all([ p.status(), p.output() ]);
await p.close();
2023-09-24 19:48:44 +00:00
/* search for _messageTypeToPrototypeMap */
2023-05-17 01:56:27 +00:00
const data = new TextDecoder().decode(stdout);
const res = data.match(/_messageTypeToPrototypeMap = {([^]*?)}/m)?.[1];
2023-09-24 19:48:44 +00:00
if(!res) throw `Could not find map!`;
/* extract records and sort by ID */
2023-05-17 01:56:27 +00:00
const rows = res.split(/[\r\n]+/).map(r => r.trim().split(/\s+/)).filter(x => x.length > 1);
rows.sort((l, r) => +l[0] - +r[0]);
2023-09-24 19:48:44 +00:00
/* emit code */
2023-05-17 01:56:27 +00:00
console.log(`export default {`);
rows.forEach(r => {
2023-09-24 19:48:44 +00:00
/* setDeprecatedMessageType */
2023-05-17 01:56:27 +00:00
if(r[3] == "null") return;
console.log(` ${r[0]}: ".${r[3]}",`);
});
console.log(`} as {[key: number]: string};`);