mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 09:43:06 +00:00
b899a10836
enum drgn_register_number in the public libdrgn API and drgn.Register.number in the Python bindings are basically exports of DWARF register numbers. They only exist as a way to identify registers that's lighter weight than string lookups. libdrgn already has struct drgn_register, so we can use that to identify registers in the public API and remove enum drgn_register_number. This has a couple of benefits: we don't depend on DWARF numbering in our API, and we don't have to generate drgn.h from the architecture files. The Python bindings can just use string names for now. If it seems useful, StackFrame.register() can take a Register in the future, we'll just need to be careful to not allow Registers from the wrong platform. While we're changing the API anyways, also change it so that registers have a list of names instead of one name. This isn't needed for x86-64 at the moment, but will be for architectures that have multiple names for the same register (like ARM). Signed-off-by: Omar Sandoval <osandov@osandov.com>
195 lines
5.1 KiB
C
195 lines
5.1 KiB
C
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "drgnpy.h"
|
|
|
|
PyObject *Platform_wrap(const struct drgn_platform *platform)
|
|
{
|
|
struct drgn_error *err;
|
|
struct drgn_platform *tmp;
|
|
Platform *ret;
|
|
|
|
err = drgn_platform_create(drgn_platform_arch(platform),
|
|
drgn_platform_flags(platform),
|
|
&tmp);
|
|
if (err)
|
|
return set_drgn_error(err);
|
|
ret = (Platform *)Platform_type.tp_alloc(&Platform_type, 0);
|
|
if (!ret)
|
|
return NULL;
|
|
ret->platform = tmp;
|
|
return (PyObject *)ret;
|
|
}
|
|
|
|
Platform *Platform_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
|
|
{
|
|
static char *keywords[] = {"arch", "flags", NULL};
|
|
struct enum_arg arch = { .type = Architecture_class, };
|
|
struct enum_arg flags = {
|
|
.type = PlatformFlags_class,
|
|
.value = DRGN_PLATFORM_DEFAULT_FLAGS,
|
|
.allow_none = true,
|
|
};
|
|
struct drgn_error *err;
|
|
struct drgn_platform *platform;
|
|
Platform *ret;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&:Platform", keywords,
|
|
enum_converter, &arch, enum_converter,
|
|
&flags))
|
|
return NULL;
|
|
|
|
err = drgn_platform_create(arch.value, flags.value, &platform);
|
|
if (err)
|
|
return set_drgn_error(err);
|
|
ret = (Platform *)subtype->tp_alloc(subtype, 0);
|
|
if (!ret) {
|
|
drgn_platform_destroy(platform);
|
|
return NULL;
|
|
}
|
|
ret->platform = platform;
|
|
return ret;
|
|
}
|
|
|
|
static void Platform_dealloc(Platform *self)
|
|
{
|
|
drgn_platform_destroy(self->platform);
|
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
}
|
|
|
|
static PyObject *Platform_richcompare(Platform *self, PyObject *other, int op)
|
|
{
|
|
if (!PyObject_TypeCheck(other, &Platform_type) ||
|
|
(op != Py_EQ && op != Py_NE))
|
|
Py_RETURN_NOTIMPLEMENTED;
|
|
bool ret = drgn_platform_eq(self->platform,
|
|
((Platform *)other)->platform);
|
|
if (op == Py_NE)
|
|
ret = !ret;
|
|
Py_RETURN_BOOL(ret);
|
|
}
|
|
|
|
static PyObject *Platform_get_arch(Platform *self, void *arg)
|
|
{
|
|
return PyObject_CallFunction(Architecture_class, "k",
|
|
(unsigned long)drgn_platform_arch(self->platform));
|
|
}
|
|
|
|
static PyObject *Platform_get_flags(Platform *self, void *arg)
|
|
{
|
|
return PyObject_CallFunction(PlatformFlags_class, "k",
|
|
(unsigned long)drgn_platform_flags(self->platform));
|
|
}
|
|
|
|
static PyObject *Platform_get_registers(Platform *self, void *arg)
|
|
{
|
|
size_t num_registers = drgn_platform_num_registers(self->platform);
|
|
PyObject *tuple = PyTuple_New(num_registers);
|
|
if (!tuple)
|
|
return NULL;
|
|
for (size_t i = 0; i < num_registers; i++) {
|
|
const struct drgn_register *reg =
|
|
drgn_platform_register(self->platform, i);
|
|
PyObject *item = Register_type.tp_alloc(&Register_type, 0);
|
|
if (!item) {
|
|
Py_DECREF(tuple);
|
|
return NULL;
|
|
}
|
|
((Register *)item)->reg = reg;
|
|
PyTuple_SET_ITEM(tuple, i, item);
|
|
}
|
|
return tuple;
|
|
}
|
|
|
|
static PyObject *Platform_repr(Platform *self)
|
|
{
|
|
PyObject *arch_obj, *flags_obj, *ret;
|
|
|
|
arch_obj = Platform_get_arch(self, NULL);
|
|
if (!arch_obj)
|
|
return NULL;
|
|
flags_obj = Platform_get_flags(self, NULL);
|
|
if (!flags_obj) {
|
|
Py_DECREF(arch_obj);
|
|
return NULL;
|
|
}
|
|
ret = PyUnicode_FromFormat("Platform(%R, %R)", arch_obj, flags_obj);
|
|
Py_XDECREF(flags_obj);
|
|
Py_XDECREF(arch_obj);
|
|
return ret;
|
|
}
|
|
|
|
static PyGetSetDef Platform_getset[] = {
|
|
{"arch", (getter)Platform_get_arch, NULL, drgn_Platform_arch_DOC},
|
|
{"flags", (getter)Platform_get_flags, NULL, drgn_Platform_flags_DOC},
|
|
{"registers", (getter)Platform_get_registers, NULL,
|
|
drgn_Platform_registers_DOC},
|
|
{},
|
|
};
|
|
|
|
PyTypeObject Platform_type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "_drgn.Platform",
|
|
.tp_basicsize = sizeof(Platform),
|
|
.tp_dealloc = (destructor)Platform_dealloc,
|
|
.tp_repr = (reprfunc)Platform_repr,
|
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
|
.tp_doc = drgn_Platform_DOC,
|
|
.tp_richcompare = (richcmpfunc)Platform_richcompare,
|
|
.tp_getset = Platform_getset,
|
|
.tp_new = (newfunc)Platform_new,
|
|
};
|
|
|
|
static PyObject *Register_richcompare(Register *self, PyObject *other, int op)
|
|
{
|
|
if (!PyObject_TypeCheck(other, &Register_type) ||
|
|
(op != Py_EQ && op != Py_NE))
|
|
Py_RETURN_NOTIMPLEMENTED;
|
|
bool ret = self->reg == ((Register *)other)->reg;
|
|
if (op == Py_NE)
|
|
ret = !ret;
|
|
Py_RETURN_BOOL(ret);
|
|
}
|
|
|
|
static PyObject *Register_get_names(Register *self, void *arg)
|
|
{
|
|
size_t num_names;
|
|
const char * const *names = drgn_register_names(self->reg, &num_names);
|
|
PyObject *ret = PyTuple_New(num_names);
|
|
for (size_t i = 0; i < num_names; i++) {
|
|
PyObject *item = PyUnicode_FromString(names[i]);
|
|
if (!item) {
|
|
Py_DECREF(ret);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(ret, i, item);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static PyObject *Register_repr(Register *self)
|
|
{
|
|
PyObject *names_obj = Register_get_names(self, NULL);
|
|
if (!names_obj)
|
|
return NULL;
|
|
PyObject *ret = PyUnicode_FromFormat("Register(%R)", names_obj);
|
|
Py_DECREF(names_obj);
|
|
return ret;
|
|
}
|
|
|
|
static PyGetSetDef Register_getset[] = {
|
|
{"names", (getter)Register_get_names, NULL, drgn_Register_names_DOC},
|
|
{},
|
|
};
|
|
|
|
PyTypeObject Register_type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "_drgn.Register",
|
|
.tp_basicsize = sizeof(Register),
|
|
.tp_repr = (reprfunc)Register_repr,
|
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
|
.tp_doc = drgn_Register_DOC,
|
|
.tp_richcompare = (richcmpfunc)Register_richcompare,
|
|
.tp_getset = Register_getset,
|
|
};
|