Skip to content

Commit

Permalink
windows: Add support for arm64
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Aug 25, 2024
1 parent 79126f0 commit 9df97f9
Show file tree
Hide file tree
Showing 14 changed files with 504 additions and 347 deletions.
52 changes: 48 additions & 4 deletions compat/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import sys
import tempfile
import traceback
from typing import Any, Literal, Mapping, Optional, Sequence
from typing import Any, Literal, Mapping, Optional, Sequence, Tuple


REPO_ROOT = Path(__file__).resolve().parent.parent
Expand Down Expand Up @@ -140,16 +140,19 @@ def setup(role: Role,
compat = set()
else:
summary = "enabled by user"
missing: list[MissingFeature] = []

if "native" in compat:
have_toolchain = True
other_label: Optional[str] = None
other_triplet: Optional[str] = None
extra_environ: dict[str, str] = {}

if host_os == "windows" and host_arch == "x86_64" and host_config == "mingw":
other_triplet = "i686-w64-mingw32"
have_toolchain = shutil.which(other_triplet + "-gcc") is not None
other_label = "x86"
have_toolchain, other_triplet = detect_mingw_toolchain_for("x86")
elif host_os == "linux" and host_arch == "x86_64" and host_config is None:
other_label = "x86"
other_triplet = "i686-linux-gnu"
have_toolchain = shutil.which(other_triplet + "-gcc") is not None
if not have_toolchain:
Expand All @@ -173,7 +176,7 @@ def setup(role: Role,
if not have_toolchain:
if not auto_detect:
raise ToolchainNotFoundError(f"unable to locate toolchain for {other_triplet}")
summary = "disabled due to missing toolchain for {other_triplet}"
missing.append(MissingFeature(other_label, other_triplet))

if host_os == "windows" and host_arch == "x86_64" and have_toolchain:
group = OutputGroup("x86", other_triplet, extra_environ)
Expand Down Expand Up @@ -269,6 +272,28 @@ def setup(role: Role,
]

if "emulated" in compat:
if host_os == "windows" and host_arch == "arm64":
for kind, emulated_arch in [("modern", "x86_64"), ("legacy", "x86")]:
if host_config == "mingw":
found, emulated_triplet = detect_mingw_toolchain_for(emulated_arch)
if not found:
if not auto_detect:
raise ToolchainNotFoundError(f"unable to locate toolchain for {emulated_triplet}")
missing.append(MissingFeature(emulated_arch, emulated_triplet))
continue
else:
emulated_triplet = None
outputs[OutputGroup(emulated_arch, emulated_triplet, extra_environ)] = [
Output(identifier=f"helper_emulated_{kind}",
name=HELPER_FILE_WINDOWS.name.replace(".exe", f"-{emulated_arch}.exe"),
file=HELPER_FILE_WINDOWS,
target=HELPER_TARGET),
Output(identifier=f"agent_emulated_{kind}",
name=AGENT_FILE_WINDOWS.name.replace(".dll", f"-{emulated_arch}.dll"),
file=AGENT_FILE_WINDOWS,
target=AGENT_TARGET),
]

if host_os == "android" and host_arch in {"x86_64", "x86"}:
outputs[OutputGroup("arm")] = [
Output(identifier="agent_emulated_legacy",
Expand All @@ -290,6 +315,8 @@ def setup(role: Role,
state = State(role, builddir, top_builddir, frida_version, host_os, host_config, allowed_prebuilds, outputs)
serialized_state = base64.b64encode(pickle.dumps(state)).decode('ascii')

if missing:
summary = ", ".join([f"{m.label} disabled due to missing toolchain for {m.triplet}" for m in missing])
variable_names, output_names = zip(*[(output.identifier, output.name) \
for output in itertools.chain.from_iterable(outputs.values())])
print("ok")
Expand Down Expand Up @@ -349,6 +376,12 @@ class Output:
target: str


@dataclass
class MissingFeature:
label: str
triplet: str


def compile(privdir: Path, state: State):
releng_location = query_releng_location(state.role)
subprojects = detect_relevant_subprojects(releng_location)
Expand Down Expand Up @@ -589,6 +622,12 @@ def configure_import_path(releng_location: Path):
sys.path.insert(0, str(releng_location.parent))


def detect_mingw_toolchain_for(arch: str) -> Tuple[bool, Optional[str]]:
triplet = MINGW_ARCHS.get(arch, arch) + "-w64-mingw32"
found = shutil.which(triplet + "-gcc") is not None
return (found, triplet)


STATE_FILENAME = "state.dat"
DEPFILE_FILENAME = "compat.deps"

Expand Down Expand Up @@ -616,6 +655,11 @@ def configure_import_path(releng_location: Path):
"LIB",
}

MINGW_ARCHS = {
"x86": "i686",
"arm64": "aarch64",
}


if __name__ == "__main__":
main(sys.argv)
3 changes: 3 additions & 0 deletions compat/meson.build
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
helper_modern = get_option('helper_modern')
helper_legacy = get_option('helper_legacy')
helper_compat = ''
helper_emulated_modern = get_option('helper_emulated_modern')
helper_emulated_legacy = get_option('helper_emulated_legacy')
helper_depends = []

agent_modern = get_option('agent_modern')
Expand All @@ -18,6 +20,7 @@ server_depends = []

no_overridden_compat_bits = \
helper_modern == 'auto' and helper_legacy == 'auto' \
and helper_emulated_modern == 'auto' and helper_emulated_legacy == 'auto' \
and agent_modern == 'auto' and agent_legacy == 'auto' \
and agent_emulated_modern == 'auto' and agent_emulated_legacy == 'auto'

Expand Down
16 changes: 14 additions & 2 deletions meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,25 @@ option('compat',
option('helper_modern',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for use on modern systems'
description: 'Prebuilt frida-helper to embed for supporting modern targets'
)

option('helper_legacy',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for use on legacy systems'
description: 'Prebuilt frida-helper to embed for supporting legacy targets'
)

option('helper_emulated_modern',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for supporting modern emulated targets'
)

option('helper_emulated_legacy',
type: 'string',
value: 'auto',
description: 'Prebuilt frida-helper to embed for supporting legacy emulated targets'
)

option('agent_modern',
Expand Down
58 changes: 41 additions & 17 deletions src/embed-agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import shutil
import subprocess
import sys
import struct


def main(argv):
Expand All @@ -27,29 +28,36 @@ def main(argv):

embedded_assets = []
if host_os == "windows":
for agent, flavor in [(agent_modern, "64"),
(agent_legacy, "32")]:
embedded_agent = priv_dir / f"frida-agent-{flavor}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{flavor}.dll"
embedded_symsrv = priv_dir / f"symsrv-{flavor}.dll"
pending_archs = {"arm64", "x86_64", "x86"}
for agent in {agent_modern, agent_legacy, agent_emulated_modern, agent_emulated_legacy}:
if agent is None:
continue
arch = detect_pefile_arch(agent)
embedded_agent = priv_dir / f"frida-agent-{arch}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{arch}.dll"
embedded_symsrv = priv_dir / f"symsrv-{arch}.dll"

if agent is not None:
shutil.copy(agent, embedded_agent)
shutil.copy(agent, embedded_agent)

if agent_dbghelp_prefix is not None:
shutil.copy(agent_dbghelp_prefix / flavor / "dbghelp.dll", embedded_dbghelp)
else:
embedded_dbghelp.write_bytes(b"")
if agent_dbghelp_prefix is not None:
shutil.copy(agent_dbghelp_prefix / arch / "dbghelp.dll", embedded_dbghelp)
else:
embedded_dbghelp.write_bytes(b"")

if agent_symsrv_prefix is not None:
shutil.copy(agent_symsrv_prefix / flavor / "symsrv.dll", embedded_symsrv)
else:
embedded_symsrv.write_bytes(b"")
if agent_symsrv_prefix is not None:
shutil.copy(agent_symsrv_prefix / arch / "symsrv.dll", embedded_symsrv)
else:
for f in [embedded_agent, embedded_dbghelp, embedded_symsrv]:
f.write_bytes(b"")
embedded_symsrv.write_bytes(b"")

embedded_assets += [embedded_agent, embedded_dbghelp, embedded_symsrv]
pending_archs.remove(arch)
for missing_arch in pending_archs:
embedded_agent = priv_dir / f"frida-agent-{missing_arch}.dll"
embedded_dbghelp = priv_dir / f"dbghelp-{missing_arch}.dll"
embedded_symsrv = priv_dir / f"symsrv-{missing_arch}.dll"
for asset in {embedded_agent, embedded_dbghelp, embedded_symsrv}:
asset.write_bytes(b"")
embedded_assets += [asset]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
embedded_agent = priv_dir / "frida-agent.dylib"
if agent_modern is not None and agent_legacy is not None:
Expand Down Expand Up @@ -103,5 +111,21 @@ def pop_cmd_array_arg(args):
return result


def detect_pefile_arch(location):
with location.open(mode="rb") as pe:
pe.seek(0x3c)
e_lfanew, = struct.unpack("<I", pe.read(4))
pe.seek(e_lfanew + 4)
machine, = struct.unpack("<H", pe.read(2))
return PE_MACHINES[machine]


PE_MACHINES = {
0x014c: "x86",
0x8664: "x86_64",
0xaa64: "arm64",
}


if __name__ == "__main__":
main(sys.argv)
43 changes: 37 additions & 6 deletions src/embed-helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import shutil
import subprocess
import sys
import struct


def main(argv):
Expand All @@ -14,12 +15,28 @@ def main(argv):
output_dir = Path(args.pop(0))
priv_dir = Path(args.pop(0))
resource_config = args.pop(0)
helper_modern, helper_legacy = [Path(p) if p else None for p in args[:2]]
helper_modern, helper_legacy, \
helper_emulated_modern, helper_emulated_legacy \
= [Path(p) if p else None for p in args[:4]]

priv_dir.mkdir(exist_ok=True)

embedded_assets = []
if host_os in {"macos", "ios", "watchos", "tvos"}:
if host_os == "windows":
pending_archs = {"arm64", "x86_64", "x86"}
for helper in {helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy}:
if helper is None:
continue
arch = detect_pefile_arch(helper)
embedded_helper = priv_dir / f"frida-helper-{arch}.exe"
shutil.copy(helper, embedded_helper)
embedded_assets += [embedded_helper]
pending_archs.remove(arch)
for missing_arch in pending_archs:
embedded_helper = priv_dir / f"frida-helper-{missing_arch}.exe"
embedded_helper.write_bytes(b"")
embedded_assets += [embedded_helper]
elif host_os in {"macos", "ios", "watchos", "tvos"}:
embedded_helper = priv_dir / "frida-helper"

if helper_modern is not None and helper_legacy is not None:
Expand All @@ -34,10 +51,8 @@ def main(argv):

embedded_assets += [embedded_helper]
else:
exe_suffix = ".exe" if host_os == "windows" else ""

embedded_helper_modern = priv_dir / f"frida-helper-64{exe_suffix}"
embedded_helper_legacy = priv_dir / f"frida-helper-32{exe_suffix}"
embedded_helper_modern = priv_dir / f"frida-helper-64"
embedded_helper_legacy = priv_dir / f"frida-helper-32"

if helper_modern is not None:
shutil.copy(helper_modern, embedded_helper_modern)
Expand Down Expand Up @@ -74,5 +89,21 @@ def pop_cmd_array_arg(args):
return result


def detect_pefile_arch(location):
with location.open(mode="rb") as pe:
pe.seek(0x3c)
e_lfanew, = struct.unpack("<I", pe.read(4))
pe.seek(e_lfanew + 4)
machine, = struct.unpack("<H", pe.read(2))
return PE_MACHINES[machine]


PE_MACHINES = {
0x014c: "x86",
0x8664: "x86_64",
0xaa64: "arm64",
}


if __name__ == "__main__":
main(sys.argv)
20 changes: 16 additions & 4 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ if have_local_backend
'@INPUT0@',
]

if helper_emulated_modern == 'auto'
helper_emulated_modern = ''
endif

if helper_emulated_legacy == 'auto'
helper_emulated_legacy = ''
endif

if host_os_family == 'windows'
backend_sources += [
'windows' / 'windows-host-session.vala',
Expand All @@ -54,14 +62,18 @@ if have_local_backend
'windows' / 'frida-helper-process-glue.c',
'windows' / 'access-helpers.c',
]
backend_vala_args += '--pkg=frida-gum-windows-1.0'

helper_backend_sources = [
'windows' / 'frida-helper-backend.vala',
'windows' / 'frida-helper-backend-glue.c',
'windows' / 'frida-helper-types.vala',
'windows' / 'wait-handle-source.c',
]
helper_backend_vala_args = base_vala_args
helper_backend_vala_args = [
base_vala_args,
'--pkg=frida-gum-windows-1.0',
]
helper_backend = static_library('frida-helper-backend', helper_backend_sources,
vala_args: helper_backend_vala_args,
c_args: frida_component_cflags,
Expand Down Expand Up @@ -105,7 +117,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
Expand Down Expand Up @@ -253,7 +265,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
Expand Down Expand Up @@ -406,7 +418,7 @@ if have_local_backend
'frida-data-helper-process.c',
'frida-data-helper-process-blob' + resource_blob_extension,
],
command: embed_helper + [helper_modern, helper_legacy],
command: embed_helper + [helper_modern, helper_legacy, helper_emulated_modern, helper_emulated_legacy],
depends: helper_depends,
)
backend_sources += [helper_process_data]
Expand Down
Loading

0 comments on commit 9df97f9

Please sign in to comment.