mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 09:43:06 +00:00
352c31e1ac
Add struct drgn_type_template_parameter to libdrgn, the corresponding TypeTemplateParameter to the Python bindings, and support for parsing them from DWARF. With this, support for templates is almost, but not quite, complete. The main wart is that DW_TAG_name of compound types includes the template parameters, so the type tag includes it as well. We should remove that from the tag and instead have the type formatting code add it only when getting the full type name. Based on a patch from Jay Kamat. Signed-off-by: Omar Sandoval <osandov@osandov.com>
333 lines
9.7 KiB
C
333 lines
9.7 KiB
C
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#ifdef WITH_KDUMPFILE
|
|
#include <libkdumpfile/kdumpfile.h>
|
|
#endif
|
|
|
|
#include "drgnpy.h"
|
|
#include "../path.h"
|
|
|
|
PyObject *MissingDebugInfoError;
|
|
PyObject *ObjectAbsentError;
|
|
PyObject *OutOfBoundsError;
|
|
|
|
static PyObject *filename_matches(PyObject *self, PyObject *args,
|
|
PyObject *kwds)
|
|
{
|
|
static char *keywords[] = {"haystack", "needle", NULL};
|
|
struct path_arg haystack_arg = {.allow_none = true};
|
|
struct path_arg needle_arg = {.allow_none = true};
|
|
struct path_iterator haystack = {
|
|
.components = (struct path_iterator_component [1]){},
|
|
.num_components = 0,
|
|
};
|
|
struct path_iterator needle = {
|
|
.components = (struct path_iterator_component [1]){},
|
|
.num_components = 0,
|
|
};
|
|
bool ret;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&:filename_matches",
|
|
keywords, path_converter,
|
|
&haystack_arg, path_converter,
|
|
&needle_arg))
|
|
return NULL;
|
|
|
|
if (haystack_arg.path) {
|
|
haystack.components[0].path = haystack_arg.path;
|
|
haystack.components[0].len = haystack_arg.length;
|
|
haystack.num_components = 1;
|
|
}
|
|
if (needle_arg.path) {
|
|
needle.components[0].path = needle_arg.path;
|
|
needle.components[0].len = needle_arg.length;
|
|
needle.num_components = 1;
|
|
}
|
|
ret = path_ends_with(&haystack, &needle);
|
|
path_cleanup(&haystack_arg);
|
|
path_cleanup(&needle_arg);
|
|
if (ret)
|
|
Py_RETURN_TRUE;
|
|
else
|
|
Py_RETURN_FALSE;
|
|
}
|
|
|
|
static PyObject *sizeof_(PyObject *self, PyObject *arg)
|
|
{
|
|
struct drgn_error *err;
|
|
uint64_t size;
|
|
|
|
if (PyObject_TypeCheck(arg, &DrgnType_type)) {
|
|
err = drgn_type_sizeof(((DrgnType *)arg)->type, &size);
|
|
} else if (PyObject_TypeCheck(arg, &DrgnObject_type)) {
|
|
err = drgn_object_sizeof(&((DrgnObject *)arg)->obj, &size);
|
|
} else {
|
|
return PyErr_Format(PyExc_TypeError,
|
|
"expected Type or Object, not %s",
|
|
Py_TYPE(arg)->tp_name);
|
|
}
|
|
if (err)
|
|
return set_drgn_error(err);
|
|
return PyLong_FromUnsignedLongLong(size);
|
|
}
|
|
|
|
static PyObject *offsetof_(PyObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
struct drgn_error *err;
|
|
|
|
static char *keywords[] = {"type", "member", NULL};
|
|
DrgnType *type;
|
|
const char *member;
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!s:offsetof", keywords,
|
|
&DrgnType_type, &type, &member))
|
|
return NULL;
|
|
uint64_t offset;
|
|
err = drgn_type_offsetof(type->type, member, &offset);
|
|
if (err)
|
|
return set_drgn_error(err);
|
|
return PyLong_FromUnsignedLongLong(offset);
|
|
}
|
|
|
|
static PyMethodDef drgn_methods[] = {
|
|
{"filename_matches", (PyCFunction)filename_matches,
|
|
METH_VARARGS | METH_KEYWORDS, drgn_filename_matches_DOC},
|
|
{"NULL", (PyCFunction)DrgnObject_NULL, METH_VARARGS | METH_KEYWORDS,
|
|
drgn_NULL_DOC},
|
|
{"sizeof", (PyCFunction)sizeof_, METH_O, drgn_sizeof_DOC},
|
|
{"offsetof", (PyCFunction)offsetof_, METH_VARARGS | METH_KEYWORDS,
|
|
drgn_offsetof_DOC},
|
|
{"cast", (PyCFunction)cast, METH_VARARGS | METH_KEYWORDS,
|
|
drgn_cast_DOC},
|
|
{"reinterpret", (PyCFunction)reinterpret, METH_VARARGS | METH_KEYWORDS,
|
|
drgn_reinterpret_DOC},
|
|
{"container_of", (PyCFunction)DrgnObject_container_of,
|
|
METH_VARARGS | METH_KEYWORDS, drgn_container_of_DOC},
|
|
{"program_from_core_dump", (PyCFunction)program_from_core_dump,
|
|
METH_VARARGS | METH_KEYWORDS, drgn_program_from_core_dump_DOC},
|
|
{"program_from_kernel", (PyCFunction)program_from_kernel,
|
|
METH_NOARGS, drgn_program_from_kernel_DOC},
|
|
{"program_from_pid", (PyCFunction)program_from_pid,
|
|
METH_VARARGS | METH_KEYWORDS, drgn_program_from_pid_DOC},
|
|
{"_linux_helper_read_vm", (PyCFunction)drgnpy_linux_helper_read_vm,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_radix_tree_lookup",
|
|
(PyCFunction)drgnpy_linux_helper_radix_tree_lookup,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_idr_find", (PyCFunction)drgnpy_linux_helper_idr_find,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_find_pid", (PyCFunction)drgnpy_linux_helper_find_pid,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_pid_task", (PyCFunction)drgnpy_linux_helper_pid_task,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_find_task", (PyCFunction)drgnpy_linux_helper_find_task,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_kaslr_offset",
|
|
(PyCFunction)drgnpy_linux_helper_kaslr_offset,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{"_linux_helper_pgtable_l5_enabled",
|
|
(PyCFunction)drgnpy_linux_helper_pgtable_l5_enabled,
|
|
METH_VARARGS | METH_KEYWORDS},
|
|
{},
|
|
};
|
|
|
|
static struct PyModuleDef drgnmodule = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"_drgn",
|
|
drgn_DOC,
|
|
-1,
|
|
drgn_methods,
|
|
};
|
|
|
|
/*
|
|
* These are for type checking and aren't strictly required at runtime, but
|
|
* adding them anyways results in better pydoc output and saves us from fiddling
|
|
* with typing.TYPE_CHECKING/forward references.
|
|
*/
|
|
static int add_type_aliases(PyObject *m)
|
|
{
|
|
/*
|
|
* This should be a subclass of typing.Protocol, but that is only
|
|
* available since Python 3.8.
|
|
*/
|
|
PyObject *IntegerLike = PyType_FromSpec(&(PyType_Spec){
|
|
.name = "_drgn.IntegerLike",
|
|
.flags = Py_TPFLAGS_DEFAULT,
|
|
.slots = (PyType_Slot []){{0, NULL}},
|
|
});
|
|
if (!IntegerLike)
|
|
return -1;
|
|
if (PyModule_AddObject(m, "IntegerLike", IntegerLike) == -1) {
|
|
Py_DECREF(IntegerLike);
|
|
return -1;
|
|
}
|
|
|
|
PyObject *os_module = PyImport_ImportModule("os");
|
|
if (!os_module)
|
|
return -1;
|
|
PyObject *os_PathLike = PyObject_GetAttrString(os_module, "PathLike");
|
|
Py_DECREF(os_module);
|
|
if (!os_PathLike)
|
|
return -1;
|
|
PyObject *item = Py_BuildValue("OOO", &PyUnicode_Type, &PyBytes_Type,
|
|
os_PathLike);
|
|
Py_DECREF(os_PathLike);
|
|
if (!item)
|
|
return -1;
|
|
|
|
PyObject *typing_module = PyImport_ImportModule("typing");
|
|
if (!typing_module) {
|
|
Py_DECREF(item);
|
|
return -1;
|
|
}
|
|
PyObject *typing_Union = PyObject_GetAttrString(typing_module, "Union");
|
|
Py_DECREF(typing_module);
|
|
if (!typing_Union) {
|
|
Py_DECREF(item);
|
|
return -1;
|
|
}
|
|
|
|
PyObject *Path = PyObject_GetItem(typing_Union, item);
|
|
Py_DECREF(typing_Union);
|
|
Py_DECREF(item);
|
|
if (!Path)
|
|
return -1;
|
|
if (PyModule_AddObject(m, "Path", Path) == -1) {
|
|
Py_DECREF(Path);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DRGNPY_PUBLIC PyMODINIT_FUNC PyInit__drgn(void)
|
|
{
|
|
PyObject *m;
|
|
PyObject *host_platform_obj;
|
|
PyObject *with_libkdumpfile;
|
|
|
|
m = PyModule_Create(&drgnmodule);
|
|
if (!m)
|
|
return NULL;
|
|
|
|
if (add_module_constants(m) == -1 || add_type_aliases(m) == -1)
|
|
goto err;
|
|
|
|
FaultError_type.tp_base = (PyTypeObject *)PyExc_Exception;
|
|
if (PyType_Ready(&FaultError_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&FaultError_type);
|
|
PyModule_AddObject(m, "FaultError", (PyObject *)&FaultError_type);
|
|
|
|
MissingDebugInfoError = PyErr_NewExceptionWithDoc("_drgn.MissingDebugInfoError",
|
|
drgn_MissingDebugInfoError_DOC,
|
|
NULL, NULL);
|
|
if (!MissingDebugInfoError)
|
|
goto err;
|
|
PyModule_AddObject(m, "MissingDebugInfoError", MissingDebugInfoError);
|
|
|
|
ObjectAbsentError =
|
|
PyErr_NewExceptionWithDoc("_drgn.ObjectAbsentError",
|
|
drgn_ObjectAbsentError_DOC,
|
|
NULL, NULL);
|
|
if (!ObjectAbsentError)
|
|
goto err;
|
|
PyModule_AddObject(m, "ObjectAbsentError", ObjectAbsentError);
|
|
|
|
OutOfBoundsError = PyErr_NewExceptionWithDoc("_drgn.OutOfBoundsError",
|
|
drgn_OutOfBoundsError_DOC,
|
|
NULL, NULL);
|
|
if (!OutOfBoundsError)
|
|
goto err;
|
|
PyModule_AddObject(m, "OutOfBoundsError", OutOfBoundsError);
|
|
|
|
if (PyType_Ready(&Language_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&Language_type);
|
|
PyModule_AddObject(m, "Language", (PyObject *)&Language_type);
|
|
if (add_languages() == -1)
|
|
goto err;
|
|
|
|
if (PyStructSequence_InitType2(&Register_type, &Register_desc) == -1)
|
|
goto err;
|
|
PyModule_AddObject(m, "Register", (PyObject *)&Register_type);
|
|
|
|
if (PyType_Ready(&DrgnObject_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&DrgnObject_type);
|
|
PyModule_AddObject(m, "Object", (PyObject *)&DrgnObject_type);
|
|
|
|
if (PyType_Ready(&ObjectIterator_type) < 0)
|
|
goto err;
|
|
|
|
if (PyType_Ready(&Platform_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&Platform_type);
|
|
PyModule_AddObject(m, "Platform", (PyObject *)&Platform_type);
|
|
|
|
if (PyType_Ready(&Program_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&Program_type);
|
|
PyModule_AddObject(m, "Program", (PyObject *)&Program_type);
|
|
|
|
if (PyType_Ready(&StackFrame_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&StackFrame_type);
|
|
PyModule_AddObject(m, "StackFrame", (PyObject *)&StackFrame_type);
|
|
|
|
if (PyType_Ready(&StackTrace_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&StackTrace_type);
|
|
PyModule_AddObject(m, "StackTrace", (PyObject *)&StackTrace_type);
|
|
|
|
if (PyType_Ready(&Symbol_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&Symbol_type);
|
|
PyModule_AddObject(m, "Symbol", (PyObject *)&Symbol_type);
|
|
|
|
if (PyType_Ready(&DrgnType_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&DrgnType_type);
|
|
PyModule_AddObject(m, "Type", (PyObject *)&DrgnType_type);
|
|
|
|
if (PyType_Ready(&TypeEnumerator_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&TypeEnumerator_type);
|
|
PyModule_AddObject(m, "TypeEnumerator",
|
|
(PyObject *)&TypeEnumerator_type);
|
|
|
|
if (PyType_Ready(&TypeMember_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&TypeMember_type);
|
|
PyModule_AddObject(m, "TypeMember", (PyObject *)&TypeMember_type);
|
|
|
|
if (PyType_Ready(&TypeParameter_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&TypeParameter_type);
|
|
PyModule_AddObject(m, "TypeParameter", (PyObject *)&TypeParameter_type);
|
|
|
|
if (PyType_Ready(&TypeTemplateParameter_type) < 0)
|
|
goto err;
|
|
Py_INCREF(&TypeTemplateParameter_type);
|
|
PyModule_AddObject(m, "TypeTemplateParameter",
|
|
(PyObject *)&TypeTemplateParameter_type);
|
|
|
|
host_platform_obj = Platform_wrap(&drgn_host_platform);
|
|
if (!host_platform_obj)
|
|
goto err;
|
|
PyModule_AddObject(m, "host_platform", host_platform_obj);
|
|
|
|
#ifdef WITH_LIBKDUMPFILE
|
|
with_libkdumpfile = Py_True;
|
|
#else
|
|
with_libkdumpfile = Py_False;
|
|
#endif
|
|
Py_INCREF(with_libkdumpfile);
|
|
PyModule_AddObject(m, "_with_libkdumpfile", with_libkdumpfile);
|
|
|
|
return m;
|
|
|
|
err:
|
|
Py_DECREF(m);
|
|
return NULL;
|
|
}
|