frida 16.2.1 → 16.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BSDmakefile +6 -0
- package/Makefile +16 -0
- package/README.md +14 -11
- package/configure +18 -0
- package/configure.bat +22 -0
- package/dist/native.js +0 -8
- package/lib/application.ts +98 -0
- package/lib/authentication.ts +3 -0
- package/lib/build.py +50 -0
- package/lib/bus.ts +30 -0
- package/lib/cancellable.ts +33 -0
- package/lib/child.ts +15 -0
- package/lib/crash.ts +11 -0
- package/lib/device.ts +329 -0
- package/lib/device_manager.ts +69 -0
- package/lib/endpoint_parameters.ts +56 -0
- package/lib/icon.ts +15 -0
- package/lib/index.ts +311 -0
- package/lib/iostream.ts +78 -0
- package/lib/meson.build +53 -0
- package/lib/native.ts +9 -0
- package/lib/portal_membership.ts +10 -0
- package/lib/portal_service.ts +105 -0
- package/lib/process.ts +57 -0
- package/lib/relay.ts +44 -0
- package/lib/script.ts +352 -0
- package/lib/session.ts +113 -0
- package/lib/signals.ts +45 -0
- package/lib/socket_address.ts +35 -0
- package/lib/spawn.ts +4 -0
- package/lib/system_parameters.ts +78 -0
- package/make.bat +23 -0
- package/meson.build +160 -0
- package/meson.options +11 -0
- package/package.json +27 -6
- package/releng/deps.py +1133 -0
- package/releng/deps.toml +391 -0
- package/releng/devkit-assets/frida-core-example-unix.c +188 -0
- package/releng/devkit-assets/frida-core-example-windows.c +197 -0
- package/releng/devkit-assets/frida-core-example.sln +28 -0
- package/releng/devkit-assets/frida-core-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-core-example.vcxproj.filters +27 -0
- package/releng/devkit-assets/frida-gum-example-unix.c +122 -0
- package/releng/devkit-assets/frida-gum-example-windows.c +132 -0
- package/releng/devkit-assets/frida-gum-example.sln +28 -0
- package/releng/devkit-assets/frida-gum-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-gum-example.vcxproj.filters +27 -0
- package/releng/devkit-assets/frida-gumjs-example-unix.c +84 -0
- package/releng/devkit-assets/frida-gumjs-example-windows.c +91 -0
- package/releng/devkit-assets/frida-gumjs-example.sln +28 -0
- package/releng/devkit-assets/frida-gumjs-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-gumjs-example.vcxproj.filters +27 -0
- package/releng/devkit.py +535 -0
- package/releng/env.py +420 -0
- package/releng/env_android.py +150 -0
- package/releng/env_apple.py +176 -0
- package/releng/env_generic.py +373 -0
- package/releng/frida_version.py +69 -0
- package/releng/machine_file.py +44 -0
- package/releng/machine_spec.py +290 -0
- package/releng/meson/meson.py +27 -0
- package/releng/meson/mesonbuild/__init__.py +0 -0
- package/releng/meson/mesonbuild/_pathlib.py +63 -0
- package/releng/meson/mesonbuild/_typing.py +69 -0
- package/releng/meson/mesonbuild/arglist.py +321 -0
- package/releng/meson/mesonbuild/ast/__init__.py +23 -0
- package/releng/meson/mesonbuild/ast/interpreter.py +441 -0
- package/releng/meson/mesonbuild/ast/introspection.py +374 -0
- package/releng/meson/mesonbuild/ast/postprocess.py +109 -0
- package/releng/meson/mesonbuild/ast/printer.py +620 -0
- package/releng/meson/mesonbuild/ast/visitor.py +161 -0
- package/releng/meson/mesonbuild/backend/__init__.py +0 -0
- package/releng/meson/mesonbuild/backend/backends.py +2047 -0
- package/releng/meson/mesonbuild/backend/ninjabackend.py +3808 -0
- package/releng/meson/mesonbuild/backend/nonebackend.py +26 -0
- package/releng/meson/mesonbuild/backend/vs2010backend.py +2078 -0
- package/releng/meson/mesonbuild/backend/vs2012backend.py +35 -0
- package/releng/meson/mesonbuild/backend/vs2013backend.py +34 -0
- package/releng/meson/mesonbuild/backend/vs2015backend.py +35 -0
- package/releng/meson/mesonbuild/backend/vs2017backend.py +59 -0
- package/releng/meson/mesonbuild/backend/vs2019backend.py +54 -0
- package/releng/meson/mesonbuild/backend/vs2022backend.py +54 -0
- package/releng/meson/mesonbuild/backend/xcodebackend.py +1781 -0
- package/releng/meson/mesonbuild/build.py +3249 -0
- package/releng/meson/mesonbuild/cargo/__init__.py +5 -0
- package/releng/meson/mesonbuild/cargo/builder.py +238 -0
- package/releng/meson/mesonbuild/cargo/cfg.py +274 -0
- package/releng/meson/mesonbuild/cargo/interpreter.py +733 -0
- package/releng/meson/mesonbuild/cargo/manifest.py +227 -0
- package/releng/meson/mesonbuild/cargo/version.py +95 -0
- package/releng/meson/mesonbuild/cmake/__init__.py +28 -0
- package/releng/meson/mesonbuild/cmake/common.py +331 -0
- package/releng/meson/mesonbuild/cmake/data/__init__.py +0 -0
- package/releng/meson/mesonbuild/cmake/data/preload.cmake +82 -0
- package/releng/meson/mesonbuild/cmake/executor.py +241 -0
- package/releng/meson/mesonbuild/cmake/fileapi.py +324 -0
- package/releng/meson/mesonbuild/cmake/generator.py +186 -0
- package/releng/meson/mesonbuild/cmake/interpreter.py +1267 -0
- package/releng/meson/mesonbuild/cmake/toolchain.py +248 -0
- package/releng/meson/mesonbuild/cmake/traceparser.py +814 -0
- package/releng/meson/mesonbuild/cmake/tracetargets.py +161 -0
- package/releng/meson/mesonbuild/compilers/__init__.py +86 -0
- package/releng/meson/mesonbuild/compilers/asm.py +307 -0
- package/releng/meson/mesonbuild/compilers/c.py +788 -0
- package/releng/meson/mesonbuild/compilers/c_function_attributes.py +143 -0
- package/releng/meson/mesonbuild/compilers/compilers.py +1388 -0
- package/releng/meson/mesonbuild/compilers/cpp.py +1035 -0
- package/releng/meson/mesonbuild/compilers/cs.py +136 -0
- package/releng/meson/mesonbuild/compilers/cuda.py +806 -0
- package/releng/meson/mesonbuild/compilers/cython.py +91 -0
- package/releng/meson/mesonbuild/compilers/d.py +861 -0
- package/releng/meson/mesonbuild/compilers/detect.py +1396 -0
- package/releng/meson/mesonbuild/compilers/fortran.py +523 -0
- package/releng/meson/mesonbuild/compilers/java.py +113 -0
- package/releng/meson/mesonbuild/compilers/mixins/__init__.py +0 -0
- package/releng/meson/mesonbuild/compilers/mixins/arm.py +167 -0
- package/releng/meson/mesonbuild/compilers/mixins/ccrx.py +113 -0
- package/releng/meson/mesonbuild/compilers/mixins/clang.py +170 -0
- package/releng/meson/mesonbuild/compilers/mixins/clike.py +1330 -0
- package/releng/meson/mesonbuild/compilers/mixins/compcert.py +117 -0
- package/releng/meson/mesonbuild/compilers/mixins/elbrus.py +93 -0
- package/releng/meson/mesonbuild/compilers/mixins/emscripten.py +89 -0
- package/releng/meson/mesonbuild/compilers/mixins/gnu.py +629 -0
- package/releng/meson/mesonbuild/compilers/mixins/intel.py +167 -0
- package/releng/meson/mesonbuild/compilers/mixins/islinker.py +120 -0
- package/releng/meson/mesonbuild/compilers/mixins/metrowerks.py +279 -0
- package/releng/meson/mesonbuild/compilers/mixins/pgi.py +88 -0
- package/releng/meson/mesonbuild/compilers/mixins/ti.py +130 -0
- package/releng/meson/mesonbuild/compilers/mixins/visualstudio.py +458 -0
- package/releng/meson/mesonbuild/compilers/mixins/xc16.py +111 -0
- package/releng/meson/mesonbuild/compilers/objc.py +120 -0
- package/releng/meson/mesonbuild/compilers/objcpp.py +102 -0
- package/releng/meson/mesonbuild/compilers/rust.py +230 -0
- package/releng/meson/mesonbuild/compilers/swift.py +131 -0
- package/releng/meson/mesonbuild/compilers/vala.py +121 -0
- package/releng/meson/mesonbuild/coredata.py +1532 -0
- package/releng/meson/mesonbuild/dependencies/__init__.py +252 -0
- package/releng/meson/mesonbuild/dependencies/base.py +663 -0
- package/releng/meson/mesonbuild/dependencies/boost.py +1083 -0
- package/releng/meson/mesonbuild/dependencies/cmake.py +656 -0
- package/releng/meson/mesonbuild/dependencies/coarrays.py +80 -0
- package/releng/meson/mesonbuild/dependencies/configtool.py +163 -0
- package/releng/meson/mesonbuild/dependencies/cuda.py +295 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakeLists.txt +102 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakeListsLLVM.txt +204 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakePathInfo.txt +31 -0
- package/releng/meson/mesonbuild/dependencies/data/__init__.py +0 -0
- package/releng/meson/mesonbuild/dependencies/detect.py +225 -0
- package/releng/meson/mesonbuild/dependencies/dev.py +707 -0
- package/releng/meson/mesonbuild/dependencies/dub.py +424 -0
- package/releng/meson/mesonbuild/dependencies/factory.py +146 -0
- package/releng/meson/mesonbuild/dependencies/framework.py +111 -0
- package/releng/meson/mesonbuild/dependencies/hdf5.py +168 -0
- package/releng/meson/mesonbuild/dependencies/misc.py +618 -0
- package/releng/meson/mesonbuild/dependencies/mpi.py +231 -0
- package/releng/meson/mesonbuild/dependencies/pkgconfig.py +570 -0
- package/releng/meson/mesonbuild/dependencies/platform.py +52 -0
- package/releng/meson/mesonbuild/dependencies/python.py +431 -0
- package/releng/meson/mesonbuild/dependencies/qt.py +484 -0
- package/releng/meson/mesonbuild/dependencies/scalapack.py +142 -0
- package/releng/meson/mesonbuild/dependencies/ui.py +281 -0
- package/releng/meson/mesonbuild/depfile.py +82 -0
- package/releng/meson/mesonbuild/envconfig.py +480 -0
- package/releng/meson/mesonbuild/environment.py +987 -0
- package/releng/meson/mesonbuild/interpreter/__init__.py +47 -0
- package/releng/meson/mesonbuild/interpreter/compiler.py +900 -0
- package/releng/meson/mesonbuild/interpreter/dependencyfallbacks.py +386 -0
- package/releng/meson/mesonbuild/interpreter/interpreter.py +3595 -0
- package/releng/meson/mesonbuild/interpreter/interpreterobjects.py +1096 -0
- package/releng/meson/mesonbuild/interpreter/kwargs.py +479 -0
- package/releng/meson/mesonbuild/interpreter/mesonmain.py +487 -0
- package/releng/meson/mesonbuild/interpreter/primitives/__init__.py +29 -0
- package/releng/meson/mesonbuild/interpreter/primitives/array.py +108 -0
- package/releng/meson/mesonbuild/interpreter/primitives/boolean.py +52 -0
- package/releng/meson/mesonbuild/interpreter/primitives/dict.py +88 -0
- package/releng/meson/mesonbuild/interpreter/primitives/integer.py +86 -0
- package/releng/meson/mesonbuild/interpreter/primitives/range.py +38 -0
- package/releng/meson/mesonbuild/interpreter/primitives/string.py +247 -0
- package/releng/meson/mesonbuild/interpreter/type_checking.py +853 -0
- package/releng/meson/mesonbuild/interpreterbase/__init__.py +126 -0
- package/releng/meson/mesonbuild/interpreterbase/_unholder.py +25 -0
- package/releng/meson/mesonbuild/interpreterbase/baseobjects.py +174 -0
- package/releng/meson/mesonbuild/interpreterbase/decorators.py +806 -0
- package/releng/meson/mesonbuild/interpreterbase/disabler.py +35 -0
- package/releng/meson/mesonbuild/interpreterbase/exceptions.py +22 -0
- package/releng/meson/mesonbuild/interpreterbase/helpers.py +67 -0
- package/releng/meson/mesonbuild/interpreterbase/interpreterbase.py +665 -0
- package/releng/meson/mesonbuild/interpreterbase/operator.py +32 -0
- package/releng/meson/mesonbuild/linkers/__init__.py +20 -0
- package/releng/meson/mesonbuild/linkers/base.py +39 -0
- package/releng/meson/mesonbuild/linkers/detect.py +229 -0
- package/releng/meson/mesonbuild/linkers/linkers.py +1614 -0
- package/releng/meson/mesonbuild/mcompile.py +380 -0
- package/releng/meson/mesonbuild/mconf.py +368 -0
- package/releng/meson/mesonbuild/mdevenv.py +234 -0
- package/releng/meson/mesonbuild/mdist.py +376 -0
- package/releng/meson/mesonbuild/mesondata.py +38 -0
- package/releng/meson/mesonbuild/mesonlib.py +23 -0
- package/releng/meson/mesonbuild/mesonmain.py +289 -0
- package/releng/meson/mesonbuild/minit.py +204 -0
- package/releng/meson/mesonbuild/minstall.py +864 -0
- package/releng/meson/mesonbuild/mintro.py +667 -0
- package/releng/meson/mesonbuild/mlog.py +542 -0
- package/releng/meson/mesonbuild/modules/__init__.py +270 -0
- package/releng/meson/mesonbuild/modules/cmake.py +442 -0
- package/releng/meson/mesonbuild/modules/cuda.py +377 -0
- package/releng/meson/mesonbuild/modules/dlang.py +117 -0
- package/releng/meson/mesonbuild/modules/external_project.py +306 -0
- package/releng/meson/mesonbuild/modules/fs.py +323 -0
- package/releng/meson/mesonbuild/modules/gnome.py +2215 -0
- package/releng/meson/mesonbuild/modules/hotdoc.py +487 -0
- package/releng/meson/mesonbuild/modules/i18n.py +405 -0
- package/releng/meson/mesonbuild/modules/icestorm.py +123 -0
- package/releng/meson/mesonbuild/modules/java.py +112 -0
- package/releng/meson/mesonbuild/modules/keyval.py +65 -0
- package/releng/meson/mesonbuild/modules/modtest.py +33 -0
- package/releng/meson/mesonbuild/modules/pkgconfig.py +744 -0
- package/releng/meson/mesonbuild/modules/python.py +556 -0
- package/releng/meson/mesonbuild/modules/python3.py +85 -0
- package/releng/meson/mesonbuild/modules/qt.py +621 -0
- package/releng/meson/mesonbuild/modules/qt4.py +23 -0
- package/releng/meson/mesonbuild/modules/qt5.py +23 -0
- package/releng/meson/mesonbuild/modules/qt6.py +22 -0
- package/releng/meson/mesonbuild/modules/rust.py +355 -0
- package/releng/meson/mesonbuild/modules/simd.py +114 -0
- package/releng/meson/mesonbuild/modules/sourceset.py +291 -0
- package/releng/meson/mesonbuild/modules/wayland.py +151 -0
- package/releng/meson/mesonbuild/modules/windows.py +207 -0
- package/releng/meson/mesonbuild/mparser.py +1114 -0
- package/releng/meson/mesonbuild/msetup.py +365 -0
- package/releng/meson/mesonbuild/msubprojects.py +764 -0
- package/releng/meson/mesonbuild/mtest.py +2201 -0
- package/releng/meson/mesonbuild/munstable_coredata.py +107 -0
- package/releng/meson/mesonbuild/optinterpreter.py +276 -0
- package/releng/meson/mesonbuild/programs.py +367 -0
- package/releng/meson/mesonbuild/rewriter.py +1075 -0
- package/releng/meson/mesonbuild/scripts/__init__.py +10 -0
- package/releng/meson/mesonbuild/scripts/clangformat.py +55 -0
- package/releng/meson/mesonbuild/scripts/clangtidy.py +30 -0
- package/releng/meson/mesonbuild/scripts/cleantrees.py +35 -0
- package/releng/meson/mesonbuild/scripts/cmake_run_ctgt.py +103 -0
- package/releng/meson/mesonbuild/scripts/cmd_or_ps.ps1 +17 -0
- package/releng/meson/mesonbuild/scripts/copy.py +19 -0
- package/releng/meson/mesonbuild/scripts/coverage.py +214 -0
- package/releng/meson/mesonbuild/scripts/delwithsuffix.py +27 -0
- package/releng/meson/mesonbuild/scripts/depfixer.py +495 -0
- package/releng/meson/mesonbuild/scripts/depscan.py +198 -0
- package/releng/meson/mesonbuild/scripts/dirchanger.py +20 -0
- package/releng/meson/mesonbuild/scripts/env2mfile.py +402 -0
- package/releng/meson/mesonbuild/scripts/externalproject.py +106 -0
- package/releng/meson/mesonbuild/scripts/gettext.py +86 -0
- package/releng/meson/mesonbuild/scripts/gtkdochelper.py +286 -0
- package/releng/meson/mesonbuild/scripts/hotdochelper.py +40 -0
- package/releng/meson/mesonbuild/scripts/itstool.py +77 -0
- package/releng/meson/mesonbuild/scripts/meson_exe.py +115 -0
- package/releng/meson/mesonbuild/scripts/msgfmthelper.py +29 -0
- package/releng/meson/mesonbuild/scripts/pycompile.py +54 -0
- package/releng/meson/mesonbuild/scripts/python_info.py +121 -0
- package/releng/meson/mesonbuild/scripts/regen_checker.py +55 -0
- package/releng/meson/mesonbuild/scripts/run_tool.py +58 -0
- package/releng/meson/mesonbuild/scripts/scanbuild.py +57 -0
- package/releng/meson/mesonbuild/scripts/symbolextractor.py +322 -0
- package/releng/meson/mesonbuild/scripts/tags.py +44 -0
- package/releng/meson/mesonbuild/scripts/test_loaded_modules.py +14 -0
- package/releng/meson/mesonbuild/scripts/uninstall.py +41 -0
- package/releng/meson/mesonbuild/scripts/vcstagger.py +35 -0
- package/releng/meson/mesonbuild/scripts/yasm.py +24 -0
- package/releng/meson/mesonbuild/templates/__init__.py +0 -0
- package/releng/meson/mesonbuild/templates/cpptemplates.py +143 -0
- package/releng/meson/mesonbuild/templates/cstemplates.py +90 -0
- package/releng/meson/mesonbuild/templates/ctemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/cudatemplates.py +143 -0
- package/releng/meson/mesonbuild/templates/dlangtemplates.py +109 -0
- package/releng/meson/mesonbuild/templates/fortrantemplates.py +101 -0
- package/releng/meson/mesonbuild/templates/javatemplates.py +94 -0
- package/releng/meson/mesonbuild/templates/mesontemplates.py +70 -0
- package/releng/meson/mesonbuild/templates/objcpptemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/objctemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/rusttemplates.py +79 -0
- package/releng/meson/mesonbuild/templates/samplefactory.py +41 -0
- package/releng/meson/mesonbuild/templates/sampleimpl.py +160 -0
- package/releng/meson/mesonbuild/templates/valatemplates.py +82 -0
- package/releng/meson/mesonbuild/utils/__init__.py +0 -0
- package/releng/meson/mesonbuild/utils/core.py +166 -0
- package/releng/meson/mesonbuild/utils/platform.py +27 -0
- package/releng/meson/mesonbuild/utils/posix.py +32 -0
- package/releng/meson/mesonbuild/utils/universal.py +2445 -0
- package/releng/meson/mesonbuild/utils/vsenv.py +126 -0
- package/releng/meson/mesonbuild/utils/win32.py +29 -0
- package/releng/meson/mesonbuild/wrap/__init__.py +59 -0
- package/releng/meson/mesonbuild/wrap/wrap.py +846 -0
- package/releng/meson/mesonbuild/wrap/wraptool.py +198 -0
- package/releng/meson-scripts/BSDmakefile +6 -0
- package/releng/meson-scripts/Makefile +16 -0
- package/releng/meson-scripts/configure +18 -0
- package/releng/meson-scripts/configure.bat +22 -0
- package/releng/meson-scripts/make.bat +23 -0
- package/releng/meson_configure.py +506 -0
- package/releng/meson_make.py +131 -0
- package/releng/mkdevkit.py +107 -0
- package/releng/mkfatmacho.py +54 -0
- package/releng/post-process-oabi.py +97 -0
- package/releng/progress.py +14 -0
- package/releng/sync-from-upstream.py +185 -0
- package/releng/tomlkit/tomlkit/__init__.py +59 -0
- package/releng/tomlkit/tomlkit/_compat.py +22 -0
- package/releng/tomlkit/tomlkit/_types.py +83 -0
- package/releng/tomlkit/tomlkit/_utils.py +158 -0
- package/releng/tomlkit/tomlkit/api.py +308 -0
- package/releng/tomlkit/tomlkit/container.py +875 -0
- package/releng/tomlkit/tomlkit/exceptions.py +227 -0
- package/releng/tomlkit/tomlkit/items.py +1967 -0
- package/releng/tomlkit/tomlkit/parser.py +1141 -0
- package/releng/tomlkit/tomlkit/py.typed +0 -0
- package/releng/tomlkit/tomlkit/source.py +180 -0
- package/releng/tomlkit/tomlkit/toml_char.py +52 -0
- package/releng/tomlkit/tomlkit/toml_document.py +7 -0
- package/releng/tomlkit/tomlkit/toml_file.py +58 -0
- package/releng/winenv.py +140 -0
- package/scripts/adjust-version.py +19 -0
- package/scripts/detect-version.py +40 -0
- package/scripts/fetch-abi-bits.py +343 -0
- package/scripts/install.js +23 -0
- package/scripts/package.py +15 -0
- package/src/addon.cc +76 -0
- package/src/application.cc +148 -0
- package/src/application.h +31 -0
- package/src/authentication.cc +174 -0
- package/src/authentication.h +24 -0
- package/src/bus.cc +167 -0
- package/src/bus.h +33 -0
- package/src/cancellable.cc +117 -0
- package/src/cancellable.h +31 -0
- package/src/child.cc +150 -0
- package/src/child.h +32 -0
- package/src/crash.cc +122 -0
- package/src/crash.h +30 -0
- package/src/device.cc +1302 -0
- package/src/device.h +55 -0
- package/src/device_manager.cc +362 -0
- package/src/device_manager.h +35 -0
- package/src/endpoint_parameters.cc +171 -0
- package/src/endpoint_parameters.h +28 -0
- package/src/glib_context.cc +62 -0
- package/src/glib_context.h +29 -0
- package/src/glib_object.cc +25 -0
- package/src/glib_object.h +37 -0
- package/src/iostream.cc +247 -0
- package/src/iostream.h +30 -0
- package/src/meson.build +26 -0
- package/src/operation.h +94 -0
- package/src/portal_membership.cc +100 -0
- package/src/portal_membership.h +26 -0
- package/src/portal_service.cc +401 -0
- package/src/portal_service.h +40 -0
- package/src/process.cc +135 -0
- package/src/process.h +30 -0
- package/src/relay.cc +139 -0
- package/src/relay.h +31 -0
- package/src/runtime.cc +443 -0
- package/src/runtime.h +64 -0
- package/src/script.cc +301 -0
- package/src/script.h +36 -0
- package/src/session.cc +860 -0
- package/src/session.h +42 -0
- package/src/signals.cc +334 -0
- package/src/signals.h +47 -0
- package/src/spawn.cc +95 -0
- package/src/spawn.h +27 -0
- package/src/usage_monitor.h +117 -0
- package/src/uv_context.cc +118 -0
- package/src/uv_context.h +40 -0
- package/src/win_delay_load_hook.cc +63 -0
- package/subprojects/frida-core.wrap +8 -0
- package/subprojects/nan.wrap +9 -0
- package/subprojects/packagefiles/nan.patch +13 -0
- package/test/data/index.ts +13 -0
- package/test/data/unixvictim-linux-x86 +0 -0
- package/test/data/unixvictim-linux-x86_64 +0 -0
- package/test/data/unixvictim-macos +0 -0
- package/test/device.ts +27 -0
- package/test/device_manager.ts +16 -0
- package/test/labrat.ts +32 -0
- package/test/script.ts +176 -0
- package/test/session.ts +73 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2013-2016 The Meson development team
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
import stat
|
|
10
|
+
import struct
|
|
11
|
+
import shutil
|
|
12
|
+
import subprocess
|
|
13
|
+
import typing as T
|
|
14
|
+
|
|
15
|
+
from ..mesonlib import OrderedSet, generate_list, Popen_safe
|
|
16
|
+
|
|
17
|
+
SHT_STRTAB = 3
|
|
18
|
+
DT_NEEDED = 1
|
|
19
|
+
DT_RPATH = 15
|
|
20
|
+
DT_RUNPATH = 29
|
|
21
|
+
DT_STRTAB = 5
|
|
22
|
+
DT_SONAME = 14
|
|
23
|
+
DT_MIPS_RLD_MAP_REL = 1879048245
|
|
24
|
+
|
|
25
|
+
# Global cache for tools
|
|
26
|
+
INSTALL_NAME_TOOL = False
|
|
27
|
+
|
|
28
|
+
class DataSizes:
|
|
29
|
+
def __init__(self, ptrsize: int, is_le: bool) -> None:
|
|
30
|
+
if is_le:
|
|
31
|
+
p = '<'
|
|
32
|
+
else:
|
|
33
|
+
p = '>'
|
|
34
|
+
self.Half = p + 'h'
|
|
35
|
+
self.HalfSize = 2
|
|
36
|
+
self.Word = p + 'I'
|
|
37
|
+
self.WordSize = 4
|
|
38
|
+
self.Sword = p + 'i'
|
|
39
|
+
self.SwordSize = 4
|
|
40
|
+
if ptrsize == 64:
|
|
41
|
+
self.Addr = p + 'Q'
|
|
42
|
+
self.AddrSize = 8
|
|
43
|
+
self.Off = p + 'Q'
|
|
44
|
+
self.OffSize = 8
|
|
45
|
+
self.XWord = p + 'Q'
|
|
46
|
+
self.XWordSize = 8
|
|
47
|
+
self.Sxword = p + 'q'
|
|
48
|
+
self.SxwordSize = 8
|
|
49
|
+
else:
|
|
50
|
+
self.Addr = p + 'I'
|
|
51
|
+
self.AddrSize = 4
|
|
52
|
+
self.Off = p + 'I'
|
|
53
|
+
self.OffSize = 4
|
|
54
|
+
|
|
55
|
+
class DynamicEntry(DataSizes):
|
|
56
|
+
def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None:
|
|
57
|
+
super().__init__(ptrsize, is_le)
|
|
58
|
+
self.ptrsize = ptrsize
|
|
59
|
+
if ptrsize == 64:
|
|
60
|
+
self.d_tag = struct.unpack(self.Sxword, ifile.read(self.SxwordSize))[0]
|
|
61
|
+
self.val = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
|
|
62
|
+
else:
|
|
63
|
+
self.d_tag = struct.unpack(self.Sword, ifile.read(self.SwordSize))[0]
|
|
64
|
+
self.val = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
65
|
+
|
|
66
|
+
def write(self, ofile: T.BinaryIO) -> None:
|
|
67
|
+
if self.ptrsize == 64:
|
|
68
|
+
ofile.write(struct.pack(self.Sxword, self.d_tag))
|
|
69
|
+
ofile.write(struct.pack(self.XWord, self.val))
|
|
70
|
+
else:
|
|
71
|
+
ofile.write(struct.pack(self.Sword, self.d_tag))
|
|
72
|
+
ofile.write(struct.pack(self.Word, self.val))
|
|
73
|
+
|
|
74
|
+
class SectionHeader(DataSizes):
|
|
75
|
+
def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None:
|
|
76
|
+
super().__init__(ptrsize, is_le)
|
|
77
|
+
is_64 = ptrsize == 64
|
|
78
|
+
|
|
79
|
+
# Elf64_Word
|
|
80
|
+
self.sh_name = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
81
|
+
# Elf64_Word
|
|
82
|
+
self.sh_type = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
83
|
+
# Elf64_Xword
|
|
84
|
+
if is_64:
|
|
85
|
+
self.sh_flags = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
|
|
86
|
+
else:
|
|
87
|
+
self.sh_flags = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
88
|
+
# Elf64_Addr
|
|
89
|
+
self.sh_addr = struct.unpack(self.Addr, ifile.read(self.AddrSize))[0]
|
|
90
|
+
# Elf64_Off
|
|
91
|
+
self.sh_offset = struct.unpack(self.Off, ifile.read(self.OffSize))[0]
|
|
92
|
+
# Elf64_Xword
|
|
93
|
+
if is_64:
|
|
94
|
+
self.sh_size = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
|
|
95
|
+
else:
|
|
96
|
+
self.sh_size = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
97
|
+
# Elf64_Word
|
|
98
|
+
self.sh_link = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
99
|
+
# Elf64_Word
|
|
100
|
+
self.sh_info = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
101
|
+
# Elf64_Xword
|
|
102
|
+
if is_64:
|
|
103
|
+
self.sh_addralign = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
|
|
104
|
+
else:
|
|
105
|
+
self.sh_addralign = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
106
|
+
# Elf64_Xword
|
|
107
|
+
if is_64:
|
|
108
|
+
self.sh_entsize = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0]
|
|
109
|
+
else:
|
|
110
|
+
self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0]
|
|
111
|
+
|
|
112
|
+
class Elf(DataSizes):
|
|
113
|
+
def __init__(self, bfile: str, verbose: bool = True) -> None:
|
|
114
|
+
self.bfile = bfile
|
|
115
|
+
self.verbose = verbose
|
|
116
|
+
self.sections: T.List[SectionHeader] = []
|
|
117
|
+
self.dynamic: T.List[DynamicEntry] = []
|
|
118
|
+
self.open_bf(bfile)
|
|
119
|
+
try:
|
|
120
|
+
(self.ptrsize, self.is_le) = self.detect_elf_type()
|
|
121
|
+
super().__init__(self.ptrsize, self.is_le)
|
|
122
|
+
self.parse_header()
|
|
123
|
+
self.parse_sections()
|
|
124
|
+
self.parse_dynamic()
|
|
125
|
+
except (struct.error, RuntimeError):
|
|
126
|
+
self.close_bf()
|
|
127
|
+
raise
|
|
128
|
+
|
|
129
|
+
def open_bf(self, bfile: str) -> None:
|
|
130
|
+
self.bf = None
|
|
131
|
+
self.bf_perms = None
|
|
132
|
+
try:
|
|
133
|
+
self.bf = open(bfile, 'r+b')
|
|
134
|
+
except PermissionError as e:
|
|
135
|
+
self.bf_perms = stat.S_IMODE(os.lstat(bfile).st_mode)
|
|
136
|
+
os.chmod(bfile, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
|
|
137
|
+
try:
|
|
138
|
+
self.bf = open(bfile, 'r+b')
|
|
139
|
+
except Exception:
|
|
140
|
+
os.chmod(bfile, self.bf_perms)
|
|
141
|
+
self.bf_perms = None
|
|
142
|
+
raise e
|
|
143
|
+
|
|
144
|
+
def close_bf(self) -> None:
|
|
145
|
+
if self.bf is not None:
|
|
146
|
+
if self.bf_perms is not None:
|
|
147
|
+
os.chmod(self.bf.fileno(), self.bf_perms)
|
|
148
|
+
self.bf_perms = None
|
|
149
|
+
self.bf.close()
|
|
150
|
+
self.bf = None
|
|
151
|
+
|
|
152
|
+
def __enter__(self) -> 'Elf':
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
def __del__(self) -> None:
|
|
156
|
+
self.close_bf()
|
|
157
|
+
|
|
158
|
+
def __exit__(self, exc_type: T.Any, exc_value: T.Any, traceback: T.Any) -> None:
|
|
159
|
+
self.close_bf()
|
|
160
|
+
|
|
161
|
+
def detect_elf_type(self) -> T.Tuple[int, bool]:
|
|
162
|
+
data = self.bf.read(6)
|
|
163
|
+
if data[1:4] != b'ELF':
|
|
164
|
+
# This script gets called to non-elf targets too
|
|
165
|
+
# so just ignore them.
|
|
166
|
+
if self.verbose:
|
|
167
|
+
print(f'File {self.bfile!r} is not an ELF file.')
|
|
168
|
+
sys.exit(0)
|
|
169
|
+
if data[4] == 1:
|
|
170
|
+
ptrsize = 32
|
|
171
|
+
elif data[4] == 2:
|
|
172
|
+
ptrsize = 64
|
|
173
|
+
else:
|
|
174
|
+
sys.exit(f'File {self.bfile!r} has unknown ELF class.')
|
|
175
|
+
if data[5] == 1:
|
|
176
|
+
is_le = True
|
|
177
|
+
elif data[5] == 2:
|
|
178
|
+
is_le = False
|
|
179
|
+
else:
|
|
180
|
+
sys.exit(f'File {self.bfile!r} has unknown ELF endianness.')
|
|
181
|
+
return ptrsize, is_le
|
|
182
|
+
|
|
183
|
+
def parse_header(self) -> None:
|
|
184
|
+
self.bf.seek(0)
|
|
185
|
+
self.e_ident = struct.unpack('16s', self.bf.read(16))[0]
|
|
186
|
+
self.e_type = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
187
|
+
self.e_machine = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
188
|
+
self.e_version = struct.unpack(self.Word, self.bf.read(self.WordSize))[0]
|
|
189
|
+
self.e_entry = struct.unpack(self.Addr, self.bf.read(self.AddrSize))[0]
|
|
190
|
+
self.e_phoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0]
|
|
191
|
+
self.e_shoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0]
|
|
192
|
+
self.e_flags = struct.unpack(self.Word, self.bf.read(self.WordSize))[0]
|
|
193
|
+
self.e_ehsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
194
|
+
self.e_phentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
195
|
+
self.e_phnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
196
|
+
self.e_shentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
197
|
+
self.e_shnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
198
|
+
self.e_shstrndx = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0]
|
|
199
|
+
|
|
200
|
+
def parse_sections(self) -> None:
|
|
201
|
+
self.bf.seek(self.e_shoff)
|
|
202
|
+
for _ in range(self.e_shnum):
|
|
203
|
+
self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le))
|
|
204
|
+
|
|
205
|
+
def read_str(self) -> bytes:
|
|
206
|
+
arr = []
|
|
207
|
+
x = self.bf.read(1)
|
|
208
|
+
while x != b'\0':
|
|
209
|
+
arr.append(x)
|
|
210
|
+
x = self.bf.read(1)
|
|
211
|
+
if x == b'':
|
|
212
|
+
raise RuntimeError('Tried to read past the end of the file')
|
|
213
|
+
return b''.join(arr)
|
|
214
|
+
|
|
215
|
+
def find_section(self, target_name: bytes) -> T.Optional[SectionHeader]:
|
|
216
|
+
section_names = self.sections[self.e_shstrndx]
|
|
217
|
+
for i in self.sections:
|
|
218
|
+
self.bf.seek(section_names.sh_offset + i.sh_name)
|
|
219
|
+
name = self.read_str()
|
|
220
|
+
if name == target_name:
|
|
221
|
+
return i
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
def parse_dynamic(self) -> None:
|
|
225
|
+
sec = self.find_section(b'.dynamic')
|
|
226
|
+
if sec is None:
|
|
227
|
+
return
|
|
228
|
+
self.bf.seek(sec.sh_offset)
|
|
229
|
+
while True:
|
|
230
|
+
e = DynamicEntry(self.bf, self.ptrsize, self.is_le)
|
|
231
|
+
self.dynamic.append(e)
|
|
232
|
+
if e.d_tag == 0:
|
|
233
|
+
break
|
|
234
|
+
|
|
235
|
+
@generate_list
|
|
236
|
+
def get_section_names(self) -> T.Generator[str, None, None]:
|
|
237
|
+
section_names = self.sections[self.e_shstrndx]
|
|
238
|
+
for i in self.sections:
|
|
239
|
+
self.bf.seek(section_names.sh_offset + i.sh_name)
|
|
240
|
+
yield self.read_str().decode()
|
|
241
|
+
|
|
242
|
+
def get_soname(self) -> T.Optional[str]:
|
|
243
|
+
soname = None
|
|
244
|
+
strtab = None
|
|
245
|
+
for i in self.dynamic:
|
|
246
|
+
if i.d_tag == DT_SONAME:
|
|
247
|
+
soname = i
|
|
248
|
+
if i.d_tag == DT_STRTAB:
|
|
249
|
+
strtab = i
|
|
250
|
+
if soname is None or strtab is None:
|
|
251
|
+
return None
|
|
252
|
+
self.bf.seek(strtab.val + soname.val)
|
|
253
|
+
return self.read_str().decode()
|
|
254
|
+
|
|
255
|
+
def get_entry_offset(self, entrynum: int) -> T.Optional[int]:
|
|
256
|
+
sec = self.find_section(b'.dynstr')
|
|
257
|
+
for i in self.dynamic:
|
|
258
|
+
if i.d_tag == entrynum:
|
|
259
|
+
res = sec.sh_offset + i.val
|
|
260
|
+
assert isinstance(res, int)
|
|
261
|
+
return res
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
def get_rpath(self) -> T.Optional[str]:
|
|
265
|
+
offset = self.get_entry_offset(DT_RPATH)
|
|
266
|
+
if offset is None:
|
|
267
|
+
return None
|
|
268
|
+
self.bf.seek(offset)
|
|
269
|
+
return self.read_str().decode()
|
|
270
|
+
|
|
271
|
+
def get_runpath(self) -> T.Optional[str]:
|
|
272
|
+
offset = self.get_entry_offset(DT_RUNPATH)
|
|
273
|
+
if offset is None:
|
|
274
|
+
return None
|
|
275
|
+
self.bf.seek(offset)
|
|
276
|
+
return self.read_str().decode()
|
|
277
|
+
|
|
278
|
+
@generate_list
|
|
279
|
+
def get_deps(self) -> T.Generator[str, None, None]:
|
|
280
|
+
sec = self.find_section(b'.dynstr')
|
|
281
|
+
for i in self.dynamic:
|
|
282
|
+
if i.d_tag == DT_NEEDED:
|
|
283
|
+
offset = sec.sh_offset + i.val
|
|
284
|
+
self.bf.seek(offset)
|
|
285
|
+
yield self.read_str().decode()
|
|
286
|
+
|
|
287
|
+
def fix_deps(self, prefix: bytes) -> None:
|
|
288
|
+
sec = self.find_section(b'.dynstr')
|
|
289
|
+
deps = []
|
|
290
|
+
for i in self.dynamic:
|
|
291
|
+
if i.d_tag == DT_NEEDED:
|
|
292
|
+
deps.append(i)
|
|
293
|
+
for i in deps:
|
|
294
|
+
offset = sec.sh_offset + i.val
|
|
295
|
+
self.bf.seek(offset)
|
|
296
|
+
name = self.read_str()
|
|
297
|
+
if name.startswith(prefix):
|
|
298
|
+
basename = name.rsplit(b'/', maxsplit=1)[-1]
|
|
299
|
+
padding = b'\0' * (len(name) - len(basename))
|
|
300
|
+
newname = basename + padding
|
|
301
|
+
assert len(newname) == len(name)
|
|
302
|
+
self.bf.seek(offset)
|
|
303
|
+
self.bf.write(newname)
|
|
304
|
+
|
|
305
|
+
def fix_rpath(self, fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: bytes) -> None:
|
|
306
|
+
# The path to search for can be either rpath or runpath.
|
|
307
|
+
# Fix both of them to be sure.
|
|
308
|
+
self.fix_rpathtype_entry(fname, rpath_dirs_to_remove, new_rpath, DT_RPATH)
|
|
309
|
+
self.fix_rpathtype_entry(fname, rpath_dirs_to_remove, new_rpath, DT_RUNPATH)
|
|
310
|
+
|
|
311
|
+
def fix_rpathtype_entry(self, fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: bytes, entrynum: int) -> None:
|
|
312
|
+
rp_off = self.get_entry_offset(entrynum)
|
|
313
|
+
if rp_off is None:
|
|
314
|
+
if self.verbose:
|
|
315
|
+
print(f'File {fname!r} does not have an rpath. It should be a fully static executable.')
|
|
316
|
+
return
|
|
317
|
+
self.bf.seek(rp_off)
|
|
318
|
+
|
|
319
|
+
old_rpath = self.read_str()
|
|
320
|
+
# Some rpath entries may come from multiple sources.
|
|
321
|
+
# Only add each one once.
|
|
322
|
+
new_rpaths: OrderedSet[bytes] = OrderedSet()
|
|
323
|
+
if new_rpath:
|
|
324
|
+
new_rpaths.update(new_rpath.split(b':'))
|
|
325
|
+
if old_rpath:
|
|
326
|
+
# Filter out build-only rpath entries
|
|
327
|
+
# added by get_link_dep_subdirs() or
|
|
328
|
+
# specified by user with build_rpath.
|
|
329
|
+
for rpath_dir in old_rpath.split(b':'):
|
|
330
|
+
if not (rpath_dir in rpath_dirs_to_remove or
|
|
331
|
+
rpath_dir == (b'X' * len(rpath_dir))):
|
|
332
|
+
if rpath_dir:
|
|
333
|
+
new_rpaths.add(rpath_dir)
|
|
334
|
+
|
|
335
|
+
# Prepend user-specified new entries while preserving the ones that came from pkgconfig etc.
|
|
336
|
+
new_rpath = b':'.join(new_rpaths)
|
|
337
|
+
|
|
338
|
+
if len(old_rpath) < len(new_rpath):
|
|
339
|
+
msg = "New rpath must not be longer than the old one.\n Old: {}\n New: {}".format(old_rpath.decode('utf-8'), new_rpath.decode('utf-8'))
|
|
340
|
+
sys.exit(msg)
|
|
341
|
+
# The linker does read-only string deduplication. If there is a
|
|
342
|
+
# string that shares a suffix with the rpath, they might get
|
|
343
|
+
# deduped. This means changing the rpath string might break something
|
|
344
|
+
# completely unrelated. This has already happened once with X.org.
|
|
345
|
+
# Thus we want to keep this change as small as possible to minimize
|
|
346
|
+
# the chance of obliterating other strings. It might still happen
|
|
347
|
+
# but our behavior is identical to what chrpath does and it has
|
|
348
|
+
# been in use for ages so based on that this should be rare.
|
|
349
|
+
if not new_rpath:
|
|
350
|
+
self.remove_rpath_entry(entrynum)
|
|
351
|
+
else:
|
|
352
|
+
self.bf.seek(rp_off)
|
|
353
|
+
self.bf.write(new_rpath)
|
|
354
|
+
self.bf.write(b'\0')
|
|
355
|
+
|
|
356
|
+
def remove_rpath_entry(self, entrynum: int) -> None:
|
|
357
|
+
sec = self.find_section(b'.dynamic')
|
|
358
|
+
if sec is None:
|
|
359
|
+
return None
|
|
360
|
+
for (i, entry) in enumerate(self.dynamic):
|
|
361
|
+
if entry.d_tag == entrynum:
|
|
362
|
+
rpentry = self.dynamic[i]
|
|
363
|
+
rpentry.d_tag = 0
|
|
364
|
+
self.dynamic = self.dynamic[:i] + self.dynamic[i + 1:] + [rpentry]
|
|
365
|
+
break
|
|
366
|
+
# DT_MIPS_RLD_MAP_REL is relative to the offset of the tag. Adjust it consequently.
|
|
367
|
+
for entry in self.dynamic[i:]:
|
|
368
|
+
if entry.d_tag == DT_MIPS_RLD_MAP_REL:
|
|
369
|
+
entry.val += 2 * (self.ptrsize // 8)
|
|
370
|
+
break
|
|
371
|
+
self.bf.seek(sec.sh_offset)
|
|
372
|
+
for entry in self.dynamic:
|
|
373
|
+
entry.write(self.bf)
|
|
374
|
+
return None
|
|
375
|
+
|
|
376
|
+
def fix_elf(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Optional[bytes], verbose: bool = True) -> None:
|
|
377
|
+
if new_rpath is not None:
|
|
378
|
+
with Elf(fname, verbose) as e:
|
|
379
|
+
# note: e.get_rpath() and e.get_runpath() may be useful
|
|
380
|
+
e.fix_rpath(fname, rpath_dirs_to_remove, new_rpath)
|
|
381
|
+
|
|
382
|
+
def get_darwin_rpaths_to_remove(fname: str) -> T.List[str]:
|
|
383
|
+
p, out, _ = Popen_safe(['otool', '-l', fname], stderr=subprocess.DEVNULL)
|
|
384
|
+
if p.returncode != 0:
|
|
385
|
+
raise subprocess.CalledProcessError(p.returncode, p.args, out)
|
|
386
|
+
result = []
|
|
387
|
+
current_cmd = 'FOOBAR'
|
|
388
|
+
for line in out.split('\n'):
|
|
389
|
+
line = line.strip()
|
|
390
|
+
if ' ' not in line:
|
|
391
|
+
continue
|
|
392
|
+
key, value = line.strip().split(' ', 1)
|
|
393
|
+
if key == 'cmd':
|
|
394
|
+
current_cmd = value
|
|
395
|
+
if key == 'path' and current_cmd == 'LC_RPATH':
|
|
396
|
+
rp = value.split('(', 1)[0].strip()
|
|
397
|
+
result.append(rp)
|
|
398
|
+
return result
|
|
399
|
+
|
|
400
|
+
def fix_darwin(fname: str, new_rpath: str, final_path: str, install_name_mappings: T.Dict[str, str]) -> None:
|
|
401
|
+
try:
|
|
402
|
+
rpaths = get_darwin_rpaths_to_remove(fname)
|
|
403
|
+
except subprocess.CalledProcessError:
|
|
404
|
+
# Otool failed, which happens when invoked on a
|
|
405
|
+
# non-executable target. Just return.
|
|
406
|
+
return
|
|
407
|
+
try:
|
|
408
|
+
args = []
|
|
409
|
+
if rpaths:
|
|
410
|
+
# TODO: fix this properly, not totally clear how
|
|
411
|
+
#
|
|
412
|
+
# removing rpaths from binaries on macOS has tons of
|
|
413
|
+
# weird edge cases. For instance, if the user provided
|
|
414
|
+
# a '-Wl,-rpath' argument in LDFLAGS that happens to
|
|
415
|
+
# coincide with an rpath generated from a dependency,
|
|
416
|
+
# this would cause installation failures, as meson would
|
|
417
|
+
# generate install_name_tool calls with two identical
|
|
418
|
+
# '-delete_rpath' arguments, which install_name_tool
|
|
419
|
+
# fails on. Because meson itself ensures that it never
|
|
420
|
+
# adds duplicate rpaths, duplicate rpaths necessarily
|
|
421
|
+
# come from user variables. The idea of using OrderedSet
|
|
422
|
+
# is to remove *at most one* duplicate RPATH entry. This
|
|
423
|
+
# is not optimal, as it only respects the user's choice
|
|
424
|
+
# partially: if they provided a non-duplicate '-Wl,-rpath'
|
|
425
|
+
# argument, it gets removed, if they provided a duplicate
|
|
426
|
+
# one, it remains in the final binary. A potentially optimal
|
|
427
|
+
# solution would split all user '-Wl,-rpath' arguments from
|
|
428
|
+
# LDFLAGS, and later add them back with '-add_rpath'.
|
|
429
|
+
for rp in OrderedSet(rpaths):
|
|
430
|
+
args += ['-delete_rpath', rp]
|
|
431
|
+
subprocess.check_call(['install_name_tool', fname] + args,
|
|
432
|
+
stdout=subprocess.DEVNULL,
|
|
433
|
+
stderr=subprocess.DEVNULL)
|
|
434
|
+
args = []
|
|
435
|
+
if new_rpath:
|
|
436
|
+
args += ['-add_rpath', new_rpath]
|
|
437
|
+
# Rewrite -install_name @rpath/libfoo.dylib to /path/to/libfoo.dylib
|
|
438
|
+
if fname.endswith('dylib'):
|
|
439
|
+
args += ['-id', final_path]
|
|
440
|
+
if install_name_mappings:
|
|
441
|
+
for old, new in install_name_mappings.items():
|
|
442
|
+
args += ['-change', old, new]
|
|
443
|
+
if args:
|
|
444
|
+
subprocess.check_call(['install_name_tool', fname] + args,
|
|
445
|
+
stdout=subprocess.DEVNULL,
|
|
446
|
+
stderr=subprocess.DEVNULL)
|
|
447
|
+
except Exception as err:
|
|
448
|
+
raise SystemExit(err)
|
|
449
|
+
|
|
450
|
+
def fix_jar(fname: str) -> None:
|
|
451
|
+
subprocess.check_call(['jar', 'xf', fname, 'META-INF/MANIFEST.MF'])
|
|
452
|
+
with open('META-INF/MANIFEST.MF', 'r+', encoding='utf-8') as f:
|
|
453
|
+
lines = f.readlines()
|
|
454
|
+
f.seek(0)
|
|
455
|
+
for line in lines:
|
|
456
|
+
if not line.startswith('Class-Path:'):
|
|
457
|
+
f.write(line)
|
|
458
|
+
f.truncate()
|
|
459
|
+
# jar -um doesn't allow removing existing attributes. Use -uM instead,
|
|
460
|
+
# which a) removes the existing manifest from the jar and b) disables
|
|
461
|
+
# special-casing for the manifest file, so we can re-add it as a normal
|
|
462
|
+
# archive member. This puts the manifest at the end of the jar rather
|
|
463
|
+
# than the beginning, but the spec doesn't forbid that.
|
|
464
|
+
subprocess.check_call(['jar', 'ufM', fname, 'META-INF/MANIFEST.MF'])
|
|
465
|
+
|
|
466
|
+
def fix_rpath(fname: str, rpath_dirs_to_remove: T.Set[bytes], new_rpath: T.Union[str, bytes], final_path: str, install_name_mappings: T.Dict[str, str], verbose: bool = True) -> None:
|
|
467
|
+
global INSTALL_NAME_TOOL # pylint: disable=global-statement
|
|
468
|
+
# Static libraries, import libraries, debug information, headers, etc
|
|
469
|
+
# never have rpaths
|
|
470
|
+
# DLLs and EXE currently do not need runtime path fixing
|
|
471
|
+
if fname.endswith(('.a', '.lib', '.pdb', '.h', '.hpp', '.dll', '.exe')):
|
|
472
|
+
return
|
|
473
|
+
try:
|
|
474
|
+
if fname.endswith('.jar'):
|
|
475
|
+
fix_jar(fname)
|
|
476
|
+
return
|
|
477
|
+
if isinstance(new_rpath, str):
|
|
478
|
+
new_rpath = new_rpath.encode('utf8')
|
|
479
|
+
fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose)
|
|
480
|
+
return
|
|
481
|
+
except SystemExit as e:
|
|
482
|
+
if isinstance(e.code, int) and e.code == 0:
|
|
483
|
+
pass
|
|
484
|
+
else:
|
|
485
|
+
raise
|
|
486
|
+
# We don't look for this on import because it will do a useless PATH lookup
|
|
487
|
+
# on non-mac platforms. That can be expensive on some Windows machines
|
|
488
|
+
# (up to 30ms), which is significant with --only-changed. For details, see:
|
|
489
|
+
# https://github.com/mesonbuild/meson/pull/6612#discussion_r378581401
|
|
490
|
+
if INSTALL_NAME_TOOL is False:
|
|
491
|
+
INSTALL_NAME_TOOL = bool(shutil.which('install_name_tool'))
|
|
492
|
+
if INSTALL_NAME_TOOL:
|
|
493
|
+
if isinstance(new_rpath, bytes):
|
|
494
|
+
new_rpath = new_rpath.decode('utf8')
|
|
495
|
+
fix_darwin(fname, new_rpath, final_path, install_name_mappings)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2020 The Meson development team
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import pathlib
|
|
9
|
+
import pickle
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
import typing as T
|
|
13
|
+
|
|
14
|
+
from ..backend.ninjabackend import ninja_quote
|
|
15
|
+
from ..compilers.compilers import lang_suffixes
|
|
16
|
+
|
|
17
|
+
if T.TYPE_CHECKING:
|
|
18
|
+
from ..backend.ninjabackend import TargetDependencyScannerInfo
|
|
19
|
+
|
|
20
|
+
CPP_IMPORT_RE = re.compile(r'\w*import ([a-zA-Z0-9]+);')
|
|
21
|
+
CPP_EXPORT_RE = re.compile(r'\w*export module ([a-zA-Z0-9]+);')
|
|
22
|
+
|
|
23
|
+
FORTRAN_INCLUDE_PAT = r"^\s*include\s*['\"](\w+\.\w+)['\"]"
|
|
24
|
+
FORTRAN_MODULE_PAT = r"^\s*\bmodule\b\s+(\w+)\s*(?:!+.*)*$"
|
|
25
|
+
FORTRAN_SUBMOD_PAT = r"^\s*\bsubmodule\b\s*\((\w+:?\w+)\)\s*(\w+)"
|
|
26
|
+
FORTRAN_USE_PAT = r"^\s*use,?\s*(?:non_intrinsic)?\s*(?:::)?\s*(\w+)"
|
|
27
|
+
|
|
28
|
+
FORTRAN_MODULE_RE = re.compile(FORTRAN_MODULE_PAT, re.IGNORECASE)
|
|
29
|
+
FORTRAN_SUBMOD_RE = re.compile(FORTRAN_SUBMOD_PAT, re.IGNORECASE)
|
|
30
|
+
FORTRAN_USE_RE = re.compile(FORTRAN_USE_PAT, re.IGNORECASE)
|
|
31
|
+
|
|
32
|
+
class DependencyScanner:
|
|
33
|
+
def __init__(self, pickle_file: str, outfile: str, sources: T.List[str]):
|
|
34
|
+
with open(pickle_file, 'rb') as pf:
|
|
35
|
+
self.target_data: TargetDependencyScannerInfo = pickle.load(pf)
|
|
36
|
+
self.outfile = outfile
|
|
37
|
+
self.sources = sources
|
|
38
|
+
self.provided_by: T.Dict[str, str] = {}
|
|
39
|
+
self.exports: T.Dict[str, str] = {}
|
|
40
|
+
self.needs: T.Dict[str, T.List[str]] = {}
|
|
41
|
+
self.sources_with_exports: T.List[str] = []
|
|
42
|
+
|
|
43
|
+
def scan_file(self, fname: str) -> None:
|
|
44
|
+
suffix = os.path.splitext(fname)[1][1:]
|
|
45
|
+
if suffix != 'C':
|
|
46
|
+
suffix = suffix.lower()
|
|
47
|
+
if suffix in lang_suffixes['fortran']:
|
|
48
|
+
self.scan_fortran_file(fname)
|
|
49
|
+
elif suffix in lang_suffixes['cpp']:
|
|
50
|
+
self.scan_cpp_file(fname)
|
|
51
|
+
else:
|
|
52
|
+
sys.exit(f'Can not scan files with suffix .{suffix}.')
|
|
53
|
+
|
|
54
|
+
def scan_fortran_file(self, fname: str) -> None:
|
|
55
|
+
fpath = pathlib.Path(fname)
|
|
56
|
+
modules_in_this_file = set()
|
|
57
|
+
for line in fpath.read_text(encoding='utf-8', errors='ignore').split('\n'):
|
|
58
|
+
import_match = FORTRAN_USE_RE.match(line)
|
|
59
|
+
export_match = FORTRAN_MODULE_RE.match(line)
|
|
60
|
+
submodule_export_match = FORTRAN_SUBMOD_RE.match(line)
|
|
61
|
+
if import_match:
|
|
62
|
+
needed = import_match.group(1).lower()
|
|
63
|
+
# In Fortran you have an using declaration also for the module
|
|
64
|
+
# you define in the same file. Prevent circular dependencies.
|
|
65
|
+
if needed not in modules_in_this_file:
|
|
66
|
+
if fname in self.needs:
|
|
67
|
+
self.needs[fname].append(needed)
|
|
68
|
+
else:
|
|
69
|
+
self.needs[fname] = [needed]
|
|
70
|
+
if export_match:
|
|
71
|
+
exported_module = export_match.group(1).lower()
|
|
72
|
+
assert exported_module not in modules_in_this_file
|
|
73
|
+
modules_in_this_file.add(exported_module)
|
|
74
|
+
if exported_module in self.provided_by:
|
|
75
|
+
raise RuntimeError(f'Multiple files provide module {exported_module}.')
|
|
76
|
+
self.sources_with_exports.append(fname)
|
|
77
|
+
self.provided_by[exported_module] = fname
|
|
78
|
+
self.exports[fname] = exported_module
|
|
79
|
+
if submodule_export_match:
|
|
80
|
+
# Store submodule "Foo" "Bar" as "foo:bar".
|
|
81
|
+
# A submodule declaration can be both an import and an export declaration:
|
|
82
|
+
#
|
|
83
|
+
# submodule (a1:a2) a3
|
|
84
|
+
# - requires a1@a2.smod
|
|
85
|
+
# - produces a1@a3.smod
|
|
86
|
+
parent_module_name_full = submodule_export_match.group(1).lower()
|
|
87
|
+
parent_module_name = parent_module_name_full.split(':')[0]
|
|
88
|
+
submodule_name = submodule_export_match.group(2).lower()
|
|
89
|
+
concat_name = f'{parent_module_name}:{submodule_name}'
|
|
90
|
+
self.sources_with_exports.append(fname)
|
|
91
|
+
self.provided_by[concat_name] = fname
|
|
92
|
+
self.exports[fname] = concat_name
|
|
93
|
+
# Fortran requires that the immediate parent module must be built
|
|
94
|
+
# before the current one. Thus:
|
|
95
|
+
#
|
|
96
|
+
# submodule (parent) parent <- requires parent.mod (really parent.smod, but they are created at the same time)
|
|
97
|
+
# submodule (a1:a2) a3 <- requires a1@a2.smod
|
|
98
|
+
#
|
|
99
|
+
# a3 does not depend on the a1 parent module directly, only transitively.
|
|
100
|
+
if fname in self.needs:
|
|
101
|
+
self.needs[fname].append(parent_module_name_full)
|
|
102
|
+
else:
|
|
103
|
+
self.needs[fname] = [parent_module_name_full]
|
|
104
|
+
|
|
105
|
+
def scan_cpp_file(self, fname: str) -> None:
|
|
106
|
+
fpath = pathlib.Path(fname)
|
|
107
|
+
for line in fpath.read_text(encoding='utf-8', errors='ignore').split('\n'):
|
|
108
|
+
import_match = CPP_IMPORT_RE.match(line)
|
|
109
|
+
export_match = CPP_EXPORT_RE.match(line)
|
|
110
|
+
if import_match:
|
|
111
|
+
needed = import_match.group(1)
|
|
112
|
+
if fname in self.needs:
|
|
113
|
+
self.needs[fname].append(needed)
|
|
114
|
+
else:
|
|
115
|
+
self.needs[fname] = [needed]
|
|
116
|
+
if export_match:
|
|
117
|
+
exported_module = export_match.group(1)
|
|
118
|
+
if exported_module in self.provided_by:
|
|
119
|
+
raise RuntimeError(f'Multiple files provide module {exported_module}.')
|
|
120
|
+
self.sources_with_exports.append(fname)
|
|
121
|
+
self.provided_by[exported_module] = fname
|
|
122
|
+
self.exports[fname] = exported_module
|
|
123
|
+
|
|
124
|
+
def objname_for(self, src: str) -> str:
|
|
125
|
+
objname = self.target_data.source2object[src]
|
|
126
|
+
assert isinstance(objname, str)
|
|
127
|
+
return objname
|
|
128
|
+
|
|
129
|
+
def module_name_for(self, src: str) -> str:
|
|
130
|
+
suffix = os.path.splitext(src)[1][1:].lower()
|
|
131
|
+
if suffix in lang_suffixes['fortran']:
|
|
132
|
+
exported = self.exports[src]
|
|
133
|
+
# Module foo:bar goes to a file name foo@bar.smod
|
|
134
|
+
# Module Foo goes to a file name foo.mod
|
|
135
|
+
namebase = exported.replace(':', '@')
|
|
136
|
+
if ':' in exported:
|
|
137
|
+
extension = 'smod'
|
|
138
|
+
else:
|
|
139
|
+
extension = 'mod'
|
|
140
|
+
return os.path.join(self.target_data.private_dir, f'{namebase}.{extension}')
|
|
141
|
+
elif suffix in lang_suffixes['cpp']:
|
|
142
|
+
return '{}.ifc'.format(self.exports[src])
|
|
143
|
+
else:
|
|
144
|
+
raise RuntimeError('Unreachable code.')
|
|
145
|
+
|
|
146
|
+
def scan(self) -> int:
|
|
147
|
+
for s in self.sources:
|
|
148
|
+
self.scan_file(s)
|
|
149
|
+
with open(self.outfile, 'w', encoding='utf-8') as ofile:
|
|
150
|
+
ofile.write('ninja_dyndep_version = 1\n')
|
|
151
|
+
for src in self.sources:
|
|
152
|
+
objfilename = self.objname_for(src)
|
|
153
|
+
mods_and_submods_needed = []
|
|
154
|
+
module_files_generated = []
|
|
155
|
+
module_files_needed = []
|
|
156
|
+
if src in self.sources_with_exports:
|
|
157
|
+
module_files_generated.append(self.module_name_for(src))
|
|
158
|
+
if src in self.needs:
|
|
159
|
+
for modname in self.needs[src]:
|
|
160
|
+
if modname not in self.provided_by:
|
|
161
|
+
# Nothing provides this module, we assume that it
|
|
162
|
+
# comes from a dependency library somewhere and is
|
|
163
|
+
# already built by the time this compilation starts.
|
|
164
|
+
pass
|
|
165
|
+
else:
|
|
166
|
+
mods_and_submods_needed.append(modname)
|
|
167
|
+
|
|
168
|
+
for modname in mods_and_submods_needed:
|
|
169
|
+
provider_src = self.provided_by[modname]
|
|
170
|
+
provider_modfile = self.module_name_for(provider_src)
|
|
171
|
+
# Prune self-dependencies
|
|
172
|
+
if provider_src != src:
|
|
173
|
+
module_files_needed.append(provider_modfile)
|
|
174
|
+
|
|
175
|
+
quoted_objfilename = ninja_quote(objfilename, True)
|
|
176
|
+
quoted_module_files_generated = [ninja_quote(x, True) for x in module_files_generated]
|
|
177
|
+
quoted_module_files_needed = [ninja_quote(x, True) for x in module_files_needed]
|
|
178
|
+
if quoted_module_files_generated:
|
|
179
|
+
mod_gen = '| ' + ' '.join(quoted_module_files_generated)
|
|
180
|
+
else:
|
|
181
|
+
mod_gen = ''
|
|
182
|
+
if quoted_module_files_needed:
|
|
183
|
+
mod_dep = '| ' + ' '.join(quoted_module_files_needed)
|
|
184
|
+
else:
|
|
185
|
+
mod_dep = ''
|
|
186
|
+
build_line = 'build {} {}: dyndep {}'.format(quoted_objfilename,
|
|
187
|
+
mod_gen,
|
|
188
|
+
mod_dep)
|
|
189
|
+
ofile.write(build_line + '\n')
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
def run(args: T.List[str]) -> int:
|
|
193
|
+
assert len(args) == 3, 'got wrong number of arguments!'
|
|
194
|
+
pickle_file, outfile, jsonfile = args
|
|
195
|
+
with open(jsonfile, encoding='utf-8') as f:
|
|
196
|
+
sources = json.load(f)
|
|
197
|
+
scanner = DependencyScanner(pickle_file, outfile, sources)
|
|
198
|
+
return scanner.scan()
|