mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-23 07:02:26 -05:00
108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate SceShellCore lifecycle offsets from a flat ELF directory.
|
|
|
|
Input files must be named ``SceShellCoreXXX.elf``, ``SceShellCoreXXXX.elf`` or
|
|
use an equivalent build suffix such as ``SceShellCore701_00.elf``.
|
|
The last two digits are the minor firmware version; the preceding digits are
|
|
the major version. For example, ``SceShellCore1140.elf`` is firmware 11.40.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from generate_shellcore_offsets import (
|
|
ShellCore,
|
|
TARGET_NAMES,
|
|
firmware_key,
|
|
)
|
|
|
|
|
|
SHELLCORE_NAME = re.compile(r"^SceShellCore(\d{3,4})(?:_\d{2})?\.elf$")
|
|
|
|
|
|
def firmware_files(root: Path) -> list[tuple[int, int, Path]]:
|
|
by_version: dict[tuple[int, int], Path] = {}
|
|
for path in root.iterdir():
|
|
if not path.is_file():
|
|
continue
|
|
match = SHELLCORE_NAME.fullmatch(path.name)
|
|
if match is None:
|
|
continue
|
|
version = match.group(1)
|
|
key = (int(version[:-2]), int(version[-2:]))
|
|
previous = by_version.get(key)
|
|
if previous is not None:
|
|
if previous.read_bytes() != path.read_bytes():
|
|
raise ValueError(
|
|
f"different SceShellCore builds for {key[0]}.{key[1]:02d}: "
|
|
f"{previous.name}, {path.name}"
|
|
)
|
|
if "_" in previous.stem and "_" not in path.stem:
|
|
by_version[key] = path
|
|
continue
|
|
by_version[key] = path
|
|
return [
|
|
(major, minor, by_version[(major, minor)])
|
|
for major, minor in sorted(by_version)
|
|
]
|
|
|
|
|
|
def generate(root: Path) -> str:
|
|
records: list[str] = []
|
|
files = firmware_files(root)
|
|
if not files:
|
|
raise ValueError(f"{root}: no SceShellCore firmware files found")
|
|
for major, minor, path in files:
|
|
firmware_name = f"{major}.{minor:02d}"
|
|
firmware = firmware_key(firmware_name)
|
|
shellcore = ShellCore(path)
|
|
targets = shellcore.locate_targets()
|
|
cave_offset, cave_size = shellcore.bridge_cave()
|
|
records.append(
|
|
" {\n"
|
|
f" .firmware = 0x{firmware:04x}u,\n"
|
|
f" .name = \"{firmware_name}\",\n"
|
|
f" .bridge_cave_offset = 0x{cave_offset:x}u,\n"
|
|
f" .bridge_cave_size = 0x{cave_size:x}u,\n"
|
|
f" .sandbox_call_target_offset = "
|
|
f"0x{targets['sandbox_ready_target']:x}u,\n"
|
|
" .targets = {"
|
|
+ ", ".join(
|
|
"{.offset = "
|
|
f"0x{targets[name]:x}u, .patch_size = "
|
|
f"{5 if name == 'sandbox_ready' else shellcore.patch_size(targets[name])}u}}"
|
|
for name in TARGET_NAMES
|
|
)
|
|
+ "},\n }"
|
|
)
|
|
if not records:
|
|
raise ValueError(f"{root}: no SceShellCore firmware files found")
|
|
return (
|
|
"/* Generated by tools/generate_shellcore_offsets_from_files.py. */\n"
|
|
+ ",\n".join(records)
|
|
+ "\n"
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate offsets from SceShellCoreXXXX.elf files"
|
|
)
|
|
parser.add_argument("root", type=Path, help="directory containing the ELF files")
|
|
parser.add_argument("--output", type=Path)
|
|
args = parser.parse_args()
|
|
output = generate(args.root)
|
|
if args.output:
|
|
with args.output.open("w", encoding="utf-8", newline="\n") as file:
|
|
file.write(output)
|
|
else:
|
|
print(output, end="")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|