Skip to content

Commit

Permalink
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
Delphix Engineering committed Oct 25, 2024
2 parents ec8dc35 + 0fff129 commit e460008
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 69 deletions.
4 changes: 4 additions & 0 deletions libdrgn/python/drgnpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,10 @@ struct path_arg {
int path_converter(PyObject *o, void *p);
void path_cleanup(struct path_arg *path);

#define PATH_ARG(name, ...) \
__attribute__((__cleanup__(path_cleanup))) \
struct path_arg name = { __VA_ARGS__ }

struct enum_arg {
PyObject *type;
unsigned long value;
Expand Down
9 changes: 3 additions & 6 deletions libdrgn/python/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ 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};
PATH_ARG(haystack_arg, .allow_none = true);
PATH_ARG(needle_arg, .allow_none = true);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&O&:filename_matches",
keywords, path_converter,
&haystack_arg, path_converter,
Expand All @@ -88,10 +88,7 @@ static PyObject *filename_matches(PyObject *self, PyObject *args,
needle.components[0].len = needle_arg.length;
needle.num_components = 1;
}
bool ret = path_ends_with(&haystack, &needle);
path_cleanup(&haystack_arg);
path_cleanup(&needle_arg);
Py_RETURN_BOOL(ret);
Py_RETURN_BOOL(path_ends_with(&haystack, &needle));
}

static PyObject *sizeof_(PyObject *self, PyObject *arg)
Expand Down
84 changes: 37 additions & 47 deletions libdrgn/python/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ static PyObject *Program_set_core_dump(Program *self, PyObject *args,
{
static char *keywords[] = {"path", NULL};
struct drgn_error *err;
struct path_arg path = { .allow_fd = true };
PATH_ARG(path, .allow_fd = true);

if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:set_core_dump",
keywords, path_converter, &path))
Expand All @@ -835,7 +835,6 @@ static PyObject *Program_set_core_dump(Program *self, PyObject *args,
err = drgn_program_set_core_dump_fd(&self->prog, path.fd);
else
err = drgn_program_set_core_dump(&self->prog, path.path);
path_cleanup(&path);
if (err)
return set_drgn_error(err);
Py_RETURN_NONE;
Expand Down Expand Up @@ -869,6 +868,13 @@ static PyObject *Program_set_pid(Program *self, PyObject *args, PyObject *kwds)

DEFINE_VECTOR(path_arg_vector, struct path_arg);

static void path_arg_vector_cleanup(struct path_arg_vector *path_args)
{
vector_for_each(path_arg_vector, path_arg, path_args)
path_cleanup(path_arg);
path_arg_vector_deinit(path_args);
}

static PyObject *Program_load_debug_info(Program *self, PyObject *args,
PyObject *kwds)
{
Expand All @@ -882,19 +888,20 @@ static PyObject *Program_load_debug_info(Program *self, PyObject *args,
&load_main))
return NULL;

struct path_arg_vector path_args = VECTOR_INIT;
const char **paths = NULL;
_cleanup_(path_arg_vector_cleanup)
struct path_arg_vector path_args = VECTOR_INIT;
_cleanup_free_ const char **paths = NULL;
if (paths_obj != Py_None) {
_cleanup_pydecref_ PyObject *it = PyObject_GetIter(paths_obj);
if (!it)
goto out;
return NULL;

Py_ssize_t length_hint = PyObject_LengthHint(paths_obj, 1);
if (length_hint == -1)
goto out;
return NULL;
if (!path_arg_vector_reserve(&path_args, length_hint)) {
PyErr_NoMemory();
goto out;
return NULL;
}

for (;;) {
Expand All @@ -906,39 +913,33 @@ static PyObject *Program_load_debug_info(Program *self, PyObject *args,
path_arg_vector_append_entry(&path_args);
if (!path_arg) {
PyErr_NoMemory();
break;
return NULL;
}
memset(path_arg, 0, sizeof(*path_arg));
if (!path_converter(item, path_arg)) {
path_arg_vector_pop(&path_args);
break;
return NULL;
}
}
if (PyErr_Occurred())
goto out;
return NULL;

paths = malloc_array(path_arg_vector_size(&path_args),
sizeof(*paths));
if (!paths) {
PyErr_NoMemory();
goto out;
return NULL;
}
for (size_t i = 0; i < path_arg_vector_size(&path_args); i++)
paths[i] = path_arg_vector_at(&path_args, i)->path;
}
err = drgn_program_load_debug_info(&self->prog, paths,
path_arg_vector_size(&path_args),
load_default, load_main);
free(paths);
if (err)
if (err) {
set_drgn_error(err);

out:
vector_for_each(path_arg_vector, path_arg, &path_args)
path_cleanup(path_arg);
path_arg_vector_deinit(&path_args);
if (PyErr_Occurred())
return NULL;
}
Py_RETURN_NONE;
}

Expand Down Expand Up @@ -1018,31 +1019,29 @@ static PyObject *Program_find_type(Program *self, PyObject *args, PyObject *kwds
static char *keywords[] = {"name", "filename", NULL};
struct drgn_error *err;
PyObject *name_or_type;
struct path_arg filename = {.allow_none = true};
PATH_ARG(filename, .allow_none = true);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&:type", keywords,
&name_or_type, path_converter,
&filename))
return NULL;

PyObject *ret = NULL;
if (PyObject_TypeCheck(name_or_type, &DrgnType_type)) {
if (DrgnType_prog((DrgnType *)name_or_type) != self) {
PyErr_SetString(PyExc_ValueError,
"type is from different program");
goto out;
return NULL;
}
Py_INCREF(name_or_type);
ret = name_or_type;
goto out;
return name_or_type;
} else if (!PyUnicode_Check(name_or_type)) {
PyErr_SetString(PyExc_TypeError,
"type() argument 1 must be str or Type");
goto out;
return NULL;
}

const char *name = PyUnicode_AsUTF8(name_or_type);
if (!name)
goto out;
return NULL;
bool clear = set_drgn_in_python();
struct drgn_qualified_type qualified_type;
err = drgn_program_find_type(&self->prog, name, filename.path,
Expand All @@ -1051,12 +1050,9 @@ static PyObject *Program_find_type(Program *self, PyObject *args, PyObject *kwds
clear_drgn_in_python();
if (err) {
set_drgn_error(err);
goto out;
return NULL;
}
ret = DrgnType_wrap(qualified_type);
out:
path_cleanup(&filename);
return ret;
return DrgnType_wrap(qualified_type);
}

static DrgnObject *Program_find_object(Program *self, const char *name,
Expand All @@ -1065,22 +1061,19 @@ static DrgnObject *Program_find_object(Program *self, const char *name,
{
struct drgn_error *err;

DrgnObject *ret = DrgnObject_alloc(self);
_cleanup_pydecref_ DrgnObject *ret = DrgnObject_alloc(self);
if (!ret)
goto out;
return NULL;
bool clear = set_drgn_in_python();
err = drgn_program_find_object(&self->prog, name, filename->path, flags,
&ret->obj);
if (clear)
clear_drgn_in_python();
if (err) {
set_drgn_error(err);
Py_DECREF(ret);
ret = NULL;
return NULL;
}
out:
path_cleanup(filename);
return ret;
return_ptr(ret);
}

static DrgnObject *Program_object(Program *self, PyObject *args,
Expand All @@ -1092,7 +1085,7 @@ static DrgnObject *Program_object(Program *self, PyObject *args,
.type = FindObjectFlags_class,
.value = DRGN_FIND_OBJECT_ANY,
};
struct path_arg filename = {.allow_none = true};
PATH_ARG(filename, .allow_none = true);

if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&O&:object", keywords,
&name, enum_converter, &flags,
Expand All @@ -1107,7 +1100,7 @@ static DrgnObject *Program_constant(Program *self, PyObject *args,
{
static char *keywords[] = {"name", "filename", NULL};
const char *name;
struct path_arg filename = {.allow_none = true};
PATH_ARG(filename, .allow_none = true);

if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&:constant", keywords,
&name, path_converter, &filename))
Expand All @@ -1122,7 +1115,7 @@ static DrgnObject *Program_function(Program *self, PyObject *args,
{
static char *keywords[] = {"name", "filename", NULL};
const char *name;
struct path_arg filename = {.allow_none = true};
PATH_ARG(filename, .allow_none = true);

if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&:function", keywords,
&name, path_converter, &filename))
Expand All @@ -1137,7 +1130,7 @@ static DrgnObject *Program_variable(Program *self, PyObject *args,
{
static char *keywords[] = {"name", "filename", NULL};
const char *name;
struct path_arg filename = {.allow_none = true};
PATH_ARG(filename, .allow_none = true);

if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&:variable", keywords,
&name, path_converter, &filename))
Expand Down Expand Up @@ -1598,24 +1591,21 @@ Program *program_from_core_dump(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"path", NULL};
struct drgn_error *err;
struct path_arg path = { .allow_fd = true };
PATH_ARG(path, .allow_fd = true);
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"O&:program_from_core_dump", keywords,
path_converter, &path))
return NULL;

_cleanup_pydecref_ Program *prog =
(Program *)PyObject_CallObject((PyObject *)&Program_type, NULL);
if (!prog) {
path_cleanup(&path);
if (!prog)
return NULL;
}

if (path.fd >= 0)
err = drgn_program_init_core_dump_fd(&prog->prog, path.fd);
else
err = drgn_program_init_core_dump(&prog->prog, path.path);
path_cleanup(&path);
if (err)
return set_drgn_error(err);
return_ptr(prog);
Expand Down
14 changes: 1 addition & 13 deletions tests/linux_kernel/test_debug_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pathlib import Path
import unittest

from drgn import Object, Program
from drgn import Program
from tests import modifyenv
from tests.linux_kernel import LinuxKernelTestCase, skip_unless_have_test_kmod

Expand Down Expand Up @@ -48,15 +48,3 @@ def test_module_debug_info_use_proc_and_sys(self):

def test_module_debug_info_use_core_dump(self):
self._test_module_debug_info(False)


class TestLinuxKernelObjectFinder(LinuxKernelTestCase):
def test_jiffies(self):
self.assertIdentical(
self.prog["jiffies"],
Object(
self.prog,
"volatile unsigned long",
address=self.prog.symbol("jiffies").address,
),
)
18 changes: 15 additions & 3 deletions tests/linux_kernel/test_special_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,30 @@

import os

import drgn
from drgn import Object, Program
from tests.linux_kernel import LinuxKernelTestCase


class TestJiffies(LinuxKernelTestCase):
def test_jiffies(self):
self.assertIdentical(
self.prog["jiffies"],
Object(
self.prog,
"volatile unsigned long",
address=self.prog.symbol("jiffies").address,
),
)


class TestUts(LinuxKernelTestCase):
def test_uts_release(self):
self.assertEqual(
self.prog["UTS_RELEASE"].string_().decode(), os.uname().release
)

def test_uts_release_no_debug_info(self):
prog = drgn.Program()
prog = Program()
prog.set_kernel()
self.assertEqual(prog["UTS_RELEASE"].string_().decode(), os.uname().release)

Expand All @@ -31,7 +43,7 @@ def test_vmcoreinfo(self):
)

def test_vmcoreinfo_no_debug_info(self):
prog = drgn.Program()
prog = Program()
prog.set_kernel()
vmcoreinfo_data = dict(
line.split("=", 1)
Expand Down

0 comments on commit e460008

Please sign in to comment.