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 Dec 19, 2024
2 parents 924145a + 92023c5 commit e5710bc
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 38 deletions.
1 change: 1 addition & 0 deletions docs/release_highlights.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ from the full `release notes <https://github.com/osandov/drgn/releases>`_.

.. toctree::

release_highlights/0.0.30.rst
release_highlights/0.0.28.rst
release_highlights/0.0.27.rst
release_highlights/0.0.26.rst
Expand Down
41 changes: 41 additions & 0 deletions docs/release_highlights/0.0.30.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
0.0.30 (Released December 18th, 2024)
=====================================

These are some of the highlights of drgn 0.0.30. See the `GitHub release
<https://github.com/osandov/drgn/releases/tag/v0.0.30>`_ for the full release
notes, including more improvements and bug fixes.

This release is relatively small, as most development effort has been focused
on the upcoming `module API <https://github.com/osandov/drgn/issues/332>`_,
which is expected to land in the next release.

Symbol Index and Kallsyms
-------------------------

Stephen Brennan continued his efforts towards `making it possible to debug the
Linux kernel without full DWARF debugging information
<https://github.com/osandov/drgn/issues/176>`_. The next step in this release
was adding new helpers for looking up symbols from kallsyms:
:func:`~drgn.helpers.linux.kallsyms.load_vmlinux_kallsyms()` and
:func:`~drgn.helpers.linux.kallsyms.load_module_kallsyms()`. These are built on
top of a new, generic API for fast symbol lookups: :class:`drgn.SymbolIndex`.

New Python 3.13 REPL
--------------------

Python 3.13 `added
<https://docs.python.org/3/whatsnew/3.13.html#a-better-interactive-interpreter>`_
a vastly improved REPL with multiline editing, colorized output, interactive
help, and more. drgn now makes use of this REPL when it is available.

Stack Tracing Through Interrupt Handlers
----------------------------------------

drgn had a longstanding `bug <https://github.com/osandov/drgn/issues/304>`_
where stack traces would stop at an interrupt handler frame. This release fixes
that (as long as the kernel is configured to use the ORC unwinder).

Linux 6.13 Support
------------------

No drgn changes were required to support Linux 6.13 as of rc3.
14 changes: 6 additions & 8 deletions libdrgn/arch_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,15 +607,13 @@ linux_kernel_pgtable_iterator_next_x86_64(struct drgn_program *prog,
for (;; level--) {
uint64_t table;
bool table_physical;
if (level == levels && prog->vmcoreinfo.phys_base &&
if (level == levels && prog->vmcoreinfo.have_phys_base &&
it->it.pgtable == prog->vmcoreinfo.swapper_pg_dir) {
// Avoid recursive address translation on swapper_pg_dir by
// directly resolving to a physical address. Don't do
// this if phys_base is 0, since that likely means it
// was not present in the vmcoreinfo. It has been
// present since Linux kernel commit 401721ecd1dc
// ("kexec: export the value of phys_base instead of
// symbol address") (in v4.10).
// Avoid recursive address translation on swapper_pg_dir
// by directly resolving to a physical address.
// phys_base has been present since Linux kernel commit
// 401721ecd1dc ("kexec: export the value of phys_base
// instead of symbol address") (in v4.10).
table = it->it.pgtable + prog->vmcoreinfo.phys_base - START_KERNEL_MAP;
table_physical = true;
} else if (level == levels) {
Expand Down
2 changes: 1 addition & 1 deletion libdrgn/configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dnl Copyright (c) Meta Platforms, Inc. and affiliates.
dnl SPDX-License-Identifier: LGPL-2.1-or-later

AC_INIT([libdrgn], [0.0.29],
AC_INIT([libdrgn], [0.0.30],
[https://github.com/osandov/drgn/issues],,
[https://github.com/osandov/drgn])

Expand Down
2 changes: 1 addition & 1 deletion libdrgn/drgn.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
/** Minor version of drgn. */
#define DRGN_VERSION_MINOR 0
/** Patch level of drgn. */
#define DRGN_VERSION_PATCH 29
#define DRGN_VERSION_PATCH 30

/**
* @defgroup ErrorHandling Error handling
Expand Down
1 change: 1 addition & 0 deletions libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct drgn_error *drgn_program_parse_vmcoreinfo(struct drgn_program *prog,
&prog->vmcoreinfo.phys_base);
if (err)
return err;
prog->vmcoreinfo.have_phys_base = true;
break;
}
@case "NUMBER(KERNELPACMASK)"@
Expand Down
18 changes: 18 additions & 0 deletions libdrgn/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,24 @@ static inline void drgn_recursion_guard_cleanup(int **guard)
__attribute__((__cleanup__(drgn_recursion_guard_cleanup), __unused__)) \
int *PP_UNIQUE(recursion_count_ptr) = &unique_recursion_count

/**
* Catch a certain kind of @ref drgn_error and free it
*
* If @a errp points to a non-@c NULL error whose code matches @a code, then the
* free the error (if necessary), replace the pointer value with @c NULL, and
* return @c true. Otherwise, return @c false, and @a err is not modified.
*/
static inline bool drgn_error_catch(struct drgn_error **errp,
enum drgn_error_code code)
{
if (*errp && (*errp)->code == code) {
drgn_error_destroy(*errp);
*errp = NULL;
return true;
}
return false;
}

/** @} */

#endif /* DRGN_ERROR_H */
29 changes: 9 additions & 20 deletions libdrgn/linux_kernel_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@ struct drgn_error *linux_helper_direct_mapping_offset(struct drgn_program *prog,
uint64_t virt_addr;
if (!err) {
err = drgn_object_read_unsigned(&tmp, &virt_addr);
} else if (err->code == DRGN_ERROR_LOOKUP) {
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
// Avoid a confusing error message with our arbitrary variable
// name.
drgn_error_destroy(err);
err = drgn_error_create(DRGN_ERROR_OTHER,
"could not find variable in direct mapping");
}
Expand Down Expand Up @@ -248,8 +247,7 @@ struct drgn_error *linux_helper_per_cpu_ptr(struct drgn_object *res,
drgn_object_qualified_type(ptr),
ptr_value + per_cpu_offset.uvalue,
0);
} else if (err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err);
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
return drgn_object_copy(res, ptr);
} else {
return err;
Expand Down Expand Up @@ -299,9 +297,8 @@ struct drgn_error *linux_helper_task_thread_info(struct drgn_object *res,
if (!err) {
// CONFIG_THREAD_INFO_IN_TASK=y
return drgn_object_address_of(res, &tmp);
} else if (err->code == DRGN_ERROR_LOOKUP) {
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
// CONFIG_THREAD_INFO_IN_TASK=n
drgn_error_destroy(err);
err = drgn_object_member_dereference(&tmp, task, "stack");
if (err)
return err;
Expand Down Expand Up @@ -340,20 +337,17 @@ struct drgn_error *linux_helper_task_cpu(const struct drgn_object *task,
if (err)
return err;
err = drgn_object_member_dereference(&tmp, &tmp, "cpu");
if (err && err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err);
if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
err = drgn_object_member_dereference(&tmp, task, "cpu");
}
if (!err) {
union drgn_value value;
err = drgn_object_read_integer(&tmp, &value);
if (!err)
*ret = value.uvalue;
} else if (err->code == DRGN_ERROR_LOOKUP) {
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
// CONFIG_SMP=n
drgn_error_destroy(err);
*ret = 0;
err = NULL;
}
return err;
}
Expand Down Expand Up @@ -387,8 +381,7 @@ linux_helper_xa_load(struct drgn_object *res,
return err;
internal_flag = 2;
node_min = 4097;
} else if (err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err);
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
// entry = (void *)xa->rnode
err = drgn_object_member_dereference(&entry, xa, "rnode");
if (err)
Expand Down Expand Up @@ -587,10 +580,8 @@ struct drgn_error *linux_helper_idr_find(struct drgn_object *res,
if (err)
return err;
id -= idr_base.uvalue;
} else if (err->code == DRGN_ERROR_LOOKUP) {
} else if (!drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
/* idr_base was added in v4.16. */
drgn_error_destroy(err);
} else {
return err;
}

Expand Down Expand Up @@ -787,8 +778,7 @@ struct drgn_error *linux_helper_find_pid(struct drgn_object *res,
if (err)
return err;
return drgn_object_cast(res, qualified_type, &tmp);
} else if (err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err);
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
err = drgn_program_find_object(drgn_object_program(res),
"pid_hash", NULL,
DRGN_FIND_OBJECT_ANY, &tmp);
Expand Down Expand Up @@ -851,8 +841,7 @@ struct drgn_error *linux_helper_pid_task(struct drgn_object *res,
+ 1];
snprintf(member, sizeof(member), PID_LINKS_FORMAT, pid_type);
err = drgn_object_container_of(res, &first, task_struct_type, member);
if (err && err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err);
if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
/* container_of(first, struct task_struct, pids[pid_type].node) */
snprintf(member, sizeof(member), PIDS_NODE_FORMAT, pid_type);
#undef PID_LINKS_FORMAT
Expand Down
2 changes: 2 additions & 0 deletions libdrgn/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ struct drgn_program {
bool arm_lpae;
/** Whether `CRASHTIME` was in the VMCOREINFO. */
bool have_crashtime;
/** Whether `phys_base` was in the VMCOREINFO. */
bool have_phys_base;
/**
* `PAGE_SHIFT` of the kernel (derived from
* `PAGE_SIZE`).
Expand Down
2 changes: 1 addition & 1 deletion scripts/build_manylinux_in_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fi

# Install a recent version of elfutils instead of whatever is in the manylinux
# image.
elfutils_version=0.191
elfutils_version=0.192
elfutils_url=https://sourceware.org/elfutils/ftp/$elfutils_version/elfutils-$elfutils_version.tar.bz2
mkdir /tmp/elfutils
cd /tmp/elfutils
Expand Down
23 changes: 16 additions & 7 deletions tests/linux_kernel/helpers/test_kallsyms.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,24 @@ def compare_local_symbols(self, finder, modules=False):


class TestProcKallsyms(TestCase):
def test_local_proc_kallsyms(self):
finder = _load_proc_kallsyms()
compare_local_symbols(self, finder)
def test_static_data(self):
with tempfile.NamedTemporaryFile() as f:
f.write(KALLSYMS_DATA)
f.flush()
finder = _load_proc_kallsyms(filename=f.name)

def test_local_proc_kallsyms_with_modules(self):
finder = _load_proc_kallsyms(modules=True)
compare_local_symbols(self, finder, modules=True)
syms = finder(None, None, None, False)
expected = [
Symbol("null", 0x0, 8, SymbolBinding.UNIQUE, SymbolKind.UNKNOWN),
Symbol("local_data", 0x8, 8, SymbolBinding.UNKNOWN, SymbolKind.OBJECT),
Symbol("global_bss", 0x10, 16, SymbolBinding.GLOBAL, SymbolKind.OBJECT),
Symbol("weak_symbol", 0x20, 32, SymbolBinding.WEAK, SymbolKind.OBJECT),
# this one has zero size since it is at the end of vmlinux
Symbol("unknown", 0x40, 0, SymbolBinding.UNKNOWN, SymbolKind.UNKNOWN),
]
self.assertEqual(syms, expected)

def test_static_data(self):
def test_static_data_with_modules(self):
with tempfile.NamedTemporaryFile() as f:
f.write(KALLSYMS_DATA)
f.flush()
Expand Down

0 comments on commit e5710bc

Please sign in to comment.