Skip to content

Commit

Permalink
meson: Add architecture compatibility automation
Browse files Browse the repository at this point in the history
For supporting targets with a different architecture, such as 32-bit
processes on a 64-bit system.

Up until now this required multiple build directories, and passing in
options to specify where the other helper and agent binaries reside.

This was however quite painful, as it required a meta build system to
automate these steps. Getting incremental builds working reliably was
also quite difficult. It also exposed the user to platform-specific
implementation details.
  • Loading branch information
oleavr committed Mar 27, 2024
1 parent 42bc070 commit 41b87c1
Show file tree
Hide file tree
Showing 8 changed files with 643 additions and 21 deletions.
420 changes: 420 additions & 0 deletions compat/build.py

Large diffs are not rendered by default.

106 changes: 106 additions & 0 deletions compat/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
helper_modern = get_option('helper_modern')
helper_legacy = get_option('helper_legacy')
helper_compat = ''
helper_depends = []

agent_modern = get_option('agent_modern')
agent_legacy = get_option('agent_legacy')
agent_compat = ''
agent_emulated_modern = get_option('agent_emulated_modern')
agent_emulated_legacy = get_option('agent_emulated_legacy')
agent_depends = []

gadget_compat = ''
gadget_depends = []

server_compat = ''
server_depends = []

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

if no_overridden_compat_bits
build_py = [python, files('build.py')]

components = []
if build_gadget
components += 'gadget'
endif
if build_server
components += 'server'
endif

setup_result = run_command(build_py,
'setup',
meson.current_build_dir(),
host_os,
host_abi,
','.join(get_option('compat')),
get_option('assets'),
','.join(components),
check: true
)
setup_output = setup_result.stdout().strip()
if setup_output != ''
tokens = setup_output.split(' ')
varnames = tokens[0].split(',')
outputs = tokens[1].split(',')
depfile = tokens[2]

if host_os_family == 'darwin'
install = false
install_dir = asset_dir
else
install = true
install_dir = []
foreach varname : varnames
if get_option('assets') == 'installed' or varname.startswith('gadget_')
install_dir += varname.endswith('_modern') ? asset_dir_modern : asset_dir_legacy
else
install_dir += false
endif
endforeach
endif

arch_support = custom_target('arch-support',
output: outputs,
command: [
build_py,
'compile',
meson.current_build_dir(),
meson.global_build_root(),
],
depfile: depfile,
install: install,
install_dir: install_dir,
)

i = 0
foreach output : arch_support.to_list()
outpath = output.full_path()
varname = varnames[i]

set_variable(varname, outpath)

if varname.startswith('helper_')
helper_compat = outpath
helper_depends += arch_support
elif varname.startswith('agent_')
agent_compat = outpath
agent_depends += arch_support
elif varname.startswith('gadget_')
gadget_compat = outpath
gadget_depends += arch_support
elif varname.startswith('server_')
server_compat = outpath
server_depends += arch_support
else
assert(false, f'unexpected variable name: @varname@')
endif

i += 1
endforeach
endif
endif
25 changes: 23 additions & 2 deletions lib/agent/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,39 @@ modulated_agent = custom_target('frida-agent-modulated',
command: modulate + operations,
)

need_universal_agent = host_os_family == 'darwin' \
and get_option('assets') == 'installed' \
and agent_depends.length() != 0

if host_os_family == 'darwin'
identity = 'FridaAgent'
else
identity = agent_name
endif
agent = custom_target('frida-agent',
input: modulated_agent,
output: agent_name,
output: need_universal_agent ? f'@agent_name@-@host_abi@' : agent_name,
command: post_process + ['shared-library', identity],
build_by_default: true,
install: get_option('assets') == 'installed',
install: get_option('assets') == 'installed' and not need_universal_agent,
install_dir: asset_dir,
)

agent_dep = declare_dependency(link_with: agent)

if need_universal_agent
custom_target('frida-agent-universal',
input: agent,
output: agent_name,
command: [
lipo,
'@INPUT@',
agent_compat,
'-create',
'-output', meson.current_build_dir() / agent_name,
],
depends: agent_depends,
install: true,
install_dir: asset_dir,
)
endif
25 changes: 22 additions & 3 deletions lib/gadget/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,36 @@ modulated_gadget = custom_target('frida-gadget-modulated',
command: modulate + operations,
)

need_universal_gadget = host_os_family == 'darwin' and gadget_depends.length() != 0

if host_os == 'macos'
identity = '@executable_path/../Frameworks/FridaGadget.dylib'
elif host_os in ['ios', 'tvos']
identity = '@executable_path/Frameworks/FridaGadget.dylib'
else
identity = gadget_name
endif
custom_target('frida-gadget',
gadget = custom_target('frida-gadget',
input: modulated_gadget,
output: gadget_name,
output: need_universal_gadget ? f'@gadget_name@-@host_abi@' : gadget_name,
command: post_process + ['shared-library', identity],
install: true,
install: not need_universal_gadget,
install_dir: asset_dir,
)

if need_universal_gadget
custom_target('frida-gadget-universal',
input: gadget,
output: gadget_name,
command: [
lipo,
'@INPUT@',
gadget_compat,
'-create',
'-output', meson.current_build_dir() / gadget_name,
],
depends: gadget_depends,
install: true,
install_dir: asset_dir,
)
endif
8 changes: 6 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,14 @@ helper_name = 'frida-helper' + exe_suffix
agent_name = 'frida-agent' + shlib_suffix
gadget_name = 'frida-gadget' + shlib_suffix

root_asset_dir = get_option('libdir') / 'frida'
if host_os_family == 'darwin'
asset_dir = get_option('libdir') / 'frida'
asset_dir = root_asset_dir
default_asset_path_template = get_option('prefix') / get_option('libdir') / 'frida'
else
asset_dir = get_option('libdir') / 'frida' / host_cpu_mode
asset_dir = root_asset_dir / host_cpu_mode
asset_dir_modern = root_asset_dir / '64'
asset_dir_legacy = root_asset_dir / '32'
default_asset_path_template = get_option('prefix') / get_option('libdir') / 'frida' / '<arch>'
endif

Expand Down Expand Up @@ -604,6 +607,7 @@ native_vala_flags = [
]
add_project_arguments(native_vala_flags, language: 'vala', native: true)

subdir('compat')
subdir('tools')
subdir('lib')
subdir('src')
Expand Down
9 changes: 9 additions & 0 deletions meson.options
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ option('asset_path_template',
description: 'Override the default installed asset path template'
)

option('compat',
type: 'array',
choices: ['auto', 'disabled', 'native', 'emulated'],
value: ['auto'],
description: 'Support for targets with a different architecture',
)

option('helper_modern',
type: 'string',
value: 'auto',
Expand All @@ -78,11 +85,13 @@ option('agent_legacy',

option('agent_emulated_modern',
type: 'string',
value: 'auto',
description: 'Prebuilt agent to embed for use on modern emulated targets'
)

option('agent_emulated_legacy',
type: 'string',
value: 'auto',
description: 'Prebuilt agent to embed for use on legacy emulated targets'
)

Expand Down
24 changes: 22 additions & 2 deletions server/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,30 @@ raw_server = executable('frida-server-raw', server_sources,
dependencies: [core_dep],
)

custom_target('frida-server',
server_name = 'frida-server' + exe_suffix
need_universal_server = get_option('assets') == 'installed' and server_depends.length() != 0

server = custom_target('frida-server',
input: [raw_server, 'frida-server.xcent'],
output: 'frida-server' + exe_suffix,
output: need_universal_server ? f'@server_name@-@host_abi@' : server_name,
command: post_process + ['executable', 're.frida.Server', '@INPUT1@'],
install: true,
install_dir: get_option('bindir'),
)

if need_universal_server
custom_target('frida-server-universal',
input: server,
output: server_name,
command: [
lipo,
'@INPUT@',
server_compat,
'-create',
'-output', meson.current_build_dir() / server_name
],
depends: server_depends,
install: true,
install_dir: get_option('bindir'),
)
endif
Loading

0 comments on commit 41b87c1

Please sign in to comment.