fix(native): select one slice when universal Mach-O slices share a CPU type (#2040)
* fix(native): select one slice when universal Mach-O slices share a CPU type On macOS 27 most system binaries are universal files whose slices share CPU_TYPE_ARM64: arm64e + arm64e.x1 (Calculator, TextEdit), x86_64 + arm64e + arm64e.x1 (/bin/ls), or arm64 + arm64e.x1 (ShortcutDroplet). Target admission names slices by CPU family, so these targets have availableArchitectures ["arm64"] while the file holds two arm64 slices. inspect_macho read that family count as a slice count and ran otool, nm, dyld_info, dwarfdump and vtool without -arch. ShortcutDroplet failed with "Malformed otool load-command output" (40 load commands against ncmds 20). Calculator reported both slices' imports (4138 instead of 2069), nm's "(for architecture ...)" header lines as exports, and no selected slice. selectArchitecture now also filters when lipo lists more than one slice. Its preference is unchanged: the family name, then arm64e, then the first arm64e.<variant>. inspect_native_dispatch_metadata matched FAT slices by CPU type only and refused /bin/ls and TextEdit as "Ambiguous FAT architecture slice". selectMachoSlice now ranks slices of the requested CPU type by base subtype in the same order: arm64 (0, then 1) or x86_64 (3), then arm64e (2), then other variants such as arm64e.x1 in FAT table order. It reports ambiguity only when the top-ranked slices share a subtype. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(native): share Mach-O slice preference across inspections * chore: preserve upstream process capture test during merge --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
parent
b69d20a300
commit
96fc84f1fb
|
|
@ -7,9 +7,13 @@ import {
|
|||
fatImage,
|
||||
machoImage,
|
||||
} from "../artifacts/apple/MachoImage.fixture.js";
|
||||
import { parseMachoLayout } from "./AppleMachoSelection.js";
|
||||
import { parseMachoLayout, selectMachoSlice } from "./AppleMachoSelection.js";
|
||||
import { decodeAppleDispatchMetadata } from "./AppleDispatchMetadata.js";
|
||||
|
||||
/** macOS 27 system binaries ship CPU_SUBTYPE_ARM64E_X1 (12) with the PAC ABI bit. */
|
||||
const ARM64E_X1 = { type: 0x0100000c, subtype: 0x8000000c } as const;
|
||||
const X86_64H = { type: 0x01000007, subtype: 8 } as const;
|
||||
|
||||
describe("native Mach-O slice selection", () => {
|
||||
it("preserves high-bit section-name bytes instead of ASCII-folding metadata names", () => {
|
||||
const segment = Buffer.alloc(152);
|
||||
|
|
@ -68,6 +72,48 @@ describe("native Mach-O slice selection", () => {
|
|||
/not aligned/u,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ layout: "arm64e, arm64e.x1", cpus: [CPU.arm64e, ARM64E_X1], index: 0 },
|
||||
{ layout: "arm64e.x1, arm64e", cpus: [ARM64E_X1, CPU.arm64e], index: 1 },
|
||||
{ layout: "arm64, arm64e.x1", cpus: [CPU.arm64, ARM64E_X1], index: 0 },
|
||||
{ layout: "arm64e.x1, arm64", cpus: [ARM64E_X1, CPU.arm64], index: 1 },
|
||||
{
|
||||
layout: "x86_64, arm64e, arm64e.x1",
|
||||
cpus: [CPU.x86_64, CPU.arm64e, ARM64E_X1],
|
||||
index: 1,
|
||||
},
|
||||
{
|
||||
layout: "x86_64h, x86_64",
|
||||
cpus: [X86_64H, CPU.x86_64],
|
||||
index: 1,
|
||||
architecture: "x86_64",
|
||||
},
|
||||
])(
|
||||
"selects one slice when FAT slices $layout share a CPU type",
|
||||
({ cpus, index, architecture = "arm64" }) => {
|
||||
const fat = Buffer.from(
|
||||
fatImage(cpus.map((cpu) => ({ cpu, bytes: machoImage({ cpu }) }))),
|
||||
);
|
||||
expect(selectMachoSlice(fat, architecture).fatDeclaration).toMatchObject({
|
||||
index,
|
||||
cpuSubtype: cpus[index]?.subtype,
|
||||
});
|
||||
expect(parseMachoLayout(fat, architecture).segments).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects slices of the requested CPU type that share a subtype", () => {
|
||||
const fat = fatImage(
|
||||
[CPU.arm64e, CPU.arm64e].map((cpu) => ({
|
||||
cpu,
|
||||
bytes: machoImage({ cpu }),
|
||||
})),
|
||||
);
|
||||
expect(() => parseMachoLayout(Buffer.from(fat), "arm64")).toThrow(
|
||||
/Ambiguous FAT architecture slice/u,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("native Mach-O fixup load command boundaries", () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import type { FixupCommands } from "./AppleMachoFixups.js";
|
||||
import {
|
||||
MACHO_ARCHITECTURE_POLICIES,
|
||||
baseMachoCpuSubtype,
|
||||
machoSubtypeRank,
|
||||
} from "./MachoArchitectureSelection.js";
|
||||
import {
|
||||
readFatSliceDeclarations,
|
||||
validateFatSlice,
|
||||
type FatSliceDeclaration,
|
||||
} from "../domain/apple/machoContainer.js";
|
||||
|
||||
/** One mapped Mach-O segment with file-backed VA range. */
|
||||
|
|
@ -90,32 +96,44 @@ export const selectMachoSlice = (
|
|||
const headerEnd = 8 + count * stride;
|
||||
if (count > 128 || headerEnd > bytes.length)
|
||||
throw malformed("Malformed FAT architecture table");
|
||||
const cpu = MACHO_CPU_TYPE[architecture];
|
||||
if (cpu === undefined) throw invalid("Requested FAT architecture is absent");
|
||||
const policy = MACHO_ARCHITECTURE_POLICIES[architecture];
|
||||
if (policy === undefined)
|
||||
throw invalid("Requested FAT architecture is absent");
|
||||
const declarations = readFatSliceDeclarations(bytes.subarray(8, headerEnd), {
|
||||
count,
|
||||
wide: fat64,
|
||||
littleEndian,
|
||||
});
|
||||
if (declarations.status !== "parsed") throw malformed(declarations.reason);
|
||||
let selected: MachoSlice | undefined;
|
||||
let best: FatSliceDeclaration | undefined;
|
||||
let bestRank = Number.POSITIVE_INFINITY;
|
||||
let ambiguous = false;
|
||||
for (const declaration of declarations.slices) {
|
||||
const issue = validateFatSlice(declaration, bytes.length, headerEnd);
|
||||
if (issue !== null) throw malformed(issue);
|
||||
if (declaration.cpuType !== cpu) continue;
|
||||
if (selected !== undefined)
|
||||
throw invalid("Ambiguous FAT architecture slice");
|
||||
selected = {
|
||||
slice: declaration.offset,
|
||||
sliceEnd: declaration.offset + declaration.size,
|
||||
fatDeclaration: {
|
||||
...declaration,
|
||||
tableEnd: headerEnd,
|
||||
},
|
||||
};
|
||||
if (declaration.cpuType !== policy.cpuType) continue;
|
||||
const rank = machoSubtypeRank(policy, declaration.cpuSubtype);
|
||||
if (best !== undefined && rank >= bestRank) {
|
||||
// Equal ranks keep FAT table order unless the slices share a subtype.
|
||||
if (
|
||||
rank === bestRank &&
|
||||
baseMachoCpuSubtype(declaration.cpuSubtype) ===
|
||||
baseMachoCpuSubtype(best.cpuSubtype)
|
||||
)
|
||||
ambiguous = true;
|
||||
continue;
|
||||
}
|
||||
best = declaration;
|
||||
bestRank = rank;
|
||||
ambiguous = false;
|
||||
}
|
||||
if (selected === undefined)
|
||||
throw invalid("Requested FAT architecture is absent");
|
||||
if (best === undefined) throw invalid("Requested FAT architecture is absent");
|
||||
if (ambiguous) throw invalid("Ambiguous FAT architecture slice");
|
||||
const selected: MachoSlice = {
|
||||
slice: best.offset,
|
||||
sliceEnd: best.offset + best.size,
|
||||
fatDeclaration: { ...best, tableEnd: headerEnd },
|
||||
};
|
||||
if (selected.slice + 4 > bytes.length)
|
||||
throw malformed("Truncated Mach-O header");
|
||||
const sliceMagic = bytes.readUInt32LE(selected.slice);
|
||||
|
|
@ -126,13 +144,6 @@ export const selectMachoSlice = (
|
|||
return selected;
|
||||
};
|
||||
|
||||
/** CPU types admitted by `machArchitecture` in the domain binary target parser. */
|
||||
const MACHO_CPU_TYPE: Readonly<Record<string, number>> = {
|
||||
x86: 7,
|
||||
x86_64: 0x01000007,
|
||||
arm: 12,
|
||||
arm64: 0x0100000c,
|
||||
};
|
||||
const MH_MAGIC = 0xfeedface;
|
||||
const MH_CIGAM = 0xcefaedfe;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
interface MachoArchitecturePolicy {
|
||||
readonly cpuType: number;
|
||||
readonly subtypes: readonly {
|
||||
readonly subtype: number;
|
||||
readonly name: string;
|
||||
}[];
|
||||
readonly variantName?: RegExp;
|
||||
}
|
||||
|
||||
/** One preference order for FAT subtype identities and Apple tool slice names. */
|
||||
export const MACHO_ARCHITECTURE_POLICIES: Readonly<
|
||||
Record<string, MachoArchitecturePolicy>
|
||||
> = {
|
||||
x86: { cpuType: 7, subtypes: [{ subtype: 3, name: "i386" }] },
|
||||
x86_64: {
|
||||
cpuType: 0x01000007,
|
||||
subtypes: [{ subtype: 3, name: "x86_64" }],
|
||||
},
|
||||
arm: { cpuType: 12, subtypes: [], variantName: /^arm$/u },
|
||||
arm64: {
|
||||
cpuType: 0x0100000c,
|
||||
subtypes: [
|
||||
{ subtype: 0, name: "arm64" },
|
||||
{ subtype: 2, name: "arm64e" },
|
||||
{ subtype: 1, name: "arm64v8" },
|
||||
],
|
||||
variantName: /^arm64e\.[A-Za-z0-9_]+$/u,
|
||||
},
|
||||
};
|
||||
|
||||
/** High subtype bits carry capabilities, such as the arm64e PAC ABI version. */
|
||||
export const baseMachoCpuSubtype = (subtype: number): number =>
|
||||
subtype & 0x00ffffff;
|
||||
|
||||
/** Unlisted subtypes follow the preferred slices in FAT table order. */
|
||||
export const machoSubtypeRank = (
|
||||
policy: MachoArchitecturePolicy,
|
||||
subtype: number,
|
||||
): number => {
|
||||
const rank = policy.subtypes.findIndex(
|
||||
(candidate) => candidate.subtype === baseMachoCpuSubtype(subtype),
|
||||
);
|
||||
return rank < 0 ? policy.subtypes.length : rank;
|
||||
};
|
||||
|
||||
/** Select a tool spelling using the same preference order as FAT selection. */
|
||||
export const selectMachoArchitectureName = (
|
||||
policy: MachoArchitecturePolicy,
|
||||
available: readonly string[],
|
||||
): string | undefined => {
|
||||
for (const { name } of policy.subtypes)
|
||||
if (available.includes(name)) return name;
|
||||
return available.find((name) => policy.variantName?.test(name));
|
||||
};
|
||||
|
|
@ -1,10 +1,18 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
CPU,
|
||||
LC,
|
||||
dylibCommand,
|
||||
fatImage,
|
||||
machoImage,
|
||||
} from "../artifacts/apple/MachoImage.fixture.js";
|
||||
import {
|
||||
AnalysisCancelledError,
|
||||
AnalysisOutputError,
|
||||
} from "../domain/analysisErrorCore.js";
|
||||
import { err, ok } from "../domain/result.js";
|
||||
import { parseMachoLayout, selectMachoSlice } from "./AppleMachoSelection.js";
|
||||
import type { NativeCommandCapture } from "./CommandRunner.js";
|
||||
import { inspectNativeMacho } from "./NativeMachoInspection.js";
|
||||
import {
|
||||
|
|
@ -78,6 +86,56 @@ describe("Mach-O tool architecture selection", () => {
|
|||
"/fixture/app",
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ names: ["arm64v8", "arm64e"], selected: "arm64e" },
|
||||
{ names: ["arm64e", "arm64v8"], selected: "arm64e" },
|
||||
{ names: ["arm64v8", "arm64e", "arm64"], selected: "arm64" },
|
||||
{ names: ["arm64v8"], selected: "arm64v8" },
|
||||
{ names: ["arm64v8", "arm64e.x1"], selected: "arm64v8" },
|
||||
{ names: ["arm64e.x1", "arm64v8"], selected: "arm64v8" },
|
||||
] as const)(
|
||||
"keeps inspection and dispatch on $selected for FAT order $names",
|
||||
async ({ names, selected }) => {
|
||||
const cpus = {
|
||||
arm64: CPU.arm64,
|
||||
arm64v8: { type: CPU.arm64.type, subtype: 1 },
|
||||
arm64e: CPU.arm64e,
|
||||
"arm64e.x1": { type: CPU.arm64.type, subtype: 0x8000000c },
|
||||
};
|
||||
const slices = names.map((name) => {
|
||||
const cpu = cpus[name];
|
||||
return {
|
||||
cpu,
|
||||
bytes: machoImage({
|
||||
cpu,
|
||||
commands: [dylibCommand(LC.LOAD_DYLIB, `/fixture/${name}.dylib`)],
|
||||
}),
|
||||
};
|
||||
});
|
||||
const fat = Buffer.from(fatImage(slices));
|
||||
const lipo = names
|
||||
.map(
|
||||
(name, index) =>
|
||||
`architecture ${name}\n cputype ${cpus[name].type}\n cpusubtype ${cpus[name].subtype}\n offset ${(index + 1) * 4096}\n size ${slices[index]?.bytes.length}\n align 2^12\n`,
|
||||
)
|
||||
.join("");
|
||||
const { commands } = await inspect(lipo, "arm64");
|
||||
expect(commands.find(({ tool }) => tool === "otool")?.args).toEqual([
|
||||
"-h",
|
||||
"-l",
|
||||
"-arch",
|
||||
selected,
|
||||
"/fixture/app",
|
||||
]);
|
||||
expect(selectMachoSlice(fat, "arm64").slice).toBe(
|
||||
(names.findIndex((name) => name === selected) + 1) * 4096,
|
||||
);
|
||||
expect(parseMachoLayout(fat, "arm64").fixups.dylibs).toEqual([
|
||||
`/fixture/${selected}.dylib`,
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("Mach-O UUID reconciliation", () => {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ import {
|
|||
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
import type { NativeCommandCapture } from "./CommandRunner.js";
|
||||
import {
|
||||
MACHO_ARCHITECTURE_POLICIES,
|
||||
selectMachoArchitectureName,
|
||||
} from "./MachoArchitectureSelection.js";
|
||||
import { parseDyldSymbols } from "./parsers/dyldInfo.js";
|
||||
import { parseLipoArchitectures } from "./parsers/lipo.js";
|
||||
import { withoutEchoedPathHeader } from "./parsers/echoedPath.js";
|
||||
|
|
@ -399,23 +403,22 @@ const selectArchitecture = (
|
|||
target: BinaryTarget,
|
||||
available: readonly string[],
|
||||
): ArchitectureSelection => {
|
||||
if (target.kind !== "executable" || target.availableArchitectures.length < 2)
|
||||
// BinaryTarget lists CPU families and lipo lists slices. A universal file
|
||||
// can hold several slices of one family (arm64e and arm64e.x1), and slice
|
||||
// tools without -arch print every slice.
|
||||
if (
|
||||
target.kind !== "executable" ||
|
||||
(target.availableArchitectures.length < 2 && available.length < 2)
|
||||
)
|
||||
return { status: "unfiltered" };
|
||||
const normalized =
|
||||
target.architecture === "x86" ? "i386" : target.architecture;
|
||||
if (available.includes(normalized))
|
||||
return { status: "selected", architecture: normalized };
|
||||
// BinaryTarget intentionally normalizes ARM64 CPU subtypes. Recover the
|
||||
// concrete arm64e slice name from lipo before invoking slice-aware tools.
|
||||
if (normalized === "arm64") {
|
||||
const arm64e = available.find((architecture) => architecture === "arm64e");
|
||||
if (arm64e !== undefined)
|
||||
return { status: "selected", architecture: arm64e };
|
||||
const variant = available.find((architecture) =>
|
||||
/^arm64e\.[A-Za-z0-9_]+$/u.test(architecture),
|
||||
);
|
||||
if (variant !== undefined)
|
||||
return { status: "selected", architecture: variant };
|
||||
}
|
||||
const policy = MACHO_ARCHITECTURE_POLICIES[target.architecture];
|
||||
const selected =
|
||||
policy === undefined
|
||||
? available.find((name) => name === normalized)
|
||||
: selectMachoArchitectureName(policy, available);
|
||||
if (selected !== undefined)
|
||||
return { status: "selected", architecture: selected };
|
||||
return { status: "absent", architecture: normalized };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { expect, it } from "vitest";
|
||||
import { inspectMachoSchema } from "../../../../src/domain/native/nativeInspection.js";
|
||||
import { err } from "../../../../src/domain/result.js";
|
||||
import { NativeCommandFailure } from "../../../../src/native/CommandRunner.js";
|
||||
import {
|
||||
NativeCommandFailure,
|
||||
type NativeCommandRunner,
|
||||
} from "../../../../src/native/CommandRunner.js";
|
||||
import { NativeMacOSProvider } from "../../../../src/native/NativeMacOSProvider.js";
|
||||
import {
|
||||
NativeFixtureRunner,
|
||||
|
|
@ -9,6 +12,35 @@ import {
|
|||
nativeMachoTarget,
|
||||
} from "../../../fixtures/nativeCommands.js";
|
||||
|
||||
/** Replay fixtures, failing any slice command that does not name the expected slice. */
|
||||
const sliceSelectingRunner = (
|
||||
fixtures: NativeFixtureRunner,
|
||||
selected: string,
|
||||
dyldArchitecture: string,
|
||||
calls: {
|
||||
readonly tool: string;
|
||||
readonly arguments_: readonly string[];
|
||||
}[] = [],
|
||||
): NativeCommandRunner => ({
|
||||
run(tool, arguments_) {
|
||||
calls.push({ tool, arguments_ });
|
||||
const expected = tool === "dyld_info" ? dyldArchitecture : selected;
|
||||
if (
|
||||
!["file", "lipo"].includes(tool) &&
|
||||
!arguments_.some(
|
||||
(argument, index) =>
|
||||
argument === expected ||
|
||||
argument === `--arch=${expected}` ||
|
||||
(argument === "-arch" && arguments_[index + 1] === expected),
|
||||
)
|
||||
)
|
||||
return Promise.resolve(
|
||||
err(new NativeCommandFailure(tool, "nonzero-exit", 1)),
|
||||
);
|
||||
return fixtures.run(tool, arguments_);
|
||||
},
|
||||
});
|
||||
|
||||
it("does not attribute the first universal slice's UUID and segments to the selected target", async () => {
|
||||
const singleSlice = await nativeFixture("otool-load.txt");
|
||||
const selected = new NativeFixtureRunner();
|
||||
|
|
@ -77,25 +109,7 @@ it.each([
|
|||
});
|
||||
const client = new NativeMacOSProvider(
|
||||
{},
|
||||
{
|
||||
run(tool, arguments_) {
|
||||
calls.push({ tool, arguments_ });
|
||||
const expected = tool === "dyld_info" ? dyldArchitecture : selected;
|
||||
if (
|
||||
!["file", "lipo"].includes(tool) &&
|
||||
!arguments_.some(
|
||||
(argument, index) =>
|
||||
argument === expected ||
|
||||
argument === `--arch=${expected}` ||
|
||||
(argument === "-arch" && arguments_[index + 1] === expected),
|
||||
)
|
||||
)
|
||||
return Promise.resolve(
|
||||
err(new NativeCommandFailure(tool, "nonzero-exit", 1)),
|
||||
);
|
||||
return fixtures.run(tool, arguments_);
|
||||
},
|
||||
},
|
||||
sliceSelectingRunner(fixtures, selected, dyldArchitecture, calls),
|
||||
"darwin",
|
||||
).createClient(nativeMachoTarget("/owned/universal"));
|
||||
|
||||
|
|
@ -116,6 +130,36 @@ it.each([
|
|||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{ capture: "calculator.txt", selected: "arm64e" },
|
||||
{ capture: "shortcut-droplet.txt", selected: "arm64" },
|
||||
])(
|
||||
"selects one slice when every universal slice has the target's CPU type ($capture)",
|
||||
async ({ capture, selected }) => {
|
||||
const base = nativeMachoTarget("/owned/universal");
|
||||
if (base.kind !== "executable")
|
||||
throw new Error("Expected executable fixture");
|
||||
// Admission names arm64, arm64e and arm64e.x1 slices by one CPU family.
|
||||
const target = { ...base, availableArchitectures: ["arm64"] as const };
|
||||
const fixtures = new NativeFixtureRunner({
|
||||
lipo: await nativeFixture(`lipo-same-cpu/${capture}`),
|
||||
});
|
||||
const result = await new NativeMacOSProvider(
|
||||
{},
|
||||
sliceSelectingRunner(fixtures, selected, selected),
|
||||
"darwin",
|
||||
)
|
||||
.createClient(target)
|
||||
.execute("inspect_macho", {});
|
||||
|
||||
if (!result.ok) throw result.error;
|
||||
expect(result.value.result).toMatchObject({
|
||||
selected_architecture: { name: selected, container_file_offset: 16384 },
|
||||
architectures: { total: 2 },
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("projects universal segment evidence into the selected slice's container offsets", async () => {
|
||||
const client = new NativeMacOSProvider(
|
||||
{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# Universal Mach-O captures whose slices share one CPU type
|
||||
|
||||
Captured on macOS 27.0.1 (26A434), arm64, from two system executables whose
|
||||
FAT slices all use `CPU_TYPE_ARM64`:
|
||||
|
||||
```sh
|
||||
lipo -detailed_info /System/Applications/Calculator.app/Contents/MacOS/Calculator > calculator.txt
|
||||
lipo -detailed_info /System/Library/CoreServices/ShortcutDroplet.app/Contents/MacOS/ShortcutDroplet > shortcut-droplet.txt
|
||||
```
|
||||
|
||||
Calculator holds `arm64e` (subtype `0x80000002`) and `arm64e.x1` (subtype
|
||||
`0x8000000c`); ShortcutDroplet holds `arm64` (subtype `0`) and `arm64e.x1`.
|
||||
Target admission names both files by the single CPU family `arm64`, while lipo
|
||||
lists two slices.
|
||||
|
||||
The executable path on the `Fat header in:` line was replaced with `fixture`,
|
||||
and trailing whitespace (lipo prints `capabilities ` for a slice without
|
||||
capabilities) and the final blank line were removed. Tool fields are otherwise
|
||||
unchanged.
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Fat header in: fixture
|
||||
fat_magic 0xcafebabe
|
||||
nfat_arch 2
|
||||
architecture arm64e
|
||||
cputype CPU_TYPE_ARM64
|
||||
cpusubtype CPU_SUBTYPE_ARM64E
|
||||
capabilities PTR_AUTH_VERSION USERSPACE 0
|
||||
offset 16384
|
||||
size 1727552
|
||||
align 2^14 (16384)
|
||||
architecture arm64e.x1
|
||||
cputype CPU_TYPE_ARM64
|
||||
cpusubtype unknown arm64 cpusubtype
|
||||
capabilities PTR_AUTH_VERSION USERSPACE 0
|
||||
offset 1753088
|
||||
size 1711088
|
||||
align 2^14 (16384)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Fat header in: fixture
|
||||
fat_magic 0xcafebabe
|
||||
nfat_arch 2
|
||||
architecture arm64
|
||||
cputype CPU_TYPE_ARM64
|
||||
cpusubtype CPU_SUBTYPE_ARM64_ALL
|
||||
capabilities
|
||||
offset 16384
|
||||
size 52000
|
||||
align 2^14 (16384)
|
||||
architecture arm64e.x1
|
||||
cputype CPU_TYPE_ARM64
|
||||
cpusubtype unknown arm64 cpusubtype
|
||||
capabilities PTR_AUTH_VERSION USERSPACE 0
|
||||
offset 81920
|
||||
size 52000
|
||||
align 2^14 (16384)
|
||||
Loading…
Reference in New Issue