mirror of
https://github.com/frida/frida-python.git
synced 2026-11-11 10:01:27 -10:00
Compare commits
161
Commits
debug/tasks
...
main
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
PYTHON ?= $(shell which python3 >/dev/null && echo python3 || echo python)
|
PYTHON ?= $(shell command -v python3 >/dev/null && echo python3 || echo python)
|
||||||
|
|
||||||
all $(MAKECMDGOALS):
|
all $(MAKECMDGOALS):
|
||||||
@$(PYTHON) \
|
@$(PYTHON) \
|
||||||
@@ -8,7 +8,7 @@ all $(MAKECMDGOALS):
|
|||||||
$(MAKECMDGOALS)
|
$(MAKECMDGOALS)
|
||||||
|
|
||||||
git-submodules:
|
git-submodules:
|
||||||
@if [ ! -f releng/meson/meson.py ] || [ ! -f frida-bindgen/frida_bindgen_core/model.py ]; then \
|
@if [ ! -f releng/meson/meson.py ] || git submodule status 2>/dev/null | grep -q '^-'; then \
|
||||||
git submodule update --init --recursive --depth 1; \
|
git submodule update --init --recursive --depth 1; \
|
||||||
fi
|
fi
|
||||||
-include git-submodules
|
-include git-submodules
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
[ -z "$PYTHON" ] && PYTHON=$(which python3 >/dev/null && echo python3 || echo python)
|
[ -z "$PYTHON" ] && PYTHON=$(command -v python3 >/dev/null && echo python3 || echo python)
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
srcroot=$(pwd)
|
srcroot=$(pwd)
|
||||||
|
|
||||||
if [ ! -f releng/meson/meson.py ]; then
|
if [ ! -f releng/meson/meson.py ] || git submodule status 2>/dev/null | grep -q '^-'; then
|
||||||
git submodule update --init --recursive --depth 1 || exit $?
|
git submodule update --init --recursive --depth 1 || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Generated
+4
-4
@@ -9,7 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"dbus-next": "frida/node-dbus-next",
|
"dbus-next": "frida-forks/node-dbus-next",
|
||||||
"duplexify": "^4.1.1",
|
"duplexify": "^4.1.1",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-class-component": "^7.2.3",
|
"vue-class-component": "^7.2.3",
|
||||||
@@ -6509,7 +6509,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/dbus-next": {
|
"node_modules/dbus-next": {
|
||||||
"version": "0.9.2",
|
"version": "0.9.2",
|
||||||
"resolved": "git+ssh://[email protected]/frida/node-dbus-next.git#0e12559b2298c140916541f57fdf9f83cf0b7975",
|
"resolved": "git+ssh://[email protected]/frida-forks/node-dbus-next.git#0e12559b2298c140916541f57fdf9f83cf0b7975",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nornagon/put": "0.0.8",
|
"@nornagon/put": "0.0.8",
|
||||||
@@ -20437,8 +20437,8 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"dbus-next": {
|
"dbus-next": {
|
||||||
"version": "git+ssh://[email protected]/frida/node-dbus-next.git#0e12559b2298c140916541f57fdf9f83cf0b7975",
|
"version": "git+ssh://[email protected]/frida-forks/node-dbus-next.git#0e12559b2298c140916541f57fdf9f83cf0b7975",
|
||||||
"from": "dbus-next@frida/node-dbus-next",
|
"from": "dbus-next@frida-forks/node-dbus-next",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nornagon/put": "0.0.8",
|
"@nornagon/put": "0.0.8",
|
||||||
"abstract-socket": "^2.0.0",
|
"abstract-socket": "^2.0.0",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"dbus-next": "frida/node-dbus-next",
|
"dbus-next": "frida-forks/node-dbus-next",
|
||||||
"duplexify": "^4.1.1",
|
"duplexify": "^4.1.1",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-class-component": "^7.2.3",
|
"vue-class-component": "^7.2.3",
|
||||||
|
|||||||
+1
-1
Submodule frida-bindgen updated: df17879d92...eace04901e.
@@ -1,27 +1,3 @@
|
|||||||
static gboolean
|
|
||||||
PyGObject_unmarshal_certificate (const gchar * str,
|
|
||||||
GTlsCertificate ** certificate)
|
|
||||||
{
|
|
||||||
GError * error = NULL;
|
|
||||||
|
|
||||||
if (strchr (str, '\n') != NULL)
|
|
||||||
*certificate = g_tls_certificate_new_from_pem (str, -1, &error);
|
|
||||||
else
|
|
||||||
*certificate = g_tls_certificate_new_from_file (str, &error);
|
|
||||||
if (error != NULL)
|
|
||||||
goto propagate_error;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
propagate_error:
|
|
||||||
{
|
|
||||||
PyFrida_raise (g_error_new_literal (FRIDA_ERROR, FRIDA_ERROR_INVALID_ARGUMENT, error->message));
|
|
||||||
g_error_free (error);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
PyEndpointParameters_init (PyEndpointParameters * self,
|
PyEndpointParameters_init (PyEndpointParameters * self,
|
||||||
PyObject * args,
|
PyObject * args,
|
||||||
@@ -31,7 +7,7 @@ PyEndpointParameters_init (PyEndpointParameters * self,
|
|||||||
static char * keywords[] = { "address", "port", "certificate", "origin", "auth_service", "asset_root", NULL };
|
static char * keywords[] = { "address", "port", "certificate", "origin", "auth_service", "asset_root", NULL };
|
||||||
char * address = NULL;
|
char * address = NULL;
|
||||||
unsigned short int port = 0;
|
unsigned short int port = 0;
|
||||||
char * certificate_value = NULL;
|
PyObject * certificate_value = NULL;
|
||||||
char * origin = NULL;
|
char * origin = NULL;
|
||||||
PyObject * auth_service_obj = NULL;
|
PyObject * auth_service_obj = NULL;
|
||||||
char * asset_root_value = NULL;
|
char * asset_root_value = NULL;
|
||||||
@@ -43,10 +19,10 @@ PyEndpointParameters_init (PyEndpointParameters * self,
|
|||||||
if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0)
|
if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords (args, kw, "|esHesesOes", keywords,
|
if (!PyArg_ParseTupleAndKeywords (args, kw, "|esHOesOes", keywords,
|
||||||
"utf-8", &address,
|
"utf-8", &address,
|
||||||
&port,
|
&port,
|
||||||
"utf-8", &certificate_value,
|
&certificate_value,
|
||||||
"utf-8", &origin,
|
"utf-8", &origin,
|
||||||
&auth_service_obj,
|
&auth_service_obj,
|
||||||
"utf-8", &asset_root_value))
|
"utf-8", &asset_root_value))
|
||||||
@@ -74,7 +50,6 @@ beach:
|
|||||||
|
|
||||||
PyMem_Free (asset_root_value);
|
PyMem_Free (asset_root_value);
|
||||||
PyMem_Free (origin);
|
PyMem_Free (origin);
|
||||||
PyMem_Free (certificate_value);
|
|
||||||
PyMem_Free (address);
|
PyMem_Free (address);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -910,6 +910,9 @@ propagate_error:
|
|||||||
static PyObject *
|
static PyObject *
|
||||||
PyGObject_marshal_variant (GVariant * variant)
|
PyGObject_marshal_variant (GVariant * variant)
|
||||||
{
|
{
|
||||||
|
if (variant == NULL)
|
||||||
|
PyFrida_RETURN_NONE;
|
||||||
|
|
||||||
switch (g_variant_classify (variant))
|
switch (g_variant_classify (variant))
|
||||||
{
|
{
|
||||||
case G_VARIANT_CLASS_STRING:
|
case G_VARIANT_CLASS_STRING:
|
||||||
@@ -1041,6 +1044,64 @@ PyGObject_marshal_variant_tuple (GVariant * variant)
|
|||||||
return tuple;
|
return tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
PyGObject_unmarshal_certificate (PyObject * value,
|
||||||
|
GTlsCertificate ** certificate)
|
||||||
|
{
|
||||||
|
PyObject * bytes;
|
||||||
|
const gchar * str;
|
||||||
|
GError * error = NULL;
|
||||||
|
|
||||||
|
if (value == Py_None)
|
||||||
|
{
|
||||||
|
*certificate = NULL;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = PyUnicode_AsUTF8String (value);
|
||||||
|
if (bytes == NULL)
|
||||||
|
return FALSE;
|
||||||
|
str = PyBytes_AsString (bytes);
|
||||||
|
|
||||||
|
if (strchr (str, '\n') != NULL)
|
||||||
|
*certificate = g_tls_certificate_new_from_pem (str, -1, &error);
|
||||||
|
else
|
||||||
|
*certificate = g_tls_certificate_new_from_file (str, &error);
|
||||||
|
|
||||||
|
Py_DecRef (bytes);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
goto propagate_error;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
propagate_error:
|
||||||
|
{
|
||||||
|
PyFrida_raise (g_error_new_literal (FRIDA_ERROR, FRIDA_ERROR_INVALID_ARGUMENT, error->message));
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
PyGObject_marshal_certificate (GTlsCertificate * certificate)
|
||||||
|
{
|
||||||
|
PyObject * result;
|
||||||
|
gchar * pem;
|
||||||
|
|
||||||
|
if (certificate == NULL)
|
||||||
|
PyFrida_RETURN_NONE;
|
||||||
|
|
||||||
|
g_object_get (certificate, "certificate-pem", &pem, NULL);
|
||||||
|
|
||||||
|
result = PyGObject_marshal_string (pem);
|
||||||
|
|
||||||
|
g_free (pem);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
PyFrida_raise (GError * error)
|
PyFrida_raise (GError * error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ static PyObject * PyGObject_marshal_variant_byte_array (GVariant * variant);
|
|||||||
static PyObject * PyGObject_marshal_variant_dict (GVariant * variant);
|
static PyObject * PyGObject_marshal_variant_dict (GVariant * variant);
|
||||||
static PyObject * PyGObject_marshal_variant_array (GVariant * variant);
|
static PyObject * PyGObject_marshal_variant_array (GVariant * variant);
|
||||||
static PyObject * PyGObject_marshal_variant_tuple (GVariant * variant);
|
static PyObject * PyGObject_marshal_variant_tuple (GVariant * variant);
|
||||||
|
static gboolean PyGObject_unmarshal_certificate (PyObject * value, GTlsCertificate ** certificate);
|
||||||
|
static PyObject * PyGObject_marshal_certificate (GTlsCertificate * certificate);
|
||||||
|
|
||||||
static PyObject * PyFrida_raise (GError * error);
|
static PyObject * PyFrida_raise (GError * error);
|
||||||
static PyObject * PyFrida_marshal_error (GError * error);
|
static PyObject * PyFrida_marshal_error (GError * error);
|
||||||
|
|||||||
+290
-52
@@ -34,10 +34,14 @@ def read_asset(name: str) -> str:
|
|||||||
return (ASSETS_DIR / name).read_text(encoding="utf-8")
|
return (ASSETS_DIR / name).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
FACADE_TYPING_IMPORTS = (
|
FACADE_TYPING_IMPORTS = """\
|
||||||
"from typing import (Any, Callable, Dict, List, Literal, Mapping, NotRequired, Optional, Tuple, TypedDict, "
|
from typing import (Any, Callable, Dict, List, Literal, Mapping, Optional, Tuple, Sequence, Union, TypeVar, cast,
|
||||||
"Sequence, Union, ParamSpec, TypeVar, cast, overload)"
|
overload)
|
||||||
)
|
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from typing import NotRequired, ParamSpec, TypedDict
|
||||||
|
else:
|
||||||
|
from typing_extensions import NotRequired, ParamSpec, TypedDict"""
|
||||||
|
|
||||||
|
|
||||||
def generate_facade_preludes(model: Model) -> List[str]:
|
def generate_facade_preludes(model: Model) -> List[str]:
|
||||||
@@ -88,17 +92,25 @@ def _to_envp(value):
|
|||||||
|
|
||||||
def _make_options(cls, values, selectors):
|
def _make_options(cls, values, selectors):
|
||||||
options = cls()
|
options = cls()
|
||||||
|
_apply_settings(options, values, selectors)
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def _apply_settings(impl, values, selectors):
|
||||||
for name, value in values.items():
|
for name, value in values.items():
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
select = selectors.get(name)
|
select = selectors.get(name)
|
||||||
if select is None:
|
if select is None:
|
||||||
setattr(options, name, value)
|
setattr(impl, name, _unwrap(value))
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
add = getattr(impl, select)
|
||||||
|
for key, element in value.items():
|
||||||
|
add(key, _unwrap(element))
|
||||||
else:
|
else:
|
||||||
add = getattr(options, select)
|
add = getattr(impl, select)
|
||||||
for element in value:
|
for element in value:
|
||||||
add(element)
|
add(_unwrap(element))
|
||||||
return options
|
|
||||||
|
|
||||||
|
|
||||||
_current_cancellable = threading.local()
|
_current_cancellable = threading.local()
|
||||||
@@ -182,17 +194,25 @@ def _to_envp(value):
|
|||||||
|
|
||||||
def _make_options(cls, values, selectors):
|
def _make_options(cls, values, selectors):
|
||||||
options = cls()
|
options = cls()
|
||||||
|
_apply_settings(options, values, selectors)
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def _apply_settings(impl, values, selectors):
|
||||||
for name, value in values.items():
|
for name, value in values.items():
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
select = selectors.get(name)
|
select = selectors.get(name)
|
||||||
if select is None:
|
if select is None:
|
||||||
setattr(options, name, value)
|
setattr(impl, name, _unwrap(value))
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
add = getattr(impl, select)
|
||||||
|
for key, element in value.items():
|
||||||
|
add(key, _unwrap(element))
|
||||||
else:
|
else:
|
||||||
add = getattr(options, select)
|
add = getattr(impl, select)
|
||||||
for element in value:
|
for element in value:
|
||||||
add(element)
|
add(_unwrap(element))
|
||||||
return options
|
|
||||||
|
|
||||||
|
|
||||||
_current_cancellable: contextvars.ContextVar = contextvars.ContextVar("frida_current_cancellable", default=None)
|
_current_cancellable: contextvars.ContextVar = contextvars.ContextVar("frida_current_cancellable", default=None)
|
||||||
@@ -416,7 +436,7 @@ def generate_aio_async_method(method: Method, model: Model) -> Optional[str]:
|
|||||||
if method.return_value is not None:
|
if method.return_value is not None:
|
||||||
call = wrap_result(call, method.return_value.type, model)
|
call = wrap_result(call, method.return_value.type, model)
|
||||||
|
|
||||||
ret = "None" if method.return_value is None else pyi_type(method.return_value.type, model)
|
ret = facade_return_type(method, model)
|
||||||
|
|
||||||
return f""" async def {method.name}({signature}) -> {ret}:
|
return f""" async def {method.name}({signature}) -> {ret}:
|
||||||
return {call}"""
|
return {call}"""
|
||||||
@@ -426,11 +446,12 @@ def generate_custom_facade_method(
|
|||||||
method: Method, logic: Union[str, Tuple[str, str]], model: Model, awaitable: bool
|
method: Method, logic: Union[str, Tuple[str, str]], model: Model, awaitable: bool
|
||||||
) -> str:
|
) -> str:
|
||||||
signature = ", ".join(["self"] + method.custom_facade_params)
|
signature = ", ".join(["self"] + method.custom_facade_params)
|
||||||
|
args = facade_call_args(method, model)
|
||||||
if method.is_async:
|
if method.is_async:
|
||||||
invoke = f"_invoke(self._impl.{method.name}, ({method.facade_call_args}))"
|
invoke = f"_invoke(self._impl.{method.name}, ({args}))"
|
||||||
call = f"await {invoke}" if awaitable else invoke
|
call = f"await {invoke}" if awaitable else invoke
|
||||||
else:
|
else:
|
||||||
call = f"self._impl.{method.name}({method.facade_call_args})"
|
call = f"self._impl.{method.name}({args})"
|
||||||
if method.return_value is not None:
|
if method.return_value is not None:
|
||||||
call = wrap_result(call, method.return_value.type, model)
|
call = wrap_result(call, method.return_value.type, model)
|
||||||
|
|
||||||
@@ -439,13 +460,27 @@ def generate_custom_facade_method(
|
|||||||
body = textwrap.indent(logic.strip(), " " * 8)
|
body = textwrap.indent(logic.strip(), " " * 8)
|
||||||
keyword = "async def" if awaitable else "def"
|
keyword = "async def" if awaitable else "def"
|
||||||
|
|
||||||
ret = "None" if method.return_value is None else pyi_type(method.return_value.type, model)
|
ret = facade_return_type(method, model)
|
||||||
|
|
||||||
return f""" {keyword} {method.name}({signature}) -> {ret}:
|
return f""" {keyword} {method.name}({signature}) -> {ret}:
|
||||||
{body}
|
{body}
|
||||||
return {call}"""
|
return {call}"""
|
||||||
|
|
||||||
|
|
||||||
|
def facade_call_args(method: Method, model: Model) -> str:
|
||||||
|
takes_kwargs = any(param.split(":")[0].strip() == "**kwargs" for param in method.custom_facade_params)
|
||||||
|
args = []
|
||||||
|
for param in method.input_parameters:
|
||||||
|
if param.type.name == "Gio.Cancellable":
|
||||||
|
continue
|
||||||
|
options = resolve_options_type(param.type, model)
|
||||||
|
if options is not None and takes_kwargs:
|
||||||
|
args.append(make_options_expr(options))
|
||||||
|
else:
|
||||||
|
args.append(param.name)
|
||||||
|
return "".join(arg + ", " for arg in args)
|
||||||
|
|
||||||
|
|
||||||
def generate_py_exception_reexports(model: Model) -> List[str]:
|
def generate_py_exception_reexports(model: Model) -> List[str]:
|
||||||
names = [f"{member.js_name}Error" for member in model.error_domain.members]
|
names = [f"{member.js_name}Error" for member in model.error_domain.members]
|
||||||
names.append("OperationCancelledError")
|
names.append("OperationCancelledError")
|
||||||
@@ -501,10 +536,8 @@ def generate_facade_init(otype: ObjectType) -> str:
|
|||||||
{body}"""
|
{body}"""
|
||||||
|
|
||||||
return f""" def __init__(self, *args, **kwargs):
|
return f""" def __init__(self, *args, **kwargs):
|
||||||
self._impl = _frida.{otype.py_name}(
|
self._impl = _frida.{otype.py_name}(*[_unwrap(a) for a in args])
|
||||||
*[_unwrap(a) for a in args],
|
_apply_settings(self._impl, kwargs, {build_option_selectors(otype)})
|
||||||
**{{k: _unwrap(v) for k, v in kwargs.items()}},
|
|
||||||
)
|
|
||||||
setup = getattr(self, "_setup", None)
|
setup = getattr(self, "_setup", None)
|
||||||
if setup is not None:
|
if setup is not None:
|
||||||
setup()"""
|
setup()"""
|
||||||
@@ -627,21 +660,29 @@ def generate_py_sync_method(method: Method, model: Model) -> Optional[str]:
|
|||||||
if any(build_sync_param(param) is None for param in method.input_parameters):
|
if any(build_sync_param(param) is None for param in method.input_parameters):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
signature = ["self"]
|
params = [facade_param(param, model) for param in method.input_parameters]
|
||||||
for param in method.input_parameters:
|
names = ", ".join(facade_argument(param, model) for param in method.input_parameters)
|
||||||
signature.append(facade_param(param, model))
|
|
||||||
names = ", ".join(param.name for param in method.input_parameters)
|
|
||||||
|
|
||||||
call = f"self._impl.{method.name}({names})"
|
call = f"self._impl.{method.name}({names})"
|
||||||
if method.return_value is not None:
|
if method.return_value is not None:
|
||||||
call = wrap_result(call, method.return_value.type, model)
|
call = wrap_result(call, method.return_value.type, model)
|
||||||
|
|
||||||
ret = "None" if method.return_value is None else pyi_type(method.return_value.type, model)
|
ret = facade_return_type(method, model)
|
||||||
|
|
||||||
return f""" def {method.name}({", ".join(signature)}) -> {ret}:
|
return f""" def {method.name}({facade_signature(method, params)}) -> {ret}:
|
||||||
return {call}"""
|
return {call}"""
|
||||||
|
|
||||||
|
|
||||||
|
def facade_signature(method: Method, params: List[str]) -> str:
|
||||||
|
return ", ".join(["self"] + (method.custom_facade_params or params))
|
||||||
|
|
||||||
|
|
||||||
|
def facade_argument(param, model: Model) -> str:
|
||||||
|
if resolve_input_object_type(param.type, model) is not None:
|
||||||
|
return f"_unwrap({param.name})"
|
||||||
|
return param.name
|
||||||
|
|
||||||
|
|
||||||
def facade_param(param, model: Model) -> str:
|
def facade_param(param, model: Model) -> str:
|
||||||
annotation = pyi_type(param.type, model)
|
annotation = pyi_type(param.type, model)
|
||||||
if param.nullable:
|
if param.nullable:
|
||||||
@@ -662,14 +703,14 @@ def generate_py_async_method(method: Method, model: Model) -> Optional[str]:
|
|||||||
if method.return_value is not None:
|
if method.return_value is not None:
|
||||||
call = wrap_result(call, method.return_value.type, model)
|
call = wrap_result(call, method.return_value.type, model)
|
||||||
|
|
||||||
ret = "None" if method.return_value is None else pyi_type(method.return_value.type, model)
|
ret = facade_return_type(method, model)
|
||||||
|
|
||||||
return f""" def {method.name}({signature}) -> {ret}:
|
return f""" def {method.name}({signature}) -> {ret}:
|
||||||
return {call}"""
|
return {call}"""
|
||||||
|
|
||||||
|
|
||||||
def build_facade_async_parts(method: Method, model: Model) -> Optional[Tuple[str, str]]:
|
def build_facade_async_parts(method: Method, model: Model) -> Optional[Tuple[str, str]]:
|
||||||
signature = ["self"]
|
params = []
|
||||||
args = []
|
args = []
|
||||||
for param in method.input_parameters:
|
for param in method.input_parameters:
|
||||||
if param.type.name == "Gio.Cancellable":
|
if param.type.name == "Gio.Cancellable":
|
||||||
@@ -678,20 +719,24 @@ def build_facade_async_parts(method: Method, model: Model) -> Optional[Tuple[str
|
|||||||
return None
|
return None
|
||||||
options = resolve_options_type(param.type, model)
|
options = resolve_options_type(param.type, model)
|
||||||
if options is not None:
|
if options is not None:
|
||||||
signature.append("**kwargs")
|
params.append("**kwargs")
|
||||||
args.append(f"_make_options(_frida.{options.py_name}, kwargs, {build_option_selectors(options)})")
|
args.append(make_options_expr(options))
|
||||||
elif resolve_input_object_type(param.type, model) is not None:
|
elif resolve_input_object_type(param.type, model) is not None:
|
||||||
signature.append(f"{param.name}: Optional[{pyi_type(param.type, model)}] = None")
|
params.append(f"{param.name}: Optional[{pyi_type(param.type, model)}] = None")
|
||||||
args.append(f"_unwrap({param.name})")
|
args.append(f"_unwrap({param.name})")
|
||||||
else:
|
else:
|
||||||
signature.append(facade_param(param, model))
|
params.append(facade_param(param, model))
|
||||||
args.append(param.name)
|
args.append(param.name)
|
||||||
|
|
||||||
if method.return_value is not None:
|
if method.return_value is not None:
|
||||||
if build_return_marshal(method.return_value.type, model) is None:
|
if build_return_marshal(method.return_value.type, model) is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return ", ".join(signature), "".join(arg + ", " for arg in args)
|
return facade_signature(method, params), "".join(arg + ", " for arg in args)
|
||||||
|
|
||||||
|
|
||||||
|
def make_options_expr(options: ObjectType) -> str:
|
||||||
|
return f"_make_options(_frida.{options.py_name}, kwargs, {build_option_selectors(options)})"
|
||||||
|
|
||||||
|
|
||||||
def build_option_selectors(options: ObjectType) -> str:
|
def build_option_selectors(options: ObjectType) -> str:
|
||||||
@@ -748,13 +793,22 @@ def generate_pyi_class(otype: ObjectType, model: Model) -> List[str]:
|
|||||||
|
|
||||||
body = []
|
body = []
|
||||||
|
|
||||||
ctor = next(iter(otype.constructors), None)
|
primary = inline_constructor(otype)
|
||||||
if ctor is not None and not ctor.throws:
|
if primary is not None:
|
||||||
params = pyi_parameters(ctor.input_parameters, model)
|
params = pyi_parameters(primary.input_parameters, model)
|
||||||
if params is not None:
|
if params is not None:
|
||||||
signature = ", ".join(["self"] + params)
|
signature = ", ".join(["self"] + params)
|
||||||
body.append(f" def __init__({signature}) -> None: ...")
|
body.append(f" def __init__({signature}) -> None: ...")
|
||||||
|
|
||||||
|
for ctor in otype.constructors:
|
||||||
|
if ctor is primary:
|
||||||
|
continue
|
||||||
|
params = pyi_parameters(ctor.input_parameters, model)
|
||||||
|
if params is None:
|
||||||
|
continue
|
||||||
|
body.append(" @staticmethod")
|
||||||
|
body.append(f" def {ctor.name}({', '.join(params)}) -> {otype.py_name}: ...")
|
||||||
|
|
||||||
if otype.name == "Object":
|
if otype.name == "Object":
|
||||||
body.append(" def on(self, signal: str, callback: Callable[..., Any]) -> None: ...")
|
body.append(" def on(self, signal: str, callback: Callable[..., Any]) -> None: ...")
|
||||||
body.append(" def off(self, signal: str, callback: Callable[..., Any]) -> None: ...")
|
body.append(" def off(self, signal: str, callback: Callable[..., Any]) -> None: ...")
|
||||||
@@ -815,7 +869,13 @@ def pyi_method(method: Method, model: Model) -> Optional[str]:
|
|||||||
if params is None:
|
if params is None:
|
||||||
return None
|
return None
|
||||||
signature = ", ".join(["self"] + params)
|
signature = ", ".join(["self"] + params)
|
||||||
ret = "None" if method.return_value is None else pyi_type(method.return_value.type, model)
|
out = method.optional_out_parameter
|
||||||
|
if out is not None:
|
||||||
|
ret = f"Optional[{pyi_type(out.type, model)}]"
|
||||||
|
elif method.return_value is None:
|
||||||
|
ret = "None"
|
||||||
|
else:
|
||||||
|
ret = pyi_type(method.return_value.type, model)
|
||||||
return f" def {method.name}({signature}) -> {ret}: ..."
|
return f" def {method.name}({signature}) -> {ret}: ..."
|
||||||
|
|
||||||
|
|
||||||
@@ -860,6 +920,8 @@ def pyi_type(type: Type, model: Model) -> str:
|
|||||||
return "dict"
|
return "dict"
|
||||||
if name == "GLib.Variant":
|
if name == "GLib.Variant":
|
||||||
return "Any"
|
return "Any"
|
||||||
|
if name == "Gio.TlsCertificate":
|
||||||
|
return "str"
|
||||||
if resolve_enumeration(type, model) is not None:
|
if resolve_enumeration(type, model) is not None:
|
||||||
return "str"
|
return "str"
|
||||||
obj = resolve_object_type(type, model)
|
obj = resolve_object_type(type, model)
|
||||||
@@ -901,6 +963,10 @@ def generate_extension_c(model: Model) -> str:
|
|||||||
code += generate_interface_implementation(otype)
|
code += generate_interface_implementation(otype)
|
||||||
|
|
||||||
code += generate_object_type_constructor(otype)
|
code += generate_object_type_constructor(otype)
|
||||||
|
for ctor in factory_constructors(otype):
|
||||||
|
marshals = build_constructor_marshals(ctor)
|
||||||
|
assert marshals is not None
|
||||||
|
code += generate_factory_function(otype, ctor, marshals)
|
||||||
|
|
||||||
return code
|
return code
|
||||||
|
|
||||||
@@ -1175,6 +1241,10 @@ def generate_prototypes(model: Model) -> str:
|
|||||||
"",
|
"",
|
||||||
f"static int {otype_cprefix}_init ({otype_cprefix} * self, PyObject * args, PyObject * kw);",
|
f"static int {otype_cprefix}_init ({otype_cprefix} * self, PyObject * args, PyObject * kw);",
|
||||||
]
|
]
|
||||||
|
for ctor in factory_constructors(otype):
|
||||||
|
prototypes.append(
|
||||||
|
f"static PyObject * {otype_cprefix}_{ctor.name} (PyObject * self, PyObject * args, PyObject * kw);"
|
||||||
|
)
|
||||||
if implementable_interface(otype):
|
if implementable_interface(otype):
|
||||||
prototypes += [
|
prototypes += [
|
||||||
f"static int {otype_cprefix}_traverse (PyObject * self, visitproc visit, void * arg);",
|
f"static int {otype_cprefix}_traverse (PyObject * self, visitproc visit, void * arg);",
|
||||||
@@ -1291,6 +1361,9 @@ def generate_object_type_methods(otype: ObjectType) -> str:
|
|||||||
functions.append(function)
|
functions.append(function)
|
||||||
entries.append(entry)
|
entries.append(entry)
|
||||||
|
|
||||||
|
for ctor in factory_constructors(otype):
|
||||||
|
entries.append(factory_method_entry(otype, ctor))
|
||||||
|
|
||||||
return f"""{"".join(functions)}
|
return f"""{"".join(functions)}
|
||||||
static PyMethodDef {otype.c_symbol_prefix}_methods[] =
|
static PyMethodDef {otype.c_symbol_prefix}_methods[] =
|
||||||
{{
|
{{
|
||||||
@@ -1306,6 +1379,11 @@ def generate_method(otype: ObjectType, method: Method) -> Optional[Tuple[str, st
|
|||||||
marshal = synchronous_method_return_marshal(method)
|
marshal = synchronous_method_return_marshal(method)
|
||||||
if marshal is None:
|
if marshal is None:
|
||||||
return None
|
return None
|
||||||
|
out = method.optional_out_parameter
|
||||||
|
if out is not None:
|
||||||
|
marshal = build_return_marshal(out.type, method.object_type.model)
|
||||||
|
if marshal is None:
|
||||||
|
return None
|
||||||
params = []
|
params = []
|
||||||
for param in method.input_parameters:
|
for param in method.input_parameters:
|
||||||
sync_param = build_sync_param(param)
|
sync_param = build_sync_param(param)
|
||||||
@@ -1649,14 +1727,17 @@ def generate_synchronous_method(otype: ObjectType, method: Method, marshal: str,
|
|||||||
indent = " " * (len(otype.c_symbol_prefix) + len(method.name) + 3)
|
indent = " " * (len(otype.c_symbol_prefix) + len(method.name) + 3)
|
||||||
handle = f"({otype.c_type} *) PY_GOBJECT_HANDLE (self)"
|
handle = f"({otype.c_type} *) PY_GOBJECT_HANDLE (self)"
|
||||||
returns_strv = method.return_value is not None and method.return_value.type.name == "utf8[]"
|
returns_strv = method.return_value is not None and method.return_value.type.name == "utf8[]"
|
||||||
|
out = method.optional_out_parameter
|
||||||
call_arg_list = [handle] + [p.call_arg for p in params]
|
call_arg_list = [handle] + [p.call_arg for p in params]
|
||||||
if returns_strv:
|
if returns_strv:
|
||||||
call_arg_list.append("&retval_length")
|
call_arg_list.append("&retval_length")
|
||||||
|
if out is not None:
|
||||||
|
call_arg_list.append(f"&{out.name}")
|
||||||
if method.throws:
|
if method.throws:
|
||||||
call_arg_list.append("&error")
|
call_arg_list.append("&error")
|
||||||
call = f"{method.c_identifier} ({', '.join(call_arg_list)})"
|
call = f"{method.c_identifier} ({', '.join(call_arg_list)})"
|
||||||
|
|
||||||
if not params and not method.throws and not returns_strv:
|
if not params and not method.throws and not returns_strv and out is None:
|
||||||
if method.return_value is None:
|
if method.return_value is None:
|
||||||
body = f" {call};\n\n PyFrida_RETURN_NONE;"
|
body = f" {call};\n\n PyFrida_RETURN_NONE;"
|
||||||
else:
|
else:
|
||||||
@@ -1675,6 +1756,8 @@ static PyObject *
|
|||||||
decls.append(" GError * error = NULL;")
|
decls.append(" GError * error = NULL;")
|
||||||
if returns_strv:
|
if returns_strv:
|
||||||
decls.append(" gint retval_length;")
|
decls.append(" gint retval_length;")
|
||||||
|
if out is not None:
|
||||||
|
decls.append(f" {out_parameter_storage_type(out)} {out.name};")
|
||||||
for p in params:
|
for p in params:
|
||||||
decls += [f" {line}" for line in p.decl.splitlines()]
|
decls += [f" {line}" for line in p.decl.splitlines()]
|
||||||
|
|
||||||
@@ -1689,7 +1772,15 @@ static PyObject *
|
|||||||
|
|
||||||
pre = "".join(f"\n {p.pre}\n" for p in params if p.pre)
|
pre = "".join(f"\n {p.pre}\n" for p in params if p.pre)
|
||||||
|
|
||||||
if method.return_value is None:
|
if out is not None:
|
||||||
|
invocation = f" gboolean found = {call};"
|
||||||
|
success = (
|
||||||
|
" if (found)\n"
|
||||||
|
f" result = {marshal.format(value=out.name)};\n"
|
||||||
|
" else\n"
|
||||||
|
" {\n Py_IncRef (Py_None);\n result = Py_None;\n }"
|
||||||
|
)
|
||||||
|
elif method.return_value is None:
|
||||||
invocation = f" {call};"
|
invocation = f" {call};"
|
||||||
success = " Py_IncRef (Py_None);\n result = Py_None;"
|
success = " Py_IncRef (Py_None);\n result = Py_None;"
|
||||||
elif returns_strv:
|
elif returns_strv:
|
||||||
@@ -1734,6 +1825,22 @@ static PyObject *
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def facade_return_type(method: Method, model: Model) -> str:
|
||||||
|
out = method.optional_out_parameter
|
||||||
|
if out is not None:
|
||||||
|
return f"Optional[{pyi_type(out.type, model)}]"
|
||||||
|
if method.return_value is None:
|
||||||
|
return "None"
|
||||||
|
return pyi_type(method.return_value.type, model)
|
||||||
|
|
||||||
|
|
||||||
|
def out_parameter_storage_type(param: Parameter) -> str:
|
||||||
|
"""What the caller declares: the out parameter's own type, less the pointer."""
|
||||||
|
c = param.type.c
|
||||||
|
assert c.endswith("*"), c
|
||||||
|
return c[:-1].strip()
|
||||||
|
|
||||||
|
|
||||||
def synchronous_method_return_marshal(method: Method) -> Optional[str]:
|
def synchronous_method_return_marshal(method: Method) -> Optional[str]:
|
||||||
if method.is_async or method.is_property_accessor:
|
if method.is_async or method.is_property_accessor:
|
||||||
return None
|
return None
|
||||||
@@ -1816,6 +1923,16 @@ def build_sync_param(param: Parameter) -> Optional["SyncParam"]:
|
|||||||
cleanup=f"g_clear_pointer (&{name}, g_variant_unref);",
|
cleanup=f"g_clear_pointer (&{name}, g_variant_unref);",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if resolve_input_object_type(param.type, param.object_type.model) is not None:
|
||||||
|
return SyncParam(
|
||||||
|
decl=f"PyObject * {name}_obj;\n{param.type.c} {name} = NULL;",
|
||||||
|
fmt="O",
|
||||||
|
parse_args=[f"&{name}_obj"],
|
||||||
|
pre=f"""if ({name}_obj != Py_None)
|
||||||
|
{name} = ({param.type.c}) PY_GOBJECT_HANDLE ({name}_obj);""",
|
||||||
|
call_arg=name,
|
||||||
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -1994,6 +2111,17 @@ def build_setter_body(param: Parameter, set_call) -> Optional[str]:
|
|||||||
g_hash_table_unref (dict);
|
g_hash_table_unref (dict);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if type_name == "Gio.TlsCertificate":
|
||||||
|
return f""" GTlsCertificate * certificate;
|
||||||
|
|
||||||
|
if (!PyGObject_unmarshal_certificate (value, &certificate))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
{set_call("certificate")}
|
||||||
|
|
||||||
|
g_clear_object (&certificate);
|
||||||
|
"""
|
||||||
|
|
||||||
if resolve_input_object_type(param.type, param.object_type.model) is not None:
|
if resolve_input_object_type(param.type, param.object_type.model) is not None:
|
||||||
handle = f"({param.type.c}) ((value != Py_None) ? PY_GOBJECT_HANDLE (value) : NULL)"
|
handle = f"({param.type.c}) ((value != Py_None) ? PY_GOBJECT_HANDLE (value) : NULL)"
|
||||||
return f" {set_call(handle)}\n"
|
return f" {set_call(handle)}\n"
|
||||||
@@ -2073,6 +2201,8 @@ def build_return_marshal(type: Type, model: Model) -> Optional[str]:
|
|||||||
return "PyGObject_marshal_vardict ({value})"
|
return "PyGObject_marshal_vardict ({value})"
|
||||||
if name == "GLib.Variant":
|
if name == "GLib.Variant":
|
||||||
return "PyGObject_marshal_variant ({value})"
|
return "PyGObject_marshal_variant ({value})"
|
||||||
|
if name == "Gio.TlsCertificate":
|
||||||
|
return "PyGObject_marshal_certificate ({value})"
|
||||||
|
|
||||||
enum = resolve_enumeration(type, model)
|
enum = resolve_enumeration(type, model)
|
||||||
if enum is not None:
|
if enum is not None:
|
||||||
@@ -2219,28 +2349,55 @@ def generate_object_type_constructor(otype: ObjectType) -> str:
|
|||||||
if implementable_interface(otype):
|
if implementable_interface(otype):
|
||||||
return generate_interface_init(otype)
|
return generate_interface_init(otype)
|
||||||
|
|
||||||
ctor = next(iter(otype.constructors), None)
|
ctor = primary_constructor(otype)
|
||||||
|
|
||||||
if ctor is None:
|
if ctor is None:
|
||||||
return generate_bare_init(otype)
|
return generate_bare_init(otype)
|
||||||
|
|
||||||
marshals: Optional[List[ParamMarshal]] = None
|
if ctor.throws:
|
||||||
if not ctor.throws:
|
return generate_unconstructable_init(otype)
|
||||||
marshals = []
|
|
||||||
for param in ctor.input_parameters:
|
|
||||||
marshal = build_param_marshal(param)
|
|
||||||
if marshal is None:
|
|
||||||
marshals = None
|
|
||||||
break
|
|
||||||
marshal.optional = param.optional
|
|
||||||
marshals.append(marshal)
|
|
||||||
|
|
||||||
|
marshals = build_constructor_marshals(ctor)
|
||||||
if marshals is None:
|
if marshals is None:
|
||||||
return generate_unconstructable_init(otype)
|
return generate_unconstructable_init(otype)
|
||||||
|
|
||||||
return generate_constructor_init(otype, ctor, marshals)
|
return generate_constructor_init(otype, ctor, marshals)
|
||||||
|
|
||||||
|
|
||||||
|
def primary_constructor(otype: ObjectType) -> Optional[Procedure]:
|
||||||
|
if not otype.constructors:
|
||||||
|
return None
|
||||||
|
return next((c for c in otype.constructors if c.name == "new"), otype.constructors[0])
|
||||||
|
|
||||||
|
|
||||||
|
def inline_constructor(otype: ObjectType) -> Optional[Procedure]:
|
||||||
|
"""The constructor __init__ takes; one that throws is reached as a factory instead."""
|
||||||
|
ctor = primary_constructor(otype)
|
||||||
|
if ctor is None or ctor.throws:
|
||||||
|
return None
|
||||||
|
return ctor
|
||||||
|
|
||||||
|
|
||||||
|
def factory_constructors(otype: ObjectType) -> List[Procedure]:
|
||||||
|
primary = inline_constructor(otype)
|
||||||
|
return [
|
||||||
|
ctor
|
||||||
|
for ctor in otype.constructors
|
||||||
|
if ctor is not primary and not ctor.is_async and build_constructor_marshals(ctor) is not None
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def build_constructor_marshals(ctor: Procedure) -> Optional[List["ParamMarshal"]]:
|
||||||
|
marshals = []
|
||||||
|
for param in ctor.input_parameters:
|
||||||
|
marshal = build_param_marshal(param)
|
||||||
|
if marshal is None:
|
||||||
|
return None
|
||||||
|
marshal.optional = param.optional
|
||||||
|
marshals.append(marshal)
|
||||||
|
return marshals
|
||||||
|
|
||||||
|
|
||||||
def generate_interface_init(otype: ObjectType) -> str:
|
def generate_interface_init(otype: ObjectType) -> str:
|
||||||
n = interface_impl_names(otype)
|
n = interface_impl_names(otype)
|
||||||
indent = constructor_indent(otype)
|
indent = constructor_indent(otype)
|
||||||
@@ -2341,7 +2498,88 @@ static int
|
|||||||
{generate_constructor_tail(marshals)}"""
|
{generate_constructor_tail(marshals)}"""
|
||||||
|
|
||||||
|
|
||||||
def generate_argument_parse(marshals: List["ParamMarshal"]) -> str:
|
def factory_method_entry(otype: ObjectType, ctor: Procedure) -> str:
|
||||||
|
return (
|
||||||
|
f' {{ "{ctor.name}", (PyCFunction) {otype.c_symbol_prefix}_{ctor.name}, '
|
||||||
|
"METH_VARARGS | METH_KEYWORDS | METH_STATIC, NULL },"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_factory_function(otype: ObjectType, ctor: Procedure, marshals: List["ParamMarshal"]) -> str:
|
||||||
|
indent = " " * (len(otype.c_symbol_prefix) + len(ctor.name) + 3)
|
||||||
|
|
||||||
|
decls = [line for m in marshals for line in m.decls]
|
||||||
|
decls.append(f"{otype.c_type} * handle;")
|
||||||
|
if ctor.throws:
|
||||||
|
decls.append("GError * error = NULL;")
|
||||||
|
decls.append("PyObject * result = NULL;")
|
||||||
|
decls_block = indent_c_code("\n".join(decls), 1, prologue="\n")
|
||||||
|
|
||||||
|
keyword_decl = ""
|
||||||
|
parse_block = ""
|
||||||
|
if marshals:
|
||||||
|
keywords = ", ".join([f'"{m.keyword}"' for m in marshals] + ["NULL"])
|
||||||
|
keyword_decl = f"\n static char * keywords[] = {{ {keywords} }};"
|
||||||
|
parse_block = "\n" + generate_argument_parse(marshals, on_failure="return NULL;")
|
||||||
|
|
||||||
|
post_block = ""
|
||||||
|
for m in marshals:
|
||||||
|
if m.post is not None:
|
||||||
|
post_block += indent_c_code(m.post, 1, prologue="\n") + "\n"
|
||||||
|
|
||||||
|
call_args = [m.call_arg for m in marshals]
|
||||||
|
if ctor.throws:
|
||||||
|
call_args.append("&error")
|
||||||
|
call = f"handle = ({otype.c_type} *) {ctor.c_identifier} ({', '.join(call_args)});"
|
||||||
|
|
||||||
|
error_block = ""
|
||||||
|
if ctor.throws:
|
||||||
|
error_block = """
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
result = PyFrida_raise (error);
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
take_handle = f"result = PyGObject_new_take_handle (g_steal_pointer (&handle), PYFRIDA_TYPE ({otype.py_name}));"
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
static PyObject *
|
||||||
|
{otype.c_symbol_prefix}_{ctor.name} (PyObject * self,
|
||||||
|
{indent}PyObject * args,
|
||||||
|
{indent}PyObject * kw)
|
||||||
|
{{{keyword_decl}{decls_block}
|
||||||
|
{parse_block}{post_block}
|
||||||
|
{call}
|
||||||
|
{error_block}
|
||||||
|
{take_handle}
|
||||||
|
|
||||||
|
{generate_factory_tail(marshals, ctor.throws)}"""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_factory_tail(marshals: List["ParamMarshal"], throws: bool) -> str:
|
||||||
|
cleanups = [m.cleanup for m in marshals if m.cleanup is not None]
|
||||||
|
cleanup_block = indent_c_code("\n".join(reversed(cleanups)), 1) if cleanups else ""
|
||||||
|
|
||||||
|
if throws or constructor_needs_beach(marshals):
|
||||||
|
prologue = f"{cleanup_block}\n\n" if cleanup_block else ""
|
||||||
|
return f"""beach:
|
||||||
|
{prologue} return result;
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
if cleanup_block:
|
||||||
|
return f"""{cleanup_block}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
return """ return result;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_argument_parse(marshals: List["ParamMarshal"], on_failure: str = "return -1;") -> str:
|
||||||
fmt = ""
|
fmt = ""
|
||||||
optional_started = False
|
optional_started = False
|
||||||
for m in marshals:
|
for m in marshals:
|
||||||
@@ -2355,7 +2593,7 @@ def generate_argument_parse(marshals: List["ParamMarshal"]) -> str:
|
|||||||
indent = " " * len(" if (!PyArg_ParseTupleAndKeywords (")
|
indent = " " * len(" if (!PyArg_ParseTupleAndKeywords (")
|
||||||
parse_args_str = (",\n" + indent).join(parse_args)
|
parse_args_str = (",\n" + indent).join(parse_args)
|
||||||
return f""" if (!PyArg_ParseTupleAndKeywords ({parse_args_str}))
|
return f""" if (!PyArg_ParseTupleAndKeywords ({parse_args_str}))
|
||||||
return -1;
|
{on_failure}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -119,11 +119,7 @@ if aux:
|
|||||||
),
|
),
|
||||||
"attach": MethodCustomizations(
|
"attach": MethodCustomizations(
|
||||||
param_typings=["target: ProcessTarget", "**kwargs: Any"],
|
param_typings=["target: ProcessTarget", "**kwargs: Any"],
|
||||||
custom_logic=(
|
custom_logic=_RESOLVE_PID,
|
||||||
"pid = self._pid_of(target)\n" "options = _make_options(_frida.SessionOptions, kwargs, {})",
|
|
||||||
"pid = await self._pid_of(target)\n"
|
|
||||||
"options = _make_options(_frida.SessionOptions, kwargs, {})",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
custom_code=CustomCode(
|
custom_code=CustomCode(
|
||||||
@@ -141,6 +137,7 @@ if aux:
|
|||||||
param_typings=["message: Any", "data: Optional[bytes] = None"],
|
param_typings=["message: Any", "data: Optional[bytes] = None"],
|
||||||
custom_logic="json = _to_json(message)",
|
custom_logic="json = _to_json(message)",
|
||||||
),
|
),
|
||||||
|
"enable_debugger": MethodCustomizations(param_typings=["port: int = 0"]),
|
||||||
"is_destroyed": MethodCustomizations(as_property=True),
|
"is_destroyed": MethodCustomizations(as_property=True),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ class Model(core.Model):
|
|||||||
|
|
||||||
|
|
||||||
class ObjectType(core.ObjectType):
|
class ObjectType(core.ObjectType):
|
||||||
|
@cached_property
|
||||||
|
def methods(self) -> List["Method"]:
|
||||||
|
return [m for m in super().methods if not m.out_parameters or m.optional_out_parameter is not None]
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def py_name(self) -> str:
|
def py_name(self) -> str:
|
||||||
custom = self.customizations
|
custom = self.customizations
|
||||||
@@ -144,10 +148,6 @@ class Method(core.Method):
|
|||||||
custom = self.customizations
|
custom = self.customizations
|
||||||
return custom.custom_logic if custom is not None else None
|
return custom.custom_logic if custom is not None else None
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def facade_call_args(self) -> str:
|
|
||||||
return "".join(f"{param.name}, " for param in self.input_parameters if param.type.name != "Gio.Cancellable")
|
|
||||||
|
|
||||||
|
|
||||||
class Property(core.Property):
|
class Property(core.Property):
|
||||||
pass
|
pass
|
||||||
@@ -281,6 +281,7 @@ def _make_class(
|
|||||||
type_struct,
|
type_struct,
|
||||||
parent,
|
parent,
|
||||||
constructors,
|
constructors,
|
||||||
|
functions,
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
signals,
|
signals,
|
||||||
@@ -295,6 +296,7 @@ def _make_class(
|
|||||||
type_struct,
|
type_struct,
|
||||||
parent,
|
parent,
|
||||||
constructors,
|
constructors,
|
||||||
|
functions,
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
signals,
|
signals,
|
||||||
@@ -311,6 +313,7 @@ def _make_interface(
|
|||||||
type_struct,
|
type_struct,
|
||||||
parent,
|
parent,
|
||||||
constructors,
|
constructors,
|
||||||
|
functions,
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
signals,
|
signals,
|
||||||
@@ -324,6 +327,7 @@ def _make_interface(
|
|||||||
type_struct,
|
type_struct,
|
||||||
parent,
|
parent,
|
||||||
constructors,
|
constructors,
|
||||||
|
functions,
|
||||||
methods,
|
methods,
|
||||||
properties,
|
properties,
|
||||||
signals,
|
signals,
|
||||||
|
|||||||
+1
-1
Submodule releng updated: abb8238970...fe7d31dfbc.
@@ -1,6 +1,6 @@
|
|||||||
[wrap-git]
|
[wrap-git]
|
||||||
url = https://github.com/frida/frida-core.git
|
url = https://github.com/frida/frida-core.git
|
||||||
revision = 17.16.4
|
revision = 588ac3b3ded6779f095825df5c64cab59f0c6774
|
||||||
depth = 1
|
depth = 1
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
|
|||||||
@@ -17,6 +17,27 @@ BINDGEN_CORE = REPO / "frida-bindgen"
|
|||||||
GIRDIR = REPO / "build" / "subprojects" / "frida-core" / "src" / "api"
|
GIRDIR = REPO / "build" / "subprojects" / "frida-core" / "src" / "api"
|
||||||
OUTDIR = REPO / "build" / "bindgen-out"
|
OUTDIR = REPO / "build" / "bindgen-out"
|
||||||
BUILT_EXTENSION = REPO / "build" / "frida" / "_frida.abi3.so"
|
BUILT_EXTENSION = REPO / "build" / "frida" / "_frida.abi3.so"
|
||||||
|
CERTIFICATE = """\
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDGzCCAgOgAwIBAgIUEoCZX+FRWNTzcvvrCE2chFvE0EgwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwHDEaMBgGA1UEAwwRZnJpZGEtcHl0aG9uLXRlc3QwIBcNMjYwNzMwMjIyNjAy
|
||||||
|
WhgPMjEyNjA3MDYyMjI2MDJaMBwxGjAYBgNVBAMMEWZyaWRhLXB5dGhvbi10ZXN0
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtKTIUbHLhkqRKdKqXuMc
|
||||||
|
u7q8OZD2eKdykp4Qvv+I5JcmNW7nlW+58zTCLaqUCsSrojDb8T2qvtRJbaJYAofE
|
||||||
|
P7bhb5ROOVwsyOjhvP7rZ4zRXIDAUlB7zE15yNkWL+Rh4l3wRxMOMIB2HQlurtDk
|
||||||
|
PIqPOITwRvrADKZt/73iMASwrkkqKnl/F3rLT0JQrd907sBdGGZNbJM9L4TUBT9t
|
||||||
|
MBBl6qXtDEFyBfeoqlnrLUTN/Jwyka+/6n6eZCN8g2g5tS1Lc7LFjX4iBG9ibgaH
|
||||||
|
hrNSTM+haLImFS3dtXFr4rOCAHnDYYvkCY1nuZOXannCvZowv0xczqpGLbj5IYJK
|
||||||
|
MQIDAQABo1MwUTAdBgNVHQ4EFgQUi83cV5yMTdWaVeRpgNO3vyeitMMwHwYDVR0j
|
||||||
|
BBgwFoAUi83cV5yMTdWaVeRpgNO3vyeitMMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAQEADScSFuasB4mgOb/kktq3O09rf/uUIa6OEjdFRec/i2+E
|
||||||
|
ZAUd5onsWQTHm4yhjqQwqVBte58tTqZB7S1HMCy5sEgEVUFnTrMUqtrf/WAnsWA6
|
||||||
|
SdjNr7h/aRnLHHysLkbl0Zo4fOIWIYSJpLn39e0OzcNBjEHN5U9HE/m/2LFku1Kb
|
||||||
|
KMTYXrhBKvVPpZLxZyoLz00EM7euaNx3juAgfQdSDfKGahf5CqqMJ/VmITISDJDR
|
||||||
|
jtN3wcv0/nZA5x/b73QCj0jqIEWqguYf4GLWitxGsSdT2dBEpT88Kz3Ibwb8uRT+
|
||||||
|
Ls3eRsdoqxiOT0E7Z44O8gjbqsYOr/jdMShwEytDwQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(
|
@unittest.skipUnless(
|
||||||
@@ -131,6 +152,29 @@ class TestExtension(unittest.TestCase):
|
|||||||
options.argv = None
|
options.argv = None
|
||||||
self.assertIsNone(options.argv)
|
self.assertIsNone(options.argv)
|
||||||
|
|
||||||
|
def test_certificate_property_accepts_pem_and_path(self):
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
options = self._frida.RemoteDeviceOptions()
|
||||||
|
self.assertIsNone(options.certificate)
|
||||||
|
|
||||||
|
options.certificate = CERTIFICATE
|
||||||
|
self.assertEqual(options.certificate, CERTIFICATE)
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile("w", suffix=".pem") as f:
|
||||||
|
f.write(CERTIFICATE)
|
||||||
|
f.flush()
|
||||||
|
options.certificate = f.name
|
||||||
|
self.assertEqual(options.certificate, CERTIFICATE)
|
||||||
|
|
||||||
|
options.certificate = None
|
||||||
|
self.assertIsNone(options.certificate)
|
||||||
|
|
||||||
|
def test_certificate_property_rejects_missing_file(self):
|
||||||
|
options = self._frida.RemoteDeviceOptions()
|
||||||
|
with self.assertRaises(self._frida.InvalidArgumentError):
|
||||||
|
options.certificate = "/nonexistent.pem"
|
||||||
|
|
||||||
def test_vardict_property_round_trips(self):
|
def test_vardict_property_round_trips(self):
|
||||||
options = self._frida.SpawnOptions()
|
options = self._frida.SpawnOptions()
|
||||||
options.aux = {"name": "value", "count": 42, "flag": True}
|
options.aux = {"name": "value", "count": 42, "flag": True}
|
||||||
@@ -646,6 +690,16 @@ class TestFacade(unittest.TestCase):
|
|||||||
finally:
|
finally:
|
||||||
session.detach()
|
session.detach()
|
||||||
|
|
||||||
|
def test_attach_accepts_linker_notifier_offsets(self):
|
||||||
|
session = self.frida.get_local_device().attach(0, linker_notifier_offsets=[0x100])
|
||||||
|
session.detach()
|
||||||
|
|
||||||
|
def test_enable_debugger_defaults_to_any_port(self):
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
for script in [self.frida.Script, self.frida.aio.Script]:
|
||||||
|
self.assertEqual(inspect.signature(script.enable_debugger).parameters["port"].default, 0)
|
||||||
|
|
||||||
def test_file_monitor_reports_changes(self):
|
def test_file_monitor_reports_changes(self):
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|||||||
Reference in new issue
Block a user