diff --git a/src/_frida.c b/src/_frida.c index 0bbb4e5..bfec6c9 100644 --- a/src/_frida.c +++ b/src/_frida.c @@ -106,6 +106,7 @@ typedef struct _PyApplication PyApplication; typedef struct _PyProcess PyProcess; typedef struct _PySpawn PySpawn; typedef struct _PyChild PyChild; +typedef struct _PyCrash PyCrash; typedef struct _PyIcon PyIcon; typedef struct _PySession PySession; typedef struct _PyScript PyScript; @@ -185,6 +186,15 @@ struct _PyChild PyObject * envp; }; +struct _PyCrash +{ + PyGObject parent; + guint pid; + PyObject * process_name; + PyObject * report; + PyObject * parameters; +}; + struct _PyIcon { PyGObject parent; @@ -239,6 +249,7 @@ static gboolean PyGObject_unmarshal_envp (PyObject * value, gchar *** envp, gint static PyObject * PyGObject_marshal_enum (gint value, GType type); static gboolean PyGObject_unmarshal_enum (const gchar * str, GType type, gpointer value); static PyObject * PyGObject_marshal_bytes (GBytes * bytes); +static PyObject * PyGObject_marshal_variant_dict (GVariant * dict); static PyObject * PyGObject_marshal_object (gpointer handle, GType type); static int PyDeviceManager_init (PyDeviceManager * self, PyObject * args, PyObject * kwds); @@ -296,6 +307,11 @@ static void PyChild_init_from_handle (PyChild * self, FridaChild * handle); static void PyChild_dealloc (PyChild * self); static PyObject * PyChild_repr (PyChild * self); +static int PyCrash_init (PyCrash * self, PyObject * args, PyObject * kw); +static void PyCrash_init_from_handle (PyCrash * self, FridaCrash * handle); +static void PyCrash_dealloc (PyCrash * self); +static PyObject * PyCrash_repr (PyCrash * self); + static PyObject * PyIcon_new_from_handle (FridaIcon * handle); static int PyIcon_init (PyIcon * self, PyObject * args, PyObject * kw); static void PyIcon_init_from_handle (PyIcon * self, FridaIcon * handle); @@ -423,6 +439,15 @@ static PyMemberDef PyChild_members[] = { NULL } }; +static PyMemberDef PyCrash_members[] = +{ + { "pid", T_UINT, G_STRUCT_OFFSET (PyCrash, pid), READONLY, "Process ID." }, + { "process_name", T_OBJECT_EX, G_STRUCT_OFFSET (PyCrash, process_name), READONLY, "Process name." }, + { "report", T_OBJECT_EX, G_STRUCT_OFFSET (PyCrash, report), READONLY, "Human-readable crash report." }, + { "parameters", T_OBJECT_EX, G_STRUCT_OFFSET (PyCrash, parameters), READONLY, "Parameters." }, + { NULL } +}; + static PyMemberDef PyIcon_members[] = { { "width", T_INT, G_STRUCT_OFFSET (PyIcon, width), READONLY, "Width in pixels." }, @@ -762,6 +787,48 @@ static PyTypeObject PyChildType = PYFRIDA_DEFINE_TYPE (Child, PyChild_init_from_handle, g_object_unref); +static PyTypeObject PyCrashType = +{ + PyVarObject_HEAD_INIT (NULL, 0) + "_frida.Crash", /* tp_name */ + sizeof (PyCrash), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) PyCrash_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + (reprfunc) PyCrash_repr, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Frida Crash Details", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + PyCrash_members, /* tp_members */ + NULL, /* tp_getset */ + &PyGObjectType, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) PyCrash_init, /* tp_init */ +}; + +PYFRIDA_DEFINE_TYPE (Crash, PyCrash_init_from_handle, g_object_unref); + static PyTypeObject PyIconType = { PyVarObject_HEAD_INIT (NULL, 0) @@ -1587,6 +1654,48 @@ PyGObject_marshal_bytes (GBytes * bytes) return PyBytes_FromStringAndSize (data, size); } +static PyObject * +PyGObject_marshal_variant_dict (GVariant * dict) +{ + PyObject * result; + GVariantIter iter; + gchar * key; + GVariant * raw_value; + + result = PyDict_New (); + + g_variant_iter_init (&iter, dict); + while (g_variant_iter_next (&iter, "{sv}", &key, &raw_value)) + { + PyObject * value = NULL; + + if (g_variant_is_of_type (raw_value, G_VARIANT_TYPE_STRING)) + { + value = PyGObject_marshal_string (g_variant_get_string (raw_value, NULL)); + } + else if (g_variant_is_of_type (raw_value, G_VARIANT_TYPE_INT64)) + { + value = PyLong_FromLongLong (g_variant_get_int64 (raw_value)); + } + else if (g_variant_is_of_type (raw_value, G_VARIANT_TYPE_BOOLEAN)) + { + value = PyBool_FromLong (g_variant_get_boolean (raw_value)); + } + else + { + g_assert_not_reached (); + } + + PyDict_SetItemString (result, key, value); + + Py_DECREF (value); + g_variant_unref (raw_value); + g_free (key); + } + + return result; +} + static PyObject * PyGObject_marshal_object (gpointer handle, GType type) { @@ -2544,6 +2653,79 @@ PyChild_repr (PyChild * self) } +static int +PyCrash_init (PyCrash * self, PyObject * args, PyObject * kw) +{ + if (PyGObjectType.tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + self->pid = 0; + self->process_name = NULL; + self->report = NULL; + self->parameters = NULL; + + return 0; +} + +static void +PyCrash_init_from_handle (PyCrash * self, FridaCrash * handle) +{ + GVariantDict * parameters_dict; + GVariant * parameters; + + self->pid = frida_crash_get_pid (handle); + self->process_name = PyGObject_marshal_string (frida_crash_get_process_name (handle)); + self->report = PyGObject_marshal_string (frida_crash_get_report (handle)); + + parameters_dict = frida_crash_load_parameters (handle); + parameters = g_variant_dict_end (parameters_dict); + self->parameters = PyGObject_marshal_variant_dict (parameters); + g_variant_unref (parameters); + g_variant_dict_unref (parameters_dict); +} + +static void +PyCrash_dealloc (PyCrash * self) +{ + Py_XDECREF (self->process_name); + Py_XDECREF (self->report); + Py_XDECREF (self->parameters); + + PyGObjectType.tp_dealloc ((PyObject *) self); +} + +static PyObject * +PyCrash_repr (PyCrash * self) +{ + PyObject * result; + FridaCrash * handle; + GString * repr; + gchar * str; + + handle = PY_GOBJECT_HANDLE (self); + + repr = g_string_new ("Crash("); + + g_string_append_printf (repr, "pid=%u, process_name=\"%s\"", self->pid, frida_crash_get_process_name (handle)); + + str = PyFrida_repr (self->report); + g_string_append_printf (repr, ", report=%s", str); + g_free (str); + + str = PyFrida_repr (self->parameters); + g_string_append_printf (repr, ", parameters=%s", str); + g_free (str); + + g_string_append (repr, ")"); + + result = PyRepr_FromString (repr->str); + + g_string_free (repr, TRUE); + + return result; +} + + static PyObject * PyIcon_new_from_handle (FridaIcon * handle) { @@ -3037,6 +3219,7 @@ MOD_INIT (_frida) PYFRIDA_REGISTER_TYPE (Process, FRIDA_TYPE_PROCESS); PYFRIDA_REGISTER_TYPE (Spawn, FRIDA_TYPE_SPAWN); PYFRIDA_REGISTER_TYPE (Child, FRIDA_TYPE_CHILD); + PYFRIDA_REGISTER_TYPE (Crash, FRIDA_TYPE_CRASH); PYFRIDA_REGISTER_TYPE (Icon, FRIDA_TYPE_ICON); PYFRIDA_REGISTER_TYPE (Session, FRIDA_TYPE_SESSION); PYFRIDA_REGISTER_TYPE (Script, FRIDA_TYPE_SCRIPT);