libdrgn: support loading only load main debug info

If we only want debugging information for vmlinux and not kernel
modules, it'd be nice to only load the former. This adds a load_main
parameter to drgn_program_load_debug_info() which specifies just that.
For now, it's only implemented for the Linux kernel. While we're here,
let's make the paths parameter optional for the Python bindings.
This commit is contained in:
Omar Sandoval 2019-11-22 16:21:36 -08:00
parent 09108d22fa
commit 6af6159cfc
6 changed files with 87 additions and 67 deletions

View File

@ -280,7 +280,7 @@ Programs
:param int pid: Process ID.
.. method:: load_debug_info(paths, default=False)
.. method:: load_debug_info(paths=None, default=False, main=False)
Load debugging information for a list of executable or library files.
@ -288,7 +288,7 @@ Programs
multiple files at once rather than one by one.
:param paths: Paths of binary files.
:type paths: Iterable[str, bytes, or os.PathLike]
:type paths: Iterable[str, bytes, or os.PathLike] or None
:param bool default: Also load debugging information which can
automatically be determined from the program.
@ -297,6 +297,14 @@ Programs
For userspace programs, this tries to load the executable and any
loaded libraries.
This implies ``main=True``.
:param bool main: Also load debugging information for the main
executable.
For the Linux kernel, this tries to load ``vmlinux``.
This is currently ignored for userspace programs.
:raises MissingDebugInfoError: if debugging information was not
available for some files; other files with debugging information
are still loaded
@ -306,7 +314,7 @@ Programs
Load debugging information which can automatically be determined from
the program.
This is equivalent to ``load_debug_info([], True)``.
This is equivalent to ``load_debug_info(None, True)``.
.. attribute:: cache

View File

@ -1149,11 +1149,14 @@ struct drgn_error *drgn_program_set_pid(struct drgn_program *prog, pid_t pid);
* Load debugging information for a list of executable or library files.
*
* @param[in] load_default Whether to also load debugging information which can
* automatically be determined from the program.
* automatically be determined from the program. This implies @p load_main.
* @param[in] load_main Whether to also load information for the main
* executable.
*/
struct drgn_error *drgn_program_load_debug_info(struct drgn_program *prog,
const char **paths, size_t n,
bool load_default);
bool load_default,
bool load_main);
/**
* Create a @ref drgn_program from a core dump file.

View File

@ -1341,10 +1341,9 @@ out:
return err;
}
static struct drgn_error *
report_default_vmlinux(struct drgn_program *prog,
struct drgn_dwarf_index *dindex,
bool *vmlinux_is_pending)
static struct drgn_error *report_vmlinux(struct drgn_program *prog,
struct drgn_dwarf_index *dindex,
bool *vmlinux_is_pending)
{
static const char * const vmlinux_paths[] = {
/*
@ -1396,7 +1395,7 @@ struct drgn_error *
linux_kernel_report_debug_info(struct drgn_program *prog,
struct drgn_dwarf_index *dindex,
const char **paths, size_t n,
bool report_default)
bool report_default, bool report_main)
{
struct drgn_error *err;
struct kernel_module_file *kmods;
@ -1404,7 +1403,7 @@ linux_kernel_report_debug_info(struct drgn_program *prog,
bool need_module_definition = false;
bool vmlinux_is_pending = false;
if (report_default && !prog->added_vmcoreinfo_object_finder) {
if (report_main && !prog->added_vmcoreinfo_object_finder) {
err = drgn_program_add_object_finder(prog,
vmcoreinfo_object_find,
prog);
@ -1506,9 +1505,9 @@ linux_kernel_report_debug_info(struct drgn_program *prog,
}
}
if (report_default && !vmlinux_is_pending &&
if (report_main && !vmlinux_is_pending &&
!drgn_dwarf_index_is_indexed(dindex, "kernel")) {
err = report_default_vmlinux(prog, dindex, &vmlinux_is_pending);
err = report_vmlinux(prog, dindex, &vmlinux_is_pending);
if (err)
goto out;
}

View File

@ -23,7 +23,7 @@ struct drgn_error *
linux_kernel_report_debug_info(struct drgn_program *prog,
struct drgn_dwarf_index *dindex,
const char **paths, size_t n,
bool report_default);
bool report_default, bool report_main);
#define KDUMP_SIGNATURE "KDUMP "
#define KDUMP_SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1)

View File

@ -599,15 +599,18 @@ static int drgn_set_platform_from_dwarf(Dwfl_Module *module, void **userdatap,
LIBDRGN_PUBLIC struct drgn_error *
drgn_program_load_debug_info(struct drgn_program *prog, const char **paths,
size_t n, bool load_default)
size_t n, bool load_default, bool load_main)
{
struct drgn_error *err;
struct drgn_dwarf_index *dindex;
bool report_from_dwfl;
if (!n && !load_default)
if (!n && !load_default && !load_main)
return NULL;
if (load_default)
load_main = true;
err = drgn_program_get_dindex(prog, &dindex);
if (err)
return err;
@ -615,7 +618,7 @@ drgn_program_load_debug_info(struct drgn_program *prog, const char **paths,
drgn_dwarf_index_report_begin(dindex);
if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) {
err = linux_kernel_report_debug_info(prog, dindex, paths, n,
load_default);
load_default, load_main);
} else {
err = userspace_report_debug_info(prog, dindex, paths, n,
load_default);
@ -625,7 +628,7 @@ drgn_program_load_debug_info(struct drgn_program *prog, const char **paths,
return err;
}
report_from_dwfl = (!(prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) &&
load_default);
load_main);
err = drgn_dwarf_index_report_end(dindex, report_from_dwfl);
if ((!err || err->code == DRGN_ERROR_MISSING_DEBUG_INFO) &&
!prog->has_platform) {
@ -729,7 +732,7 @@ struct drgn_error *drgn_program_init_core_dump(struct drgn_program *prog,
err = drgn_program_set_core_dump(prog, path);
if (err)
return err;
err = drgn_program_load_debug_info(prog, NULL, 0, true);
err = drgn_program_load_debug_info(prog, NULL, 0, true, true);
if (err && err->code == DRGN_ERROR_MISSING_DEBUG_INFO) {
drgn_error_destroy(err);
err = NULL;
@ -744,7 +747,7 @@ struct drgn_error *drgn_program_init_kernel(struct drgn_program *prog)
err = drgn_program_set_kernel(prog);
if (err)
return err;
err = drgn_program_load_debug_info(prog, NULL, 0, true);
err = drgn_program_load_debug_info(prog, NULL, 0, true, true);
if (err && err->code == DRGN_ERROR_MISSING_DEBUG_INFO) {
drgn_error_destroy(err);
err = NULL;
@ -759,7 +762,7 @@ struct drgn_error *drgn_program_init_pid(struct drgn_program *prog, pid_t pid)
err = drgn_program_set_pid(prog, pid);
if (err)
return err;
err = drgn_program_load_debug_info(prog, NULL, 0, true);
err = drgn_program_load_debug_info(prog, NULL, 0, true, true);
if (err && err->code == DRGN_ERROR_MISSING_DEBUG_INFO) {
drgn_error_destroy(err);
err = NULL;

View File

@ -420,63 +420,70 @@ static PyObject *Program_set_pid(Program *self, PyObject *args, PyObject *kwds)
static PyObject *Program_load_debug_info(Program *self, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {"paths", "default", NULL};
static char *keywords[] = {"paths", "default", "main", NULL};
struct drgn_error *err;
PyObject *paths_obj, *it, *item;
PyObject *paths_obj = Py_None;
struct path_arg *path_args = NULL;
Py_ssize_t length_hint;
size_t n = 0, i;
const char **paths;
const char **paths = NULL;
int load_default = 0;
int load_main = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|p:load_debug_info",
keywords, &paths_obj, &load_default))
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Opp:load_debug_info",
keywords, &paths_obj, &load_default,
&load_main))
return NULL;
it = PyObject_GetIter(paths_obj);
if (!it)
return NULL;
if (paths_obj != Py_None) {
Py_ssize_t length_hint;
PyObject *it, *item;
length_hint = PyObject_LengthHint(paths_obj, 1);
if (length_hint == -1) {
Py_DECREF(it);
return NULL;
}
path_args = calloc(length_hint, sizeof(*path_args));
if (!path_args) {
Py_DECREF(it);
return NULL;
}
it = PyObject_GetIter(paths_obj);
if (!it)
return NULL;
while ((item = PyIter_Next(it))) {
int ret;
if (n >= length_hint) {
length_hint *= 2;
if (!resize_array(&path_args, length_hint)) {
Py_DECREF(item);
PyErr_NoMemory();
break;
}
length_hint = PyObject_LengthHint(paths_obj, 1);
if (length_hint == -1) {
Py_DECREF(it);
return NULL;
}
path_args = calloc(length_hint, sizeof(*path_args));
if (!path_args) {
Py_DECREF(it);
return NULL;
}
ret = path_converter(item, &path_args[n]);
Py_DECREF(item);
if (!ret)
break;
n++;
}
Py_DECREF(it);
if (PyErr_Occurred())
goto out;
paths = malloc_array(n, sizeof(*paths));
if (!paths) {
PyErr_NoMemory();
goto out;
while ((item = PyIter_Next(it))) {
int ret;
if (n >= length_hint) {
length_hint *= 2;
if (!resize_array(&path_args, length_hint)) {
Py_DECREF(item);
PyErr_NoMemory();
break;
}
}
ret = path_converter(item, &path_args[n]);
Py_DECREF(item);
if (!ret)
break;
n++;
}
Py_DECREF(it);
if (PyErr_Occurred())
goto out;
paths = malloc_array(n, sizeof(*paths));
if (!paths) {
PyErr_NoMemory();
goto out;
}
for (i = 0; i < n; i++)
paths[i] = path_args[i].path;
}
for (i = 0; i < n; i++)
paths[i] = path_args[i].path;
err = drgn_program_load_debug_info(&self->prog, paths, n, load_default);
err = drgn_program_load_debug_info(&self->prog, paths, n, load_default,
load_main);
free(paths);
if (err)
set_drgn_error(err);
@ -493,7 +500,7 @@ static PyObject *Program_load_default_debug_info(Program *self)
{
struct drgn_error *err;
err = drgn_program_load_debug_info(&self->prog, NULL, 0, true);
err = drgn_program_load_debug_info(&self->prog, NULL, 0, true, true);
if (err)
return set_drgn_error(err);
Py_RETURN_NONE;