libdrgn: add THREAD_SIZE to Linux kernel object finder

Despite the naming, this is the kernel stack size.
This commit is contained in:
Omar Sandoval 2020-05-19 17:09:00 -07:00
parent 971a2d3687
commit 4d8597f0f8
3 changed files with 59 additions and 0 deletions

View File

@ -234,6 +234,33 @@ out:
return err;
}
static struct drgn_error *
linux_kernel_get_thread_size(struct drgn_program *prog, uint64_t *ret)
{
struct drgn_error *err;
struct drgn_qualified_type thread_union_type;
struct drgn_member_info stack_member;
if (!prog->thread_size) {
err = drgn_program_find_type(prog, "union thread_union", NULL,
&thread_union_type);
if (err)
return err;
err = drgn_program_member_info(prog, thread_union_type.type,
"stack", &stack_member);
if (err)
return err;
err = drgn_type_sizeof(stack_member.qualified_type.type,
&prog->thread_size);
if (err) {
prog->thread_size = 0;
return err;
}
}
*ret = prog->thread_size;
return NULL;
}
struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
const char *filename,
enum drgn_find_object_flags flags,
@ -296,6 +323,20 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
return drgn_object_set_unsigned(ret, qualified_type,
~(prog->vmcoreinfo.page_size - 1),
0);
} else if (name_len == strlen("THREAD_SIZE") &&
memcmp(name, "THREAD_SIZE", name_len) == 0) {
uint64_t thread_size;
err = linux_kernel_get_thread_size(prog, &thread_size);
if (err)
return err;
err = drgn_type_index_find_primitive(&prog->tindex,
DRGN_C_TYPE_UNSIGNED_LONG,
&qualified_type.type);
if (err)
return err;
return drgn_object_set_unsigned(ret, qualified_type,
thread_size, 0);
} else if (name_len == strlen("UTS_RELEASE") &&
memcmp(name, "UTS_RELEASE", name_len) == 0) {
size_t len;

View File

@ -74,6 +74,8 @@ struct drgn_program {
uint64_t page_offset;
/* Cached vmemmap. */
uint64_t vmemmap;
/* Cached THREAD_SIZE. */
uint64_t thread_size;
#ifdef WITH_LIBKDUMPFILE
kdump_ctx_t *kdump_ctx;
#endif

View File

@ -15,6 +15,10 @@ from tests.helpers.linux import (
)
def is_power_of_two(n):
return n != 0 and (n & (n - 1)) == 0
class TestSched(LinuxHelperTestCase):
def test_task_state_to_char(self):
task = find_task(self.prog, os.getpid())
@ -35,3 +39,15 @@ class TestSched(LinuxHelperTestCase):
self.assertEqual(task_state_to_char(task), "Z")
os.waitpid(pid, 0)
def test_thread_size(self):
# As far as I can tell, there's no way to query this value from
# userspace, so at least sanity check that it's a power-of-two multiple
# of the page size and that we can read the entire stack.
thread_size = self.prog["THREAD_SIZE"].value_()
page_size = self.prog["PAGE_SIZE"].value_()
self.assertEqual(thread_size % page_size, 0)
self.assertTrue(is_power_of_two(thread_size // page_size))
task = find_task(self.prog, os.getpid())
self.prog.read(task.stack, thread_size)