mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 01:33:06 +00:00
libdrgn: get module section address from sysfs when possible
In the running kernel, we don't have to walk the list of modules and module sections, since we can just look it up directly in sysfs.
This commit is contained in:
parent
f11e030aaa
commit
ed6a6f0b3e
@ -280,6 +280,10 @@ Programs
|
||||
|
||||
The program is the Linux kernel.
|
||||
|
||||
.. attribute:: IS_RUNNING_KERNEL
|
||||
|
||||
The program is the running operating system kernel.
|
||||
|
||||
.. class:: Architecture
|
||||
|
||||
``Architecture`` is an :class:`enum.Flag` of flags describing the target
|
||||
|
@ -856,6 +856,8 @@ struct drgn_program;
|
||||
enum drgn_program_flags {
|
||||
/** The program is the Linux kernel. */
|
||||
DRGN_PROGRAM_IS_LINUX_KERNEL = (1 << 0),
|
||||
/** The program is the running operating system kernel. */
|
||||
DRGN_PROGRAM_IS_RUNNING_KERNEL = (1 << 1),
|
||||
};
|
||||
|
||||
/** Target architecture of a @ref drgn_program. */
|
||||
|
@ -1,11 +1,13 @@
|
||||
// Copyright 2018-2019 - Omar Sandoval
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "kmod.h"
|
||||
#include "program.h"
|
||||
|
||||
struct drgn_error *
|
||||
kernel_module_iterator_init(struct kernel_module_iterator *it,
|
||||
@ -88,6 +90,43 @@ kernel_module_iterator_next(struct kernel_module_iterator *it)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
kernel_module_section_address_from_sysfs(struct drgn_program *prog,
|
||||
const char *module_name,
|
||||
const char *section_name,
|
||||
uint64_t *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
FILE *file;
|
||||
char *path;
|
||||
|
||||
if (asprintf(&path, "/sys/module/%s/sections/%s", module_name,
|
||||
section_name) == -1) {
|
||||
return &drgn_enomem;
|
||||
}
|
||||
file = fopen(path, "r");
|
||||
if (!file) {
|
||||
if (errno == ENOENT) {
|
||||
err = drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"%s is not loaded",
|
||||
module_name);
|
||||
} else {
|
||||
err = drgn_error_create_os(errno, path, "fopen");
|
||||
}
|
||||
goto out_path;
|
||||
}
|
||||
if (fscanf(file, "%" SCNx64, ret) != 1) {
|
||||
err = drgn_error_format(DRGN_ERROR_OTHER, "could not parse %s",
|
||||
path);
|
||||
} else {
|
||||
err = NULL;
|
||||
}
|
||||
fclose(file);
|
||||
out_path:
|
||||
free(path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct drgn_error *find_section_address(struct drgn_object *mod,
|
||||
const char *section_name,
|
||||
uint64_t *ret)
|
||||
@ -156,6 +195,17 @@ struct drgn_error *kernel_module_section_address(struct drgn_program *prog,
|
||||
struct drgn_error *err;
|
||||
struct kernel_module_iterator it;
|
||||
|
||||
/*
|
||||
* For the running kernel, we can take a shortcut by looking at sysfs.
|
||||
* Otherwise, we have to walk the list of modules in the kernel.
|
||||
*/
|
||||
if (prog->flags & DRGN_PROGRAM_IS_RUNNING_KERNEL) {
|
||||
return kernel_module_section_address_from_sysfs(prog,
|
||||
module_name,
|
||||
section_name,
|
||||
ret);
|
||||
}
|
||||
|
||||
err = kernel_module_iterator_init(&it, prog);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -627,7 +627,7 @@ drgn_program_set_core_dump(struct drgn_program *prog, const char *path)
|
||||
size_t phnum, i, mappings_capacity = 0;
|
||||
bool have_non_zero_phys_addr = false;
|
||||
struct drgn_memory_file_segment *current_file_segment;
|
||||
bool have_nt_taskstruct = false, have_vmcoreinfo = false;
|
||||
bool have_nt_taskstruct = false, have_vmcoreinfo = false, is_proc_kcore;
|
||||
|
||||
err = drgn_program_check_initialized(prog);
|
||||
if (err)
|
||||
@ -785,20 +785,10 @@ drgn_program_set_core_dump(struct drgn_program *prog, const char *path)
|
||||
resize_array(&prog->mappings, prog->num_mappings);
|
||||
}
|
||||
|
||||
if (have_nt_taskstruct && !have_vmcoreinfo) {
|
||||
if (have_nt_taskstruct) {
|
||||
/*
|
||||
* Before Linux kernel commit 23c85094fe18 ("proc/kcore: add
|
||||
* vmcoreinfo note to /proc/kcore") (in v4.19), /proc/kcore
|
||||
* didn't have a VMCOREINFO note. However, it has always had an
|
||||
* NT_TASKSTRUCT note. If this is a file in /proc with the
|
||||
* NT_TASKSTRUCT note, then it's probably /proc/kcore, and we
|
||||
* need to try to get vmcoreinfo elsewhere.
|
||||
*
|
||||
* Since Linux kernel commit 464920104bf7 ("/proc/kcore: update
|
||||
* physical address for kcore ram and text") (in v4.11), we can
|
||||
* read from the physical address of vmcoreinfo exported in
|
||||
* sysfs. Before that, p_paddr in /proc/kcore is always zero, so
|
||||
* we have to use a hackier fallback.
|
||||
* If the core file has an NT_TASKSTRUCT note and is in /proc,
|
||||
* then it's probably /proc/kcore.
|
||||
*/
|
||||
struct statfs fs;
|
||||
|
||||
@ -807,7 +797,22 @@ drgn_program_set_core_dump(struct drgn_program *prog, const char *path)
|
||||
if (err)
|
||||
goto out_mappings;
|
||||
}
|
||||
if (fs.f_type == 0x9fa0 /* PROC_SUPER_MAGIC */) {
|
||||
is_proc_kcore = fs.f_type == 0x9fa0; /* PROC_SUPER_MAGIC */
|
||||
} else {
|
||||
is_proc_kcore = false;
|
||||
}
|
||||
|
||||
if (!have_vmcoreinfo && is_proc_kcore) {
|
||||
/*
|
||||
* Before Linux kernel commit 23c85094fe18 ("proc/kcore: add
|
||||
* vmcoreinfo note to /proc/kcore") (in v4.19), /proc/kcore
|
||||
* didn't have a VMCOREINFO note. Since Linux kernel commit
|
||||
* 464920104bf7 ("/proc/kcore: update physical address for kcore
|
||||
* ram and text") (in v4.11), we can read from the physical
|
||||
* address of vmcoreinfo exported in sysfs. Before that, p_paddr
|
||||
* in /proc/kcore is always zero, so we have to use a hackier
|
||||
* fallback.
|
||||
*/
|
||||
if (have_non_zero_phys_addr) {
|
||||
err = read_vmcoreinfo_from_sysfs(&prog->reader,
|
||||
&prog->vmcoreinfo);
|
||||
@ -818,10 +823,11 @@ drgn_program_set_core_dump(struct drgn_program *prog, const char *path)
|
||||
goto out_mappings;
|
||||
have_vmcoreinfo = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_vmcoreinfo)
|
||||
prog->flags |= DRGN_PROGRAM_IS_LINUX_KERNEL;
|
||||
if (is_proc_kcore)
|
||||
prog->flags |= DRGN_PROGRAM_IS_RUNNING_KERNEL;
|
||||
drgn_program_update_arch(prog, arch);
|
||||
return NULL;
|
||||
|
||||
|
@ -62,12 +62,6 @@ struct file_mapping {
|
||||
uint64_t file_offset;
|
||||
};
|
||||
|
||||
struct drgn_cleanup {
|
||||
void (*cb)(void *);
|
||||
void *arg;
|
||||
struct drgn_cleanup *next;
|
||||
};
|
||||
|
||||
struct drgn_dwarf_info_cache;
|
||||
|
||||
struct drgn_program {
|
||||
|
Loading…
Reference in New Issue
Block a user