frida 16.2.0 → 16.2.2

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.
Files changed (386) hide show
  1. package/BSDmakefile +6 -0
  2. package/Makefile +16 -0
  3. package/README.md +14 -11
  4. package/configure +18 -0
  5. package/configure.bat +22 -0
  6. package/dist/native.js +0 -8
  7. package/lib/application.ts +98 -0
  8. package/lib/authentication.ts +3 -0
  9. package/lib/build.py +50 -0
  10. package/lib/bus.ts +30 -0
  11. package/lib/cancellable.ts +33 -0
  12. package/lib/child.ts +15 -0
  13. package/lib/crash.ts +11 -0
  14. package/lib/device.ts +329 -0
  15. package/lib/device_manager.ts +69 -0
  16. package/lib/endpoint_parameters.ts +56 -0
  17. package/lib/icon.ts +15 -0
  18. package/lib/index.ts +311 -0
  19. package/lib/iostream.ts +78 -0
  20. package/lib/meson.build +53 -0
  21. package/lib/native.ts +9 -0
  22. package/lib/portal_membership.ts +10 -0
  23. package/lib/portal_service.ts +105 -0
  24. package/lib/process.ts +57 -0
  25. package/lib/relay.ts +44 -0
  26. package/lib/script.ts +352 -0
  27. package/lib/session.ts +113 -0
  28. package/lib/signals.ts +45 -0
  29. package/lib/socket_address.ts +35 -0
  30. package/lib/spawn.ts +4 -0
  31. package/lib/system_parameters.ts +78 -0
  32. package/make.bat +23 -0
  33. package/meson.build +160 -0
  34. package/meson.options +11 -0
  35. package/package.json +27 -6
  36. package/releng/deps.py +1133 -0
  37. package/releng/deps.toml +391 -0
  38. package/releng/devkit-assets/frida-core-example-unix.c +188 -0
  39. package/releng/devkit-assets/frida-core-example-windows.c +197 -0
  40. package/releng/devkit-assets/frida-core-example.sln +28 -0
  41. package/releng/devkit-assets/frida-core-example.vcxproj +157 -0
  42. package/releng/devkit-assets/frida-core-example.vcxproj.filters +27 -0
  43. package/releng/devkit-assets/frida-gum-example-unix.c +122 -0
  44. package/releng/devkit-assets/frida-gum-example-windows.c +132 -0
  45. package/releng/devkit-assets/frida-gum-example.sln +28 -0
  46. package/releng/devkit-assets/frida-gum-example.vcxproj +157 -0
  47. package/releng/devkit-assets/frida-gum-example.vcxproj.filters +27 -0
  48. package/releng/devkit-assets/frida-gumjs-example-unix.c +84 -0
  49. package/releng/devkit-assets/frida-gumjs-example-windows.c +91 -0
  50. package/releng/devkit-assets/frida-gumjs-example.sln +28 -0
  51. package/releng/devkit-assets/frida-gumjs-example.vcxproj +157 -0
  52. package/releng/devkit-assets/frida-gumjs-example.vcxproj.filters +27 -0
  53. package/releng/devkit.py +535 -0
  54. package/releng/env.py +420 -0
  55. package/releng/env_android.py +150 -0
  56. package/releng/env_apple.py +176 -0
  57. package/releng/env_generic.py +373 -0
  58. package/releng/frida_version.py +69 -0
  59. package/releng/machine_file.py +44 -0
  60. package/releng/machine_spec.py +290 -0
  61. package/releng/meson/meson.py +27 -0
  62. package/releng/meson/mesonbuild/__init__.py +0 -0
  63. package/releng/meson/mesonbuild/_pathlib.py +63 -0
  64. package/releng/meson/mesonbuild/_typing.py +69 -0
  65. package/releng/meson/mesonbuild/arglist.py +321 -0
  66. package/releng/meson/mesonbuild/ast/__init__.py +23 -0
  67. package/releng/meson/mesonbuild/ast/interpreter.py +441 -0
  68. package/releng/meson/mesonbuild/ast/introspection.py +374 -0
  69. package/releng/meson/mesonbuild/ast/postprocess.py +109 -0
  70. package/releng/meson/mesonbuild/ast/printer.py +620 -0
  71. package/releng/meson/mesonbuild/ast/visitor.py +161 -0
  72. package/releng/meson/mesonbuild/backend/__init__.py +0 -0
  73. package/releng/meson/mesonbuild/backend/backends.py +2047 -0
  74. package/releng/meson/mesonbuild/backend/ninjabackend.py +3808 -0
  75. package/releng/meson/mesonbuild/backend/nonebackend.py +26 -0
  76. package/releng/meson/mesonbuild/backend/vs2010backend.py +2078 -0
  77. package/releng/meson/mesonbuild/backend/vs2012backend.py +35 -0
  78. package/releng/meson/mesonbuild/backend/vs2013backend.py +34 -0
  79. package/releng/meson/mesonbuild/backend/vs2015backend.py +35 -0
  80. package/releng/meson/mesonbuild/backend/vs2017backend.py +59 -0
  81. package/releng/meson/mesonbuild/backend/vs2019backend.py +54 -0
  82. package/releng/meson/mesonbuild/backend/vs2022backend.py +54 -0
  83. package/releng/meson/mesonbuild/backend/xcodebackend.py +1781 -0
  84. package/releng/meson/mesonbuild/build.py +3249 -0
  85. package/releng/meson/mesonbuild/cargo/__init__.py +5 -0
  86. package/releng/meson/mesonbuild/cargo/builder.py +238 -0
  87. package/releng/meson/mesonbuild/cargo/cfg.py +274 -0
  88. package/releng/meson/mesonbuild/cargo/interpreter.py +733 -0
  89. package/releng/meson/mesonbuild/cargo/manifest.py +227 -0
  90. package/releng/meson/mesonbuild/cargo/version.py +95 -0
  91. package/releng/meson/mesonbuild/cmake/__init__.py +28 -0
  92. package/releng/meson/mesonbuild/cmake/common.py +331 -0
  93. package/releng/meson/mesonbuild/cmake/data/__init__.py +0 -0
  94. package/releng/meson/mesonbuild/cmake/data/preload.cmake +82 -0
  95. package/releng/meson/mesonbuild/cmake/executor.py +241 -0
  96. package/releng/meson/mesonbuild/cmake/fileapi.py +324 -0
  97. package/releng/meson/mesonbuild/cmake/generator.py +186 -0
  98. package/releng/meson/mesonbuild/cmake/interpreter.py +1267 -0
  99. package/releng/meson/mesonbuild/cmake/toolchain.py +248 -0
  100. package/releng/meson/mesonbuild/cmake/traceparser.py +814 -0
  101. package/releng/meson/mesonbuild/cmake/tracetargets.py +161 -0
  102. package/releng/meson/mesonbuild/compilers/__init__.py +86 -0
  103. package/releng/meson/mesonbuild/compilers/asm.py +307 -0
  104. package/releng/meson/mesonbuild/compilers/c.py +788 -0
  105. package/releng/meson/mesonbuild/compilers/c_function_attributes.py +143 -0
  106. package/releng/meson/mesonbuild/compilers/compilers.py +1388 -0
  107. package/releng/meson/mesonbuild/compilers/cpp.py +1035 -0
  108. package/releng/meson/mesonbuild/compilers/cs.py +136 -0
  109. package/releng/meson/mesonbuild/compilers/cuda.py +806 -0
  110. package/releng/meson/mesonbuild/compilers/cython.py +91 -0
  111. package/releng/meson/mesonbuild/compilers/d.py +861 -0
  112. package/releng/meson/mesonbuild/compilers/detect.py +1396 -0
  113. package/releng/meson/mesonbuild/compilers/fortran.py +523 -0
  114. package/releng/meson/mesonbuild/compilers/java.py +113 -0
  115. package/releng/meson/mesonbuild/compilers/mixins/__init__.py +0 -0
  116. package/releng/meson/mesonbuild/compilers/mixins/arm.py +167 -0
  117. package/releng/meson/mesonbuild/compilers/mixins/ccrx.py +113 -0
  118. package/releng/meson/mesonbuild/compilers/mixins/clang.py +170 -0
  119. package/releng/meson/mesonbuild/compilers/mixins/clike.py +1330 -0
  120. package/releng/meson/mesonbuild/compilers/mixins/compcert.py +117 -0
  121. package/releng/meson/mesonbuild/compilers/mixins/elbrus.py +93 -0
  122. package/releng/meson/mesonbuild/compilers/mixins/emscripten.py +89 -0
  123. package/releng/meson/mesonbuild/compilers/mixins/gnu.py +629 -0
  124. package/releng/meson/mesonbuild/compilers/mixins/intel.py +167 -0
  125. package/releng/meson/mesonbuild/compilers/mixins/islinker.py +120 -0
  126. package/releng/meson/mesonbuild/compilers/mixins/metrowerks.py +279 -0
  127. package/releng/meson/mesonbuild/compilers/mixins/pgi.py +88 -0
  128. package/releng/meson/mesonbuild/compilers/mixins/ti.py +130 -0
  129. package/releng/meson/mesonbuild/compilers/mixins/visualstudio.py +458 -0
  130. package/releng/meson/mesonbuild/compilers/mixins/xc16.py +111 -0
  131. package/releng/meson/mesonbuild/compilers/objc.py +120 -0
  132. package/releng/meson/mesonbuild/compilers/objcpp.py +102 -0
  133. package/releng/meson/mesonbuild/compilers/rust.py +230 -0
  134. package/releng/meson/mesonbuild/compilers/swift.py +131 -0
  135. package/releng/meson/mesonbuild/compilers/vala.py +121 -0
  136. package/releng/meson/mesonbuild/coredata.py +1532 -0
  137. package/releng/meson/mesonbuild/dependencies/__init__.py +252 -0
  138. package/releng/meson/mesonbuild/dependencies/base.py +663 -0
  139. package/releng/meson/mesonbuild/dependencies/boost.py +1083 -0
  140. package/releng/meson/mesonbuild/dependencies/cmake.py +656 -0
  141. package/releng/meson/mesonbuild/dependencies/coarrays.py +80 -0
  142. package/releng/meson/mesonbuild/dependencies/configtool.py +163 -0
  143. package/releng/meson/mesonbuild/dependencies/cuda.py +295 -0
  144. package/releng/meson/mesonbuild/dependencies/data/CMakeLists.txt +102 -0
  145. package/releng/meson/mesonbuild/dependencies/data/CMakeListsLLVM.txt +204 -0
  146. package/releng/meson/mesonbuild/dependencies/data/CMakePathInfo.txt +31 -0
  147. package/releng/meson/mesonbuild/dependencies/data/__init__.py +0 -0
  148. package/releng/meson/mesonbuild/dependencies/detect.py +225 -0
  149. package/releng/meson/mesonbuild/dependencies/dev.py +707 -0
  150. package/releng/meson/mesonbuild/dependencies/dub.py +424 -0
  151. package/releng/meson/mesonbuild/dependencies/factory.py +146 -0
  152. package/releng/meson/mesonbuild/dependencies/framework.py +111 -0
  153. package/releng/meson/mesonbuild/dependencies/hdf5.py +168 -0
  154. package/releng/meson/mesonbuild/dependencies/misc.py +618 -0
  155. package/releng/meson/mesonbuild/dependencies/mpi.py +231 -0
  156. package/releng/meson/mesonbuild/dependencies/pkgconfig.py +570 -0
  157. package/releng/meson/mesonbuild/dependencies/platform.py +52 -0
  158. package/releng/meson/mesonbuild/dependencies/python.py +431 -0
  159. package/releng/meson/mesonbuild/dependencies/qt.py +484 -0
  160. package/releng/meson/mesonbuild/dependencies/scalapack.py +142 -0
  161. package/releng/meson/mesonbuild/dependencies/ui.py +281 -0
  162. package/releng/meson/mesonbuild/depfile.py +82 -0
  163. package/releng/meson/mesonbuild/envconfig.py +480 -0
  164. package/releng/meson/mesonbuild/environment.py +987 -0
  165. package/releng/meson/mesonbuild/interpreter/__init__.py +47 -0
  166. package/releng/meson/mesonbuild/interpreter/compiler.py +900 -0
  167. package/releng/meson/mesonbuild/interpreter/dependencyfallbacks.py +386 -0
  168. package/releng/meson/mesonbuild/interpreter/interpreter.py +3595 -0
  169. package/releng/meson/mesonbuild/interpreter/interpreterobjects.py +1096 -0
  170. package/releng/meson/mesonbuild/interpreter/kwargs.py +479 -0
  171. package/releng/meson/mesonbuild/interpreter/mesonmain.py +487 -0
  172. package/releng/meson/mesonbuild/interpreter/primitives/__init__.py +29 -0
  173. package/releng/meson/mesonbuild/interpreter/primitives/array.py +108 -0
  174. package/releng/meson/mesonbuild/interpreter/primitives/boolean.py +52 -0
  175. package/releng/meson/mesonbuild/interpreter/primitives/dict.py +88 -0
  176. package/releng/meson/mesonbuild/interpreter/primitives/integer.py +86 -0
  177. package/releng/meson/mesonbuild/interpreter/primitives/range.py +38 -0
  178. package/releng/meson/mesonbuild/interpreter/primitives/string.py +247 -0
  179. package/releng/meson/mesonbuild/interpreter/type_checking.py +853 -0
  180. package/releng/meson/mesonbuild/interpreterbase/__init__.py +126 -0
  181. package/releng/meson/mesonbuild/interpreterbase/_unholder.py +25 -0
  182. package/releng/meson/mesonbuild/interpreterbase/baseobjects.py +174 -0
  183. package/releng/meson/mesonbuild/interpreterbase/decorators.py +806 -0
  184. package/releng/meson/mesonbuild/interpreterbase/disabler.py +35 -0
  185. package/releng/meson/mesonbuild/interpreterbase/exceptions.py +22 -0
  186. package/releng/meson/mesonbuild/interpreterbase/helpers.py +67 -0
  187. package/releng/meson/mesonbuild/interpreterbase/interpreterbase.py +665 -0
  188. package/releng/meson/mesonbuild/interpreterbase/operator.py +32 -0
  189. package/releng/meson/mesonbuild/linkers/__init__.py +20 -0
  190. package/releng/meson/mesonbuild/linkers/base.py +39 -0
  191. package/releng/meson/mesonbuild/linkers/detect.py +229 -0
  192. package/releng/meson/mesonbuild/linkers/linkers.py +1614 -0
  193. package/releng/meson/mesonbuild/mcompile.py +380 -0
  194. package/releng/meson/mesonbuild/mconf.py +368 -0
  195. package/releng/meson/mesonbuild/mdevenv.py +234 -0
  196. package/releng/meson/mesonbuild/mdist.py +376 -0
  197. package/releng/meson/mesonbuild/mesondata.py +38 -0
  198. package/releng/meson/mesonbuild/mesonlib.py +23 -0
  199. package/releng/meson/mesonbuild/mesonmain.py +289 -0
  200. package/releng/meson/mesonbuild/minit.py +204 -0
  201. package/releng/meson/mesonbuild/minstall.py +864 -0
  202. package/releng/meson/mesonbuild/mintro.py +667 -0
  203. package/releng/meson/mesonbuild/mlog.py +542 -0
  204. package/releng/meson/mesonbuild/modules/__init__.py +270 -0
  205. package/releng/meson/mesonbuild/modules/cmake.py +442 -0
  206. package/releng/meson/mesonbuild/modules/cuda.py +377 -0
  207. package/releng/meson/mesonbuild/modules/dlang.py +117 -0
  208. package/releng/meson/mesonbuild/modules/external_project.py +306 -0
  209. package/releng/meson/mesonbuild/modules/fs.py +323 -0
  210. package/releng/meson/mesonbuild/modules/gnome.py +2215 -0
  211. package/releng/meson/mesonbuild/modules/hotdoc.py +487 -0
  212. package/releng/meson/mesonbuild/modules/i18n.py +405 -0
  213. package/releng/meson/mesonbuild/modules/icestorm.py +123 -0
  214. package/releng/meson/mesonbuild/modules/java.py +112 -0
  215. package/releng/meson/mesonbuild/modules/keyval.py +65 -0
  216. package/releng/meson/mesonbuild/modules/modtest.py +33 -0
  217. package/releng/meson/mesonbuild/modules/pkgconfig.py +744 -0
  218. package/releng/meson/mesonbuild/modules/python.py +556 -0
  219. package/releng/meson/mesonbuild/modules/python3.py +85 -0
  220. package/releng/meson/mesonbuild/modules/qt.py +621 -0
  221. package/releng/meson/mesonbuild/modules/qt4.py +23 -0
  222. package/releng/meson/mesonbuild/modules/qt5.py +23 -0
  223. package/releng/meson/mesonbuild/modules/qt6.py +22 -0
  224. package/releng/meson/mesonbuild/modules/rust.py +355 -0
  225. package/releng/meson/mesonbuild/modules/simd.py +114 -0
  226. package/releng/meson/mesonbuild/modules/sourceset.py +291 -0
  227. package/releng/meson/mesonbuild/modules/wayland.py +151 -0
  228. package/releng/meson/mesonbuild/modules/windows.py +207 -0
  229. package/releng/meson/mesonbuild/mparser.py +1114 -0
  230. package/releng/meson/mesonbuild/msetup.py +365 -0
  231. package/releng/meson/mesonbuild/msubprojects.py +764 -0
  232. package/releng/meson/mesonbuild/mtest.py +2201 -0
  233. package/releng/meson/mesonbuild/munstable_coredata.py +107 -0
  234. package/releng/meson/mesonbuild/optinterpreter.py +276 -0
  235. package/releng/meson/mesonbuild/programs.py +367 -0
  236. package/releng/meson/mesonbuild/rewriter.py +1075 -0
  237. package/releng/meson/mesonbuild/scripts/__init__.py +10 -0
  238. package/releng/meson/mesonbuild/scripts/clangformat.py +55 -0
  239. package/releng/meson/mesonbuild/scripts/clangtidy.py +30 -0
  240. package/releng/meson/mesonbuild/scripts/cleantrees.py +35 -0
  241. package/releng/meson/mesonbuild/scripts/cmake_run_ctgt.py +103 -0
  242. package/releng/meson/mesonbuild/scripts/cmd_or_ps.ps1 +17 -0
  243. package/releng/meson/mesonbuild/scripts/copy.py +19 -0
  244. package/releng/meson/mesonbuild/scripts/coverage.py +214 -0
  245. package/releng/meson/mesonbuild/scripts/delwithsuffix.py +27 -0
  246. package/releng/meson/mesonbuild/scripts/depfixer.py +495 -0
  247. package/releng/meson/mesonbuild/scripts/depscan.py +198 -0
  248. package/releng/meson/mesonbuild/scripts/dirchanger.py +20 -0
  249. package/releng/meson/mesonbuild/scripts/env2mfile.py +402 -0
  250. package/releng/meson/mesonbuild/scripts/externalproject.py +106 -0
  251. package/releng/meson/mesonbuild/scripts/gettext.py +86 -0
  252. package/releng/meson/mesonbuild/scripts/gtkdochelper.py +286 -0
  253. package/releng/meson/mesonbuild/scripts/hotdochelper.py +40 -0
  254. package/releng/meson/mesonbuild/scripts/itstool.py +77 -0
  255. package/releng/meson/mesonbuild/scripts/meson_exe.py +115 -0
  256. package/releng/meson/mesonbuild/scripts/msgfmthelper.py +29 -0
  257. package/releng/meson/mesonbuild/scripts/pycompile.py +54 -0
  258. package/releng/meson/mesonbuild/scripts/python_info.py +121 -0
  259. package/releng/meson/mesonbuild/scripts/regen_checker.py +55 -0
  260. package/releng/meson/mesonbuild/scripts/run_tool.py +58 -0
  261. package/releng/meson/mesonbuild/scripts/scanbuild.py +57 -0
  262. package/releng/meson/mesonbuild/scripts/symbolextractor.py +322 -0
  263. package/releng/meson/mesonbuild/scripts/tags.py +44 -0
  264. package/releng/meson/mesonbuild/scripts/test_loaded_modules.py +14 -0
  265. package/releng/meson/mesonbuild/scripts/uninstall.py +41 -0
  266. package/releng/meson/mesonbuild/scripts/vcstagger.py +35 -0
  267. package/releng/meson/mesonbuild/scripts/yasm.py +24 -0
  268. package/releng/meson/mesonbuild/templates/__init__.py +0 -0
  269. package/releng/meson/mesonbuild/templates/cpptemplates.py +143 -0
  270. package/releng/meson/mesonbuild/templates/cstemplates.py +90 -0
  271. package/releng/meson/mesonbuild/templates/ctemplates.py +126 -0
  272. package/releng/meson/mesonbuild/templates/cudatemplates.py +143 -0
  273. package/releng/meson/mesonbuild/templates/dlangtemplates.py +109 -0
  274. package/releng/meson/mesonbuild/templates/fortrantemplates.py +101 -0
  275. package/releng/meson/mesonbuild/templates/javatemplates.py +94 -0
  276. package/releng/meson/mesonbuild/templates/mesontemplates.py +70 -0
  277. package/releng/meson/mesonbuild/templates/objcpptemplates.py +126 -0
  278. package/releng/meson/mesonbuild/templates/objctemplates.py +126 -0
  279. package/releng/meson/mesonbuild/templates/rusttemplates.py +79 -0
  280. package/releng/meson/mesonbuild/templates/samplefactory.py +41 -0
  281. package/releng/meson/mesonbuild/templates/sampleimpl.py +160 -0
  282. package/releng/meson/mesonbuild/templates/valatemplates.py +82 -0
  283. package/releng/meson/mesonbuild/utils/__init__.py +0 -0
  284. package/releng/meson/mesonbuild/utils/core.py +166 -0
  285. package/releng/meson/mesonbuild/utils/platform.py +27 -0
  286. package/releng/meson/mesonbuild/utils/posix.py +32 -0
  287. package/releng/meson/mesonbuild/utils/universal.py +2445 -0
  288. package/releng/meson/mesonbuild/utils/vsenv.py +126 -0
  289. package/releng/meson/mesonbuild/utils/win32.py +29 -0
  290. package/releng/meson/mesonbuild/wrap/__init__.py +59 -0
  291. package/releng/meson/mesonbuild/wrap/wrap.py +846 -0
  292. package/releng/meson/mesonbuild/wrap/wraptool.py +198 -0
  293. package/releng/meson-scripts/BSDmakefile +6 -0
  294. package/releng/meson-scripts/Makefile +16 -0
  295. package/releng/meson-scripts/configure +18 -0
  296. package/releng/meson-scripts/configure.bat +22 -0
  297. package/releng/meson-scripts/make.bat +23 -0
  298. package/releng/meson_configure.py +506 -0
  299. package/releng/meson_make.py +131 -0
  300. package/releng/mkdevkit.py +107 -0
  301. package/releng/mkfatmacho.py +54 -0
  302. package/releng/post-process-oabi.py +97 -0
  303. package/releng/progress.py +14 -0
  304. package/releng/sync-from-upstream.py +185 -0
  305. package/releng/tomlkit/tomlkit/__init__.py +59 -0
  306. package/releng/tomlkit/tomlkit/_compat.py +22 -0
  307. package/releng/tomlkit/tomlkit/_types.py +83 -0
  308. package/releng/tomlkit/tomlkit/_utils.py +158 -0
  309. package/releng/tomlkit/tomlkit/api.py +308 -0
  310. package/releng/tomlkit/tomlkit/container.py +875 -0
  311. package/releng/tomlkit/tomlkit/exceptions.py +227 -0
  312. package/releng/tomlkit/tomlkit/items.py +1967 -0
  313. package/releng/tomlkit/tomlkit/parser.py +1141 -0
  314. package/releng/tomlkit/tomlkit/py.typed +0 -0
  315. package/releng/tomlkit/tomlkit/source.py +180 -0
  316. package/releng/tomlkit/tomlkit/toml_char.py +52 -0
  317. package/releng/tomlkit/tomlkit/toml_document.py +7 -0
  318. package/releng/tomlkit/tomlkit/toml_file.py +58 -0
  319. package/releng/winenv.py +140 -0
  320. package/scripts/adjust-version.py +19 -0
  321. package/scripts/detect-version.py +40 -0
  322. package/scripts/fetch-abi-bits.py +343 -0
  323. package/scripts/install.js +23 -0
  324. package/scripts/package.py +15 -0
  325. package/src/addon.cc +76 -0
  326. package/src/application.cc +148 -0
  327. package/src/application.h +31 -0
  328. package/src/authentication.cc +174 -0
  329. package/src/authentication.h +24 -0
  330. package/src/bus.cc +167 -0
  331. package/src/bus.h +33 -0
  332. package/src/cancellable.cc +117 -0
  333. package/src/cancellable.h +31 -0
  334. package/src/child.cc +150 -0
  335. package/src/child.h +32 -0
  336. package/src/crash.cc +122 -0
  337. package/src/crash.h +30 -0
  338. package/src/device.cc +1302 -0
  339. package/src/device.h +55 -0
  340. package/src/device_manager.cc +362 -0
  341. package/src/device_manager.h +35 -0
  342. package/src/endpoint_parameters.cc +171 -0
  343. package/src/endpoint_parameters.h +28 -0
  344. package/src/glib_context.cc +62 -0
  345. package/src/glib_context.h +29 -0
  346. package/src/glib_object.cc +25 -0
  347. package/src/glib_object.h +37 -0
  348. package/src/iostream.cc +247 -0
  349. package/src/iostream.h +30 -0
  350. package/src/meson.build +26 -0
  351. package/src/operation.h +94 -0
  352. package/src/portal_membership.cc +100 -0
  353. package/src/portal_membership.h +26 -0
  354. package/src/portal_service.cc +401 -0
  355. package/src/portal_service.h +40 -0
  356. package/src/process.cc +135 -0
  357. package/src/process.h +30 -0
  358. package/src/relay.cc +139 -0
  359. package/src/relay.h +31 -0
  360. package/src/runtime.cc +443 -0
  361. package/src/runtime.h +64 -0
  362. package/src/script.cc +301 -0
  363. package/src/script.h +36 -0
  364. package/src/session.cc +860 -0
  365. package/src/session.h +42 -0
  366. package/src/signals.cc +334 -0
  367. package/src/signals.h +47 -0
  368. package/src/spawn.cc +95 -0
  369. package/src/spawn.h +27 -0
  370. package/src/usage_monitor.h +117 -0
  371. package/src/uv_context.cc +118 -0
  372. package/src/uv_context.h +40 -0
  373. package/src/win_delay_load_hook.cc +63 -0
  374. package/subprojects/frida-core.wrap +8 -0
  375. package/subprojects/nan.wrap +9 -0
  376. package/subprojects/packagefiles/nan.patch +13 -0
  377. package/test/data/index.ts +13 -0
  378. package/test/data/unixvictim-linux-x86 +0 -0
  379. package/test/data/unixvictim-linux-x86_64 +0 -0
  380. package/test/data/unixvictim-macos +0 -0
  381. package/test/device.ts +27 -0
  382. package/test/device_manager.ts +16 -0
  383. package/test/labrat.ts +32 -0
  384. package/test/script.ts +176 -0
  385. package/test/session.ts +73 -0
  386. package/tsconfig.json +18 -0
@@ -0,0 +1,1075 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright 2016 The Meson development team
3
+
4
+ # This tool is used to manipulate an existing Meson build definition.
5
+ #
6
+ # - add a file to a target
7
+ # - remove files from a target
8
+ # - move targets
9
+ # - reindent?
10
+ from __future__ import annotations
11
+
12
+ from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstPrinter
13
+ from mesonbuild.mesonlib import MesonException, setup_vsenv
14
+ from . import mlog, environment
15
+ from functools import wraps
16
+ from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseStringNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, StringNode, SymbolNode
17
+ import json, os, re, sys
18
+ import typing as T
19
+
20
+ if T.TYPE_CHECKING:
21
+ from argparse import ArgumentParser, HelpFormatter
22
+ from .mparser import BaseNode
23
+
24
+ class RewriterException(MesonException):
25
+ pass
26
+
27
+ # Note: when adding arguments, please also add them to the completion
28
+ # scripts in $MESONSRC/data/shell-completions/
29
+ def add_arguments(parser: ArgumentParser, formatter: T.Callable[[str], HelpFormatter]) -> None:
30
+ parser.add_argument('-s', '--sourcedir', type=str, default='.', metavar='SRCDIR', help='Path to source directory.')
31
+ parser.add_argument('-V', '--verbose', action='store_true', default=False, help='Enable verbose output')
32
+ parser.add_argument('-S', '--skip-errors', dest='skip', action='store_true', default=False, help='Skip errors instead of aborting')
33
+ subparsers = parser.add_subparsers(dest='type', title='Rewriter commands', description='Rewrite command to execute')
34
+
35
+ # Target
36
+ tgt_parser = subparsers.add_parser('target', aliases=['tgt'], help='Modify a target', formatter_class=formatter)
37
+ tgt_parser.add_argument('-s', '--subdir', default='', dest='subdir', help='Subdirectory of the new target (only for the "add_target" action)')
38
+ tgt_parser.add_argument('--type', dest='tgt_type', choices=rewriter_keys['target']['target_type'][2], default='executable',
39
+ help='Type of the target to add (only for the "add_target" action)')
40
+ tgt_parser.add_argument('target', help='Name or ID of the target')
41
+ tgt_parser.add_argument('operation', choices=['add', 'rm', 'add_target', 'rm_target', 'add_extra_files', 'rm_extra_files', 'info'],
42
+ help='Action to execute')
43
+ tgt_parser.add_argument('sources', nargs='*', help='Sources to add/remove')
44
+
45
+ # KWARGS
46
+ kw_parser = subparsers.add_parser('kwargs', help='Modify keyword arguments', formatter_class=formatter)
47
+ kw_parser.add_argument('operation', choices=rewriter_keys['kwargs']['operation'][2],
48
+ help='Action to execute')
49
+ kw_parser.add_argument('function', choices=list(rewriter_func_kwargs.keys()),
50
+ help='Function type to modify')
51
+ kw_parser.add_argument('id', help='ID of the function to modify (can be anything for "project")')
52
+ kw_parser.add_argument('kwargs', nargs='*', help='Pairs of keyword and value')
53
+
54
+ # Default options
55
+ def_parser = subparsers.add_parser('default-options', aliases=['def'], help='Modify the project default options', formatter_class=formatter)
56
+ def_parser.add_argument('operation', choices=rewriter_keys['default_options']['operation'][2],
57
+ help='Action to execute')
58
+ def_parser.add_argument('options', nargs='*', help='Key, value pairs of configuration option')
59
+
60
+ # JSON file/command
61
+ cmd_parser = subparsers.add_parser('command', aliases=['cmd'], help='Execute a JSON array of commands', formatter_class=formatter)
62
+ cmd_parser.add_argument('json', help='JSON string or file to execute')
63
+
64
+ class RequiredKeys:
65
+ def __init__(self, keys):
66
+ self.keys = keys
67
+
68
+ def __call__(self, f):
69
+ @wraps(f)
70
+ def wrapped(*wrapped_args, **wrapped_kwargs):
71
+ assert len(wrapped_args) >= 2
72
+ cmd = wrapped_args[1]
73
+ for key, val in self.keys.items():
74
+ typ = val[0] # The type of the value
75
+ default = val[1] # The default value -- None is required
76
+ choices = val[2] # Valid choices -- None is for everything
77
+ if key not in cmd:
78
+ if default is not None:
79
+ cmd[key] = default
80
+ else:
81
+ raise RewriterException('Key "{}" is missing in object for {}'
82
+ .format(key, f.__name__))
83
+ if not isinstance(cmd[key], typ):
84
+ raise RewriterException('Invalid type of "{}". Required is {} but provided was {}'
85
+ .format(key, typ.__name__, type(cmd[key]).__name__))
86
+ if choices is not None:
87
+ assert isinstance(choices, list)
88
+ if cmd[key] not in choices:
89
+ raise RewriterException('Invalid value of "{}": Possible values are {} but provided was "{}"'
90
+ .format(key, choices, cmd[key]))
91
+ return f(*wrapped_args, **wrapped_kwargs)
92
+
93
+ return wrapped
94
+
95
+ def _symbol(val: str) -> SymbolNode:
96
+ return SymbolNode(Token('', '', 0, 0, 0, (0, 0), val))
97
+
98
+ class MTypeBase:
99
+ def __init__(self, node: T.Optional[BaseNode] = None):
100
+ if node is None:
101
+ self.node = self.new_node()
102
+ else:
103
+ self.node = node
104
+ self.node_type = None
105
+ for i in self.supported_nodes():
106
+ if isinstance(self.node, i):
107
+ self.node_type = i
108
+
109
+ @classmethod
110
+ def new_node(cls, value=None):
111
+ # Overwrite in derived class
112
+ raise RewriterException('Internal error: new_node of MTypeBase was called')
113
+
114
+ @classmethod
115
+ def supported_nodes(cls):
116
+ # Overwrite in derived class
117
+ return []
118
+
119
+ def can_modify(self):
120
+ return self.node_type is not None
121
+
122
+ def get_node(self):
123
+ return self.node
124
+
125
+ def add_value(self, value):
126
+ # Overwrite in derived class
127
+ mlog.warning('Cannot add a value of type', mlog.bold(type(self).__name__), '--> skipping')
128
+
129
+ def remove_value(self, value):
130
+ # Overwrite in derived class
131
+ mlog.warning('Cannot remove a value of type', mlog.bold(type(self).__name__), '--> skipping')
132
+
133
+ def remove_regex(self, value):
134
+ # Overwrite in derived class
135
+ mlog.warning('Cannot remove a regex in type', mlog.bold(type(self).__name__), '--> skipping')
136
+
137
+ class MTypeStr(MTypeBase):
138
+ def __init__(self, node: T.Optional[BaseNode] = None):
139
+ super().__init__(node)
140
+
141
+ @classmethod
142
+ def new_node(cls, value=None):
143
+ if value is None:
144
+ value = ''
145
+ return StringNode(Token('', '', 0, 0, 0, None, str(value)))
146
+
147
+ @classmethod
148
+ def supported_nodes(cls):
149
+ return [StringNode]
150
+
151
+ class MTypeBool(MTypeBase):
152
+ def __init__(self, node: T.Optional[BaseNode] = None):
153
+ super().__init__(node)
154
+
155
+ @classmethod
156
+ def new_node(cls, value=None):
157
+ return BooleanNode(Token('', '', 0, 0, 0, None, bool(value)))
158
+
159
+ @classmethod
160
+ def supported_nodes(cls):
161
+ return [BooleanNode]
162
+
163
+ class MTypeID(MTypeBase):
164
+ def __init__(self, node: T.Optional[BaseNode] = None):
165
+ super().__init__(node)
166
+
167
+ @classmethod
168
+ def new_node(cls, value=None):
169
+ if value is None:
170
+ value = ''
171
+ return IdNode(Token('', '', 0, 0, 0, None, str(value)))
172
+
173
+ @classmethod
174
+ def supported_nodes(cls):
175
+ return [IdNode]
176
+
177
+ class MTypeList(MTypeBase):
178
+ def __init__(self, node: T.Optional[BaseNode] = None):
179
+ super().__init__(node)
180
+
181
+ @classmethod
182
+ def new_node(cls, value=None):
183
+ if value is None:
184
+ value = []
185
+ elif not isinstance(value, list):
186
+ return cls._new_element_node(value)
187
+ args = ArgumentNode(Token('', '', 0, 0, 0, None, ''))
188
+ args.arguments = [cls._new_element_node(i) for i in value]
189
+ return ArrayNode(_symbol('['), args, _symbol(']'))
190
+
191
+ @classmethod
192
+ def _new_element_node(cls, value):
193
+ # Overwrite in derived class
194
+ raise RewriterException('Internal error: _new_element_node of MTypeList was called')
195
+
196
+ def _ensure_array_node(self):
197
+ if not isinstance(self.node, ArrayNode):
198
+ tmp = self.node
199
+ self.node = self.new_node()
200
+ self.node.args.arguments = [tmp]
201
+
202
+ @staticmethod
203
+ def _check_is_equal(node, value) -> bool:
204
+ # Overwrite in derived class
205
+ return False
206
+
207
+ @staticmethod
208
+ def _check_regex_matches(node, regex: str) -> bool:
209
+ # Overwrite in derived class
210
+ return False
211
+
212
+ def get_node(self):
213
+ if isinstance(self.node, ArrayNode):
214
+ if len(self.node.args.arguments) == 1:
215
+ return self.node.args.arguments[0]
216
+ return self.node
217
+
218
+ @classmethod
219
+ def supported_element_nodes(cls):
220
+ # Overwrite in derived class
221
+ return []
222
+
223
+ @classmethod
224
+ def supported_nodes(cls):
225
+ return [ArrayNode] + cls.supported_element_nodes()
226
+
227
+ def add_value(self, value):
228
+ if not isinstance(value, list):
229
+ value = [value]
230
+ self._ensure_array_node()
231
+ for i in value:
232
+ self.node.args.arguments += [self._new_element_node(i)]
233
+
234
+ def _remove_helper(self, value, equal_func):
235
+ def check_remove_node(node):
236
+ for j in value:
237
+ if equal_func(i, j):
238
+ return True
239
+ return False
240
+
241
+ if not isinstance(value, list):
242
+ value = [value]
243
+ self._ensure_array_node()
244
+ removed_list = []
245
+ for i in self.node.args.arguments:
246
+ if not check_remove_node(i):
247
+ removed_list += [i]
248
+ self.node.args.arguments = removed_list
249
+
250
+ def remove_value(self, value):
251
+ self._remove_helper(value, self._check_is_equal)
252
+
253
+ def remove_regex(self, regex: str):
254
+ self._remove_helper(regex, self._check_regex_matches)
255
+
256
+ class MTypeStrList(MTypeList):
257
+ def __init__(self, node: T.Optional[BaseNode] = None):
258
+ super().__init__(node)
259
+
260
+ @classmethod
261
+ def _new_element_node(cls, value):
262
+ return StringNode(Token('', '', 0, 0, 0, None, str(value)))
263
+
264
+ @staticmethod
265
+ def _check_is_equal(node, value) -> bool:
266
+ if isinstance(node, BaseStringNode):
267
+ return node.value == value
268
+ return False
269
+
270
+ @staticmethod
271
+ def _check_regex_matches(node, regex: str) -> bool:
272
+ if isinstance(node, BaseStringNode):
273
+ return re.match(regex, node.value) is not None
274
+ return False
275
+
276
+ @classmethod
277
+ def supported_element_nodes(cls):
278
+ return [StringNode]
279
+
280
+ class MTypeIDList(MTypeList):
281
+ def __init__(self, node: T.Optional[BaseNode] = None):
282
+ super().__init__(node)
283
+
284
+ @classmethod
285
+ def _new_element_node(cls, value):
286
+ return IdNode(Token('', '', 0, 0, 0, None, str(value)))
287
+
288
+ @staticmethod
289
+ def _check_is_equal(node, value) -> bool:
290
+ if isinstance(node, IdNode):
291
+ return node.value == value
292
+ return False
293
+
294
+ @staticmethod
295
+ def _check_regex_matches(node, regex: str) -> bool:
296
+ if isinstance(node, BaseStringNode):
297
+ return re.match(regex, node.value) is not None
298
+ return False
299
+
300
+ @classmethod
301
+ def supported_element_nodes(cls):
302
+ return [IdNode]
303
+
304
+ rewriter_keys = {
305
+ 'default_options': {
306
+ 'operation': (str, None, ['set', 'delete']),
307
+ 'options': (dict, {}, None)
308
+ },
309
+ 'kwargs': {
310
+ 'function': (str, None, None),
311
+ 'id': (str, None, None),
312
+ 'operation': (str, None, ['set', 'delete', 'add', 'remove', 'remove_regex', 'info']),
313
+ 'kwargs': (dict, {}, None)
314
+ },
315
+ 'target': {
316
+ 'target': (str, None, None),
317
+ 'operation': (str, None, ['src_add', 'src_rm', 'target_rm', 'target_add', 'extra_files_add', 'extra_files_rm', 'info']),
318
+ 'sources': (list, [], None),
319
+ 'subdir': (str, '', None),
320
+ 'target_type': (str, 'executable', ['both_libraries', 'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library']),
321
+ }
322
+ }
323
+
324
+ rewriter_func_kwargs = {
325
+ 'dependency': {
326
+ 'language': MTypeStr,
327
+ 'method': MTypeStr,
328
+ 'native': MTypeBool,
329
+ 'not_found_message': MTypeStr,
330
+ 'required': MTypeBool,
331
+ 'static': MTypeBool,
332
+ 'version': MTypeStrList,
333
+ 'modules': MTypeStrList
334
+ },
335
+ 'target': {
336
+ 'build_by_default': MTypeBool,
337
+ 'build_rpath': MTypeStr,
338
+ 'dependencies': MTypeIDList,
339
+ 'gui_app': MTypeBool,
340
+ 'link_with': MTypeIDList,
341
+ 'export_dynamic': MTypeBool,
342
+ 'implib': MTypeBool,
343
+ 'install': MTypeBool,
344
+ 'install_dir': MTypeStr,
345
+ 'install_rpath': MTypeStr,
346
+ 'pie': MTypeBool
347
+ },
348
+ 'project': {
349
+ 'default_options': MTypeStrList,
350
+ 'meson_version': MTypeStr,
351
+ 'license': MTypeStrList,
352
+ 'subproject_dir': MTypeStr,
353
+ 'version': MTypeStr
354
+ }
355
+ }
356
+
357
+ class Rewriter:
358
+ def __init__(self, sourcedir: str, generator: str = 'ninja', skip_errors: bool = False):
359
+ self.sourcedir = sourcedir
360
+ self.interpreter = IntrospectionInterpreter(sourcedir, '', generator, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()])
361
+ self.skip_errors = skip_errors
362
+ self.modified_nodes = []
363
+ self.to_remove_nodes = []
364
+ self.to_add_nodes = []
365
+ self.functions = {
366
+ 'default_options': self.process_default_options,
367
+ 'kwargs': self.process_kwargs,
368
+ 'target': self.process_target,
369
+ }
370
+ self.info_dump = None
371
+
372
+ def analyze_meson(self):
373
+ mlog.log('Analyzing meson file:', mlog.bold(os.path.join(self.sourcedir, environment.build_filename)))
374
+ self.interpreter.analyze()
375
+ mlog.log(' -- Project:', mlog.bold(self.interpreter.project_data['descriptive_name']))
376
+ mlog.log(' -- Version:', mlog.cyan(self.interpreter.project_data['version']))
377
+
378
+ def add_info(self, cmd_type: str, cmd_id: str, data: dict):
379
+ if self.info_dump is None:
380
+ self.info_dump = {}
381
+ if cmd_type not in self.info_dump:
382
+ self.info_dump[cmd_type] = {}
383
+ self.info_dump[cmd_type][cmd_id] = data
384
+
385
+ def print_info(self):
386
+ if self.info_dump is None:
387
+ return
388
+ sys.stderr.write(json.dumps(self.info_dump, indent=2))
389
+
390
+ def on_error(self):
391
+ if self.skip_errors:
392
+ return mlog.cyan('-->'), mlog.yellow('skipping')
393
+ return mlog.cyan('-->'), mlog.red('aborting')
394
+
395
+ def handle_error(self):
396
+ if self.skip_errors:
397
+ return None
398
+ raise MesonException('Rewriting the meson.build failed')
399
+
400
+ def find_target(self, target: str):
401
+ def check_list(name: str) -> T.List[BaseNode]:
402
+ result = []
403
+ for i in self.interpreter.targets:
404
+ if name in {i['name'], i['id']}:
405
+ result += [i]
406
+ return result
407
+
408
+ targets = check_list(target)
409
+ if targets:
410
+ if len(targets) == 1:
411
+ return targets[0]
412
+ else:
413
+ mlog.error('There are multiple targets matching', mlog.bold(target))
414
+ for i in targets:
415
+ mlog.error(' -- Target name', mlog.bold(i['name']), 'with ID', mlog.bold(i['id']))
416
+ mlog.error('Please try again with the unique ID of the target', *self.on_error())
417
+ self.handle_error()
418
+ return None
419
+
420
+ # Check the assignments
421
+ tgt = None
422
+ if target in self.interpreter.assignments:
423
+ node = self.interpreter.assignments[target]
424
+ if isinstance(node, FunctionNode):
425
+ if node.func_name.value in {'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'}:
426
+ tgt = self.interpreter.assign_vals[target]
427
+
428
+ return tgt
429
+
430
+ def find_dependency(self, dependency: str):
431
+ def check_list(name: str):
432
+ for i in self.interpreter.dependencies:
433
+ if name == i['name']:
434
+ return i
435
+ return None
436
+
437
+ dep = check_list(dependency)
438
+ if dep is not None:
439
+ return dep
440
+
441
+ # Check the assignments
442
+ if dependency in self.interpreter.assignments:
443
+ node = self.interpreter.assignments[dependency]
444
+ if isinstance(node, FunctionNode):
445
+ if node.func_name.value == 'dependency':
446
+ name = self.interpreter.flatten_args(node.args)[0]
447
+ dep = check_list(name)
448
+
449
+ return dep
450
+
451
+ @RequiredKeys(rewriter_keys['default_options'])
452
+ def process_default_options(self, cmd):
453
+ # First, remove the old values
454
+ kwargs_cmd = {
455
+ 'function': 'project',
456
+ 'id': "/",
457
+ 'operation': 'remove_regex',
458
+ 'kwargs': {
459
+ 'default_options': [f'{x}=.*' for x in cmd['options'].keys()]
460
+ }
461
+ }
462
+ self.process_kwargs(kwargs_cmd)
463
+
464
+ # Then add the new values
465
+ if cmd['operation'] != 'set':
466
+ return
467
+
468
+ kwargs_cmd['operation'] = 'add'
469
+ kwargs_cmd['kwargs']['default_options'] = []
470
+
471
+ cdata = self.interpreter.coredata
472
+ options = {
473
+ **{str(k): v for k, v in cdata.options.items()},
474
+ **{str(k): v for k, v in cdata.options.items()},
475
+ **{str(k): v for k, v in cdata.options.items()},
476
+ **{str(k): v for k, v in cdata.options.items()},
477
+ **{str(k): v for k, v in cdata.options.items()},
478
+ }
479
+
480
+ for key, val in sorted(cmd['options'].items()):
481
+ if key not in options:
482
+ mlog.error('Unknown options', mlog.bold(key), *self.on_error())
483
+ self.handle_error()
484
+ continue
485
+
486
+ try:
487
+ val = options[key].validate_value(val)
488
+ except MesonException as e:
489
+ mlog.error('Unable to set', mlog.bold(key), mlog.red(str(e)), *self.on_error())
490
+ self.handle_error()
491
+ continue
492
+
493
+ kwargs_cmd['kwargs']['default_options'] += [f'{key}={val}']
494
+
495
+ self.process_kwargs(kwargs_cmd)
496
+
497
+ @RequiredKeys(rewriter_keys['kwargs'])
498
+ def process_kwargs(self, cmd):
499
+ mlog.log('Processing function type', mlog.bold(cmd['function']), 'with id', mlog.cyan("'" + cmd['id'] + "'"))
500
+ if cmd['function'] not in rewriter_func_kwargs:
501
+ mlog.error('Unknown function type', cmd['function'], *self.on_error())
502
+ return self.handle_error()
503
+ kwargs_def = rewriter_func_kwargs[cmd['function']]
504
+
505
+ # Find the function node to modify
506
+ node = None
507
+ arg_node = None
508
+ if cmd['function'] == 'project':
509
+ # msys bash may expand '/' to a path. It will mangle '//' to '/'
510
+ # but in order to keep usage shell-agnostic, also allow `//` as
511
+ # the function ID such that it will work in both msys bash and
512
+ # other shells.
513
+ if {'/', '//'}.isdisjoint({cmd['id']}):
514
+ mlog.error('The ID for the function type project must be "/" or "//" not "' + cmd['id'] + '"', *self.on_error())
515
+ return self.handle_error()
516
+ node = self.interpreter.project_node
517
+ arg_node = node.args
518
+ elif cmd['function'] == 'target':
519
+ tmp = self.find_target(cmd['id'])
520
+ if tmp:
521
+ node = tmp['node']
522
+ arg_node = node.args
523
+ elif cmd['function'] == 'dependency':
524
+ tmp = self.find_dependency(cmd['id'])
525
+ if tmp:
526
+ node = tmp['node']
527
+ arg_node = node.args
528
+ if not node:
529
+ mlog.error('Unable to find the function node')
530
+ assert isinstance(node, FunctionNode)
531
+ assert isinstance(arg_node, ArgumentNode)
532
+ # Transform the key nodes to plain strings
533
+ arg_node.kwargs = {k.value: v for k, v in arg_node.kwargs.items()}
534
+
535
+ # Print kwargs info
536
+ if cmd['operation'] == 'info':
537
+ info_data = {}
538
+ for key, val in sorted(arg_node.kwargs.items()):
539
+ info_data[key] = None
540
+ if isinstance(val, ElementaryNode):
541
+ info_data[key] = val.value
542
+ elif isinstance(val, ArrayNode):
543
+ data_list = []
544
+ for i in val.args.arguments:
545
+ element = None
546
+ if isinstance(i, ElementaryNode):
547
+ element = i.value
548
+ data_list += [element]
549
+ info_data[key] = data_list
550
+
551
+ self.add_info('kwargs', '{}#{}'.format(cmd['function'], cmd['id']), info_data)
552
+ return # Nothing else to do
553
+
554
+ # Modify the kwargs
555
+ num_changed = 0
556
+ for key, val in sorted(cmd['kwargs'].items()):
557
+ if key not in kwargs_def:
558
+ mlog.error('Cannot modify unknown kwarg', mlog.bold(key), *self.on_error())
559
+ self.handle_error()
560
+ continue
561
+
562
+ if cmd['operation'] == 'delete':
563
+ # Remove the key from the kwargs
564
+ if key not in arg_node.kwargs:
565
+ mlog.log(' -- Key', mlog.bold(key), 'is already deleted')
566
+ continue
567
+ mlog.log(' -- Deleting', mlog.bold(key), 'from the kwargs')
568
+ del arg_node.kwargs[key]
569
+ elif cmd['operation'] == 'set':
570
+ # Replace the key from the kwargs
571
+ mlog.log(' -- Setting', mlog.bold(key), 'to', mlog.yellow(str(val)))
572
+ arg_node.kwargs[key] = kwargs_def[key].new_node(val)
573
+ else:
574
+ # Modify the value from the kwargs
575
+
576
+ if key not in arg_node.kwargs:
577
+ arg_node.kwargs[key] = None
578
+ modifier = kwargs_def[key](arg_node.kwargs[key])
579
+ if not modifier.can_modify():
580
+ mlog.log(' -- Skipping', mlog.bold(key), 'because it is too complex to modify')
581
+ continue
582
+
583
+ # Apply the operation
584
+ val_str = str(val)
585
+ if cmd['operation'] == 'add':
586
+ mlog.log(' -- Adding', mlog.yellow(val_str), 'to', mlog.bold(key))
587
+ modifier.add_value(val)
588
+ elif cmd['operation'] == 'remove':
589
+ mlog.log(' -- Removing', mlog.yellow(val_str), 'from', mlog.bold(key))
590
+ modifier.remove_value(val)
591
+ elif cmd['operation'] == 'remove_regex':
592
+ mlog.log(' -- Removing all values matching', mlog.yellow(val_str), 'from', mlog.bold(key))
593
+ modifier.remove_regex(val)
594
+
595
+ # Write back the result
596
+ arg_node.kwargs[key] = modifier.get_node()
597
+
598
+ num_changed += 1
599
+
600
+ # Convert the keys back to IdNode's
601
+ arg_node.kwargs = {IdNode(Token('', '', 0, 0, 0, None, k)): v for k, v in arg_node.kwargs.items()}
602
+ for k, v in arg_node.kwargs.items():
603
+ k.level = v.level
604
+ if num_changed > 0 and node not in self.modified_nodes:
605
+ self.modified_nodes += [node]
606
+
607
+ def find_assignment_node(self, node: BaseNode) -> AssignmentNode:
608
+ if node.ast_id and node.ast_id in self.interpreter.reverse_assignment:
609
+ return self.interpreter.reverse_assignment[node.ast_id]
610
+ return None
611
+
612
+ @RequiredKeys(rewriter_keys['target'])
613
+ def process_target(self, cmd):
614
+ mlog.log('Processing target', mlog.bold(cmd['target']), 'operation', mlog.cyan(cmd['operation']))
615
+ target = self.find_target(cmd['target'])
616
+ if target is None and cmd['operation'] != 'target_add':
617
+ mlog.error('Unknown target', mlog.bold(cmd['target']), *self.on_error())
618
+ return self.handle_error()
619
+
620
+ # Make source paths relative to the current subdir
621
+ def rel_source(src: str) -> str:
622
+ subdir = os.path.abspath(os.path.join(self.sourcedir, target['subdir']))
623
+ if os.path.isabs(src):
624
+ return os.path.relpath(src, subdir)
625
+ elif not os.path.exists(src):
626
+ return src # Trust the user when the source doesn't exist
627
+ # Make sure that the path is relative to the subdir
628
+ return os.path.relpath(os.path.abspath(src), subdir)
629
+
630
+ if target is not None:
631
+ cmd['sources'] = [rel_source(x) for x in cmd['sources']]
632
+
633
+ # Utility function to get a list of the sources from a node
634
+ def arg_list_from_node(n):
635
+ args = []
636
+ if isinstance(n, FunctionNode):
637
+ args = list(n.args.arguments)
638
+ if n.func_name.value in BUILD_TARGET_FUNCTIONS:
639
+ args.pop(0)
640
+ elif isinstance(n, ArrayNode):
641
+ args = n.args.arguments
642
+ elif isinstance(n, ArgumentNode):
643
+ args = n.arguments
644
+ return args
645
+
646
+ to_sort_nodes = []
647
+
648
+ if cmd['operation'] == 'src_add':
649
+ node = None
650
+ if target['sources']:
651
+ node = target['sources'][0]
652
+ else:
653
+ node = target['node']
654
+ assert node is not None
655
+
656
+ # Generate the current source list
657
+ src_list = []
658
+ for i in target['sources']:
659
+ for j in arg_list_from_node(i):
660
+ if isinstance(j, BaseStringNode):
661
+ src_list += [j.value]
662
+
663
+ # Generate the new String nodes
664
+ to_append = []
665
+ for i in sorted(set(cmd['sources'])):
666
+ if i in src_list:
667
+ mlog.log(' -- Source', mlog.green(i), 'is already defined for the target --> skipping')
668
+ continue
669
+ mlog.log(' -- Adding source', mlog.green(i), 'at',
670
+ mlog.yellow(f'{node.filename}:{node.lineno}'))
671
+ token = Token('string', node.filename, 0, 0, 0, None, i)
672
+ to_append += [StringNode(token)]
673
+
674
+ # Append to the AST at the right place
675
+ arg_node = None
676
+ if isinstance(node, (FunctionNode, ArrayNode)):
677
+ arg_node = node.args
678
+ elif isinstance(node, ArgumentNode):
679
+ arg_node = node
680
+ assert arg_node is not None
681
+ arg_node.arguments += to_append
682
+
683
+ # Mark the node as modified
684
+ if arg_node not in to_sort_nodes and not isinstance(node, FunctionNode):
685
+ to_sort_nodes += [arg_node]
686
+ if node not in self.modified_nodes:
687
+ self.modified_nodes += [node]
688
+
689
+ elif cmd['operation'] == 'src_rm':
690
+ # Helper to find the exact string node and its parent
691
+ def find_node(src):
692
+ for i in target['sources']:
693
+ for j in arg_list_from_node(i):
694
+ if isinstance(j, BaseStringNode):
695
+ if j.value == src:
696
+ return i, j
697
+ return None, None
698
+
699
+ for i in cmd['sources']:
700
+ # Try to find the node with the source string
701
+ root, string_node = find_node(i)
702
+ if root is None:
703
+ mlog.warning(' -- Unable to find source', mlog.green(i), 'in the target')
704
+ continue
705
+
706
+ # Remove the found string node from the argument list
707
+ arg_node = None
708
+ if isinstance(root, (FunctionNode, ArrayNode)):
709
+ arg_node = root.args
710
+ elif isinstance(root, ArgumentNode):
711
+ arg_node = root
712
+ assert arg_node is not None
713
+ mlog.log(' -- Removing source', mlog.green(i), 'from',
714
+ mlog.yellow(f'{string_node.filename}:{string_node.lineno}'))
715
+ arg_node.arguments.remove(string_node)
716
+
717
+ # Mark the node as modified
718
+ if arg_node not in to_sort_nodes and not isinstance(root, FunctionNode):
719
+ to_sort_nodes += [arg_node]
720
+ if root not in self.modified_nodes:
721
+ self.modified_nodes += [root]
722
+
723
+ elif cmd['operation'] == 'extra_files_add':
724
+ tgt_function: FunctionNode = target['node']
725
+ mark_array = True
726
+ try:
727
+ node = target['extra_files'][0]
728
+ except IndexError:
729
+ # Specifying `extra_files` with a list that flattens to empty gives an empty
730
+ # target['extra_files'] list, account for that.
731
+ try:
732
+ extra_files_key = next(k for k in tgt_function.args.kwargs.keys() if isinstance(k, IdNode) and k.value == 'extra_files')
733
+ node = tgt_function.args.kwargs[extra_files_key]
734
+ except StopIteration:
735
+ # Target has no extra_files kwarg, create one
736
+ node = ArrayNode(_symbol('['), ArgumentNode(Token('', tgt_function.filename, 0, 0, 0, None, '[]')), _symbol(']'))
737
+ tgt_function.args.kwargs[IdNode(Token('string', tgt_function.filename, 0, 0, 0, None, 'extra_files'))] = node
738
+ mark_array = False
739
+ if tgt_function not in self.modified_nodes:
740
+ self.modified_nodes += [tgt_function]
741
+ target['extra_files'] = [node]
742
+ if isinstance(node, IdNode):
743
+ node = self.interpreter.assignments[node.value]
744
+ target['extra_files'] = [node]
745
+ if not isinstance(node, ArrayNode):
746
+ mlog.error('Target', mlog.bold(cmd['target']), 'extra_files argument must be a list', *self.on_error())
747
+ return self.handle_error()
748
+
749
+ # Generate the current extra files list
750
+ extra_files_list = []
751
+ for i in target['extra_files']:
752
+ for j in arg_list_from_node(i):
753
+ if isinstance(j, BaseStringNode):
754
+ extra_files_list += [j.value]
755
+
756
+ # Generate the new String nodes
757
+ to_append = []
758
+ for i in sorted(set(cmd['sources'])):
759
+ if i in extra_files_list:
760
+ mlog.log(' -- Extra file', mlog.green(i), 'is already defined for the target --> skipping')
761
+ continue
762
+ mlog.log(' -- Adding extra file', mlog.green(i), 'at',
763
+ mlog.yellow(f'{node.filename}:{node.lineno}'))
764
+ token = Token('string', node.filename, 0, 0, 0, None, i)
765
+ to_append += [StringNode(token)]
766
+
767
+ # Append to the AST at the right place
768
+ arg_node = node.args
769
+ arg_node.arguments += to_append
770
+
771
+ # Mark the node as modified
772
+ if arg_node not in to_sort_nodes:
773
+ to_sort_nodes += [arg_node]
774
+ # If the extra_files array is newly created, don't mark it as its parent function node already is,
775
+ # otherwise this would cause double modification.
776
+ if mark_array and node not in self.modified_nodes:
777
+ self.modified_nodes += [node]
778
+
779
+ elif cmd['operation'] == 'extra_files_rm':
780
+ # Helper to find the exact string node and its parent
781
+ def find_node(src):
782
+ for i in target['extra_files']:
783
+ for j in arg_list_from_node(i):
784
+ if isinstance(j, BaseStringNode):
785
+ if j.value == src:
786
+ return i, j
787
+ return None, None
788
+
789
+ for i in cmd['sources']:
790
+ # Try to find the node with the source string
791
+ root, string_node = find_node(i)
792
+ if root is None:
793
+ mlog.warning(' -- Unable to find extra file', mlog.green(i), 'in the target')
794
+ continue
795
+
796
+ # Remove the found string node from the argument list
797
+ arg_node = root.args
798
+ mlog.log(' -- Removing extra file', mlog.green(i), 'from',
799
+ mlog.yellow(f'{string_node.filename}:{string_node.lineno}'))
800
+ arg_node.arguments.remove(string_node)
801
+
802
+ # Mark the node as modified
803
+ if arg_node not in to_sort_nodes and not isinstance(root, FunctionNode):
804
+ to_sort_nodes += [arg_node]
805
+ if root not in self.modified_nodes:
806
+ self.modified_nodes += [root]
807
+
808
+ elif cmd['operation'] == 'target_add':
809
+ if target is not None:
810
+ mlog.error('Can not add target', mlog.bold(cmd['target']), 'because it already exists', *self.on_error())
811
+ return self.handle_error()
812
+
813
+ id_base = re.sub(r'[- ]', '_', cmd['target'])
814
+ target_id = id_base + '_exe' if cmd['target_type'] == 'executable' else '_lib'
815
+ source_id = id_base + '_sources'
816
+ filename = os.path.join(cmd['subdir'], environment.build_filename)
817
+
818
+ # Build src list
819
+ src_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
820
+ src_arr_node = ArrayNode(_symbol('['), src_arg_node, _symbol(']'))
821
+ src_far_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
822
+ src_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), 'files')), _symbol('('), src_far_node, _symbol(')'))
823
+ src_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), source_id)), _symbol('='), src_fun_node)
824
+ src_arg_node.arguments = [StringNode(Token('string', filename, 0, 0, 0, None, x)) for x in cmd['sources']]
825
+ src_far_node.arguments = [src_arr_node]
826
+
827
+ # Build target
828
+ tgt_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
829
+ tgt_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), cmd['target_type'])), _symbol('('), tgt_arg_node, _symbol(')'))
830
+ tgt_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), target_id)), _symbol('='), tgt_fun_node)
831
+ tgt_arg_node.arguments = [
832
+ StringNode(Token('string', filename, 0, 0, 0, None, cmd['target'])),
833
+ IdNode(Token('string', filename, 0, 0, 0, None, source_id))
834
+ ]
835
+
836
+ src_ass_node.accept(AstIndentationGenerator())
837
+ tgt_ass_node.accept(AstIndentationGenerator())
838
+ self.to_add_nodes += [src_ass_node, tgt_ass_node]
839
+
840
+ elif cmd['operation'] == 'target_rm':
841
+ to_remove = self.find_assignment_node(target['node'])
842
+ if to_remove is None:
843
+ to_remove = target['node']
844
+ self.to_remove_nodes += [to_remove]
845
+ mlog.log(' -- Removing target', mlog.green(cmd['target']), 'at',
846
+ mlog.yellow(f'{to_remove.filename}:{to_remove.lineno}'))
847
+
848
+ elif cmd['operation'] == 'info':
849
+ # T.List all sources in the target
850
+ src_list = []
851
+ for i in target['sources']:
852
+ for j in arg_list_from_node(i):
853
+ if isinstance(j, BaseStringNode):
854
+ src_list += [j.value]
855
+ extra_files_list = []
856
+ for i in target['extra_files']:
857
+ for j in arg_list_from_node(i):
858
+ if isinstance(j, BaseStringNode):
859
+ extra_files_list += [j.value]
860
+ test_data = {
861
+ 'name': target['name'],
862
+ 'sources': src_list,
863
+ 'extra_files': extra_files_list
864
+ }
865
+ self.add_info('target', target['id'], test_data)
866
+
867
+ # Sort files
868
+ for i in to_sort_nodes:
869
+ convert = lambda text: int(text) if text.isdigit() else text.lower()
870
+ alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
871
+ path_sorter = lambda key: ([(key.count('/') <= idx, alphanum_key(x)) for idx, x in enumerate(key.split('/'))])
872
+
873
+ unknown = [x for x in i.arguments if not isinstance(x, BaseStringNode)]
874
+ sources = [x for x in i.arguments if isinstance(x, BaseStringNode)]
875
+ sources = sorted(sources, key=lambda x: path_sorter(x.value))
876
+ i.arguments = unknown + sources
877
+
878
+ def process(self, cmd):
879
+ if 'type' not in cmd:
880
+ raise RewriterException('Command has no key "type"')
881
+ if cmd['type'] not in self.functions:
882
+ raise RewriterException('Unknown command "{}". Supported commands are: {}'
883
+ .format(cmd['type'], list(self.functions.keys())))
884
+ self.functions[cmd['type']](cmd)
885
+
886
+ def apply_changes(self):
887
+ assert all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.modified_nodes)
888
+ assert all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.to_remove_nodes)
889
+ assert all(isinstance(x, (ArrayNode, FunctionNode)) for x in self.modified_nodes)
890
+ assert all(isinstance(x, (ArrayNode, AssignmentNode, FunctionNode)) for x in self.to_remove_nodes)
891
+ # Sort based on line and column in reversed order
892
+ work_nodes = [{'node': x, 'action': 'modify'} for x in self.modified_nodes]
893
+ work_nodes += [{'node': x, 'action': 'rm'} for x in self.to_remove_nodes]
894
+ work_nodes = sorted(work_nodes, key=lambda x: (x['node'].lineno, x['node'].colno), reverse=True)
895
+ work_nodes += [{'node': x, 'action': 'add'} for x in self.to_add_nodes]
896
+
897
+ # Generating the new replacement string
898
+ str_list = []
899
+ for i in work_nodes:
900
+ new_data = ''
901
+ if i['action'] == 'modify' or i['action'] == 'add':
902
+ printer = AstPrinter()
903
+ i['node'].accept(printer)
904
+ printer.post_process()
905
+ new_data = printer.result.strip()
906
+ data = {
907
+ 'file': i['node'].filename,
908
+ 'str': new_data,
909
+ 'node': i['node'],
910
+ 'action': i['action']
911
+ }
912
+ str_list += [data]
913
+
914
+ # Load build files
915
+ files = {}
916
+ for i in str_list:
917
+ if i['file'] in files:
918
+ continue
919
+ fpath = os.path.realpath(os.path.join(self.sourcedir, i['file']))
920
+ fdata = ''
921
+ # Create an empty file if it does not exist
922
+ if not os.path.exists(fpath):
923
+ with open(fpath, 'w', encoding='utf-8'):
924
+ pass
925
+ with open(fpath, encoding='utf-8') as fp:
926
+ fdata = fp.read()
927
+
928
+ # Generate line offsets numbers
929
+ m_lines = fdata.splitlines(True)
930
+ offset = 0
931
+ line_offsets = []
932
+ for j in m_lines:
933
+ line_offsets += [offset]
934
+ offset += len(j)
935
+
936
+ files[i['file']] = {
937
+ 'path': fpath,
938
+ 'raw': fdata,
939
+ 'offsets': line_offsets
940
+ }
941
+
942
+ # Replace in source code
943
+ def remove_node(i):
944
+ offsets = files[i['file']]['offsets']
945
+ raw = files[i['file']]['raw']
946
+ node = i['node']
947
+ line = node.lineno - 1
948
+ col = node.colno
949
+ start = offsets[line] + col
950
+ end = start
951
+ if isinstance(node, (ArrayNode, FunctionNode)):
952
+ end = offsets[node.end_lineno - 1] + node.end_colno
953
+
954
+ # Only removal is supported for assignments
955
+ elif isinstance(node, AssignmentNode) and i['action'] == 'rm':
956
+ if isinstance(node.value, (ArrayNode, FunctionNode)):
957
+ remove_node({'file': i['file'], 'str': '', 'node': node.value, 'action': 'rm'})
958
+ raw = files[i['file']]['raw']
959
+ while raw[end] != '=':
960
+ end += 1
961
+ end += 1 # Handle the '='
962
+ while raw[end] in {' ', '\n', '\t'}:
963
+ end += 1
964
+
965
+ files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:]
966
+
967
+ for i in str_list:
968
+ if i['action'] in {'modify', 'rm'}:
969
+ remove_node(i)
970
+ elif i['action'] == 'add':
971
+ files[i['file']]['raw'] += i['str'] + '\n'
972
+
973
+ # Write the files back
974
+ for key, val in files.items():
975
+ mlog.log('Rewriting', mlog.yellow(key))
976
+ with open(val['path'], 'w', encoding='utf-8') as fp:
977
+ fp.write(val['raw'])
978
+
979
+ target_operation_map = {
980
+ 'add': 'src_add',
981
+ 'rm': 'src_rm',
982
+ 'add_target': 'target_add',
983
+ 'rm_target': 'target_rm',
984
+ 'add_extra_files': 'extra_files_add',
985
+ 'rm_extra_files': 'extra_files_rm',
986
+ 'info': 'info',
987
+ }
988
+
989
+ def list_to_dict(in_list: T.List[str]) -> T.Dict[str, str]:
990
+ result = {}
991
+ it = iter(in_list)
992
+ try:
993
+ for i in it:
994
+ # calling next(it) is not a mistake, we're taking the next element from
995
+ # the iterator, avoiding the need to preprocess it into a sequence of
996
+ # key value pairs.
997
+ result[i] = next(it)
998
+ except StopIteration:
999
+ raise TypeError('in_list parameter of list_to_dict must have an even length.')
1000
+ return result
1001
+
1002
+ def generate_target(options) -> T.List[dict]:
1003
+ return [{
1004
+ 'type': 'target',
1005
+ 'target': options.target,
1006
+ 'operation': target_operation_map[options.operation],
1007
+ 'sources': options.sources,
1008
+ 'subdir': options.subdir,
1009
+ 'target_type': options.tgt_type,
1010
+ }]
1011
+
1012
+ def generate_kwargs(options) -> T.List[dict]:
1013
+ return [{
1014
+ 'type': 'kwargs',
1015
+ 'function': options.function,
1016
+ 'id': options.id,
1017
+ 'operation': options.operation,
1018
+ 'kwargs': list_to_dict(options.kwargs),
1019
+ }]
1020
+
1021
+ def generate_def_opts(options) -> T.List[dict]:
1022
+ return [{
1023
+ 'type': 'default_options',
1024
+ 'operation': options.operation,
1025
+ 'options': list_to_dict(options.options),
1026
+ }]
1027
+
1028
+ def generate_cmd(options) -> T.List[dict]:
1029
+ if os.path.exists(options.json):
1030
+ with open(options.json, encoding='utf-8') as fp:
1031
+ return json.load(fp)
1032
+ else:
1033
+ return json.loads(options.json)
1034
+
1035
+ # Map options.type to the actual type name
1036
+ cli_type_map = {
1037
+ 'target': generate_target,
1038
+ 'tgt': generate_target,
1039
+ 'kwargs': generate_kwargs,
1040
+ 'default-options': generate_def_opts,
1041
+ 'def': generate_def_opts,
1042
+ 'command': generate_cmd,
1043
+ 'cmd': generate_cmd,
1044
+ }
1045
+
1046
+ def run(options):
1047
+ if not options.verbose:
1048
+ mlog.set_quiet()
1049
+
1050
+ try:
1051
+ setup_vsenv()
1052
+ rewriter = Rewriter(options.sourcedir, skip_errors=options.skip)
1053
+ rewriter.analyze_meson()
1054
+
1055
+ if options.type is None:
1056
+ mlog.error('No command specified')
1057
+ return 1
1058
+
1059
+ commands = cli_type_map[options.type](options)
1060
+
1061
+ if not isinstance(commands, list):
1062
+ raise TypeError('Command is not a list')
1063
+
1064
+ for i in commands:
1065
+ if not isinstance(i, object):
1066
+ raise TypeError('Command is not an object')
1067
+ rewriter.process(i)
1068
+
1069
+ rewriter.apply_changes()
1070
+ rewriter.print_info()
1071
+ return 0
1072
+ except Exception as e:
1073
+ raise e
1074
+ finally:
1075
+ mlog.set_verbose()