2020-05-15 23:13:02 +01:00
|
|
|
// Copyright (c) Facebook, Inc. and its affiliates.
|
2021-04-03 09:10:35 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2019-06-04 23:20:03 +01:00
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
#include <dirent.h>
|
2020-09-24 00:02:02 +01:00
|
|
|
#include <elf.h>
|
|
|
|
#include <gelf.h>
|
|
|
|
#include <libelf.h>
|
|
|
|
#include <stdio.h>
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
#include <errno.h>
|
2019-06-04 23:20:03 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
#include "binary_buffer.h"
|
2020-10-10 01:17:10 +01:00
|
|
|
#include "bitops.h"
|
2020-09-16 01:42:53 +01:00
|
|
|
#include "debug_info.h"
|
2020-09-24 00:02:02 +01:00
|
|
|
#include "drgn.h"
|
|
|
|
#include "error.h"
|
|
|
|
#include "hash_table.h"
|
2020-05-06 08:35:29 +01:00
|
|
|
#include "helpers.h"
|
2020-09-24 00:02:02 +01:00
|
|
|
#include "language.h"
|
2019-06-04 23:20:03 +01:00
|
|
|
#include "linux_kernel.h"
|
2020-09-24 00:02:02 +01:00
|
|
|
#include "memory_reader.h"
|
|
|
|
#include "platform.h"
|
2019-06-04 23:20:03 +01:00
|
|
|
#include "program.h"
|
2020-09-24 00:02:02 +01:00
|
|
|
#include "type.h"
|
|
|
|
#include "util.h"
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-05-06 08:35:29 +01:00
|
|
|
struct drgn_error *read_memory_via_pgtable(void *buf, uint64_t address,
|
|
|
|
size_t count, uint64_t offset,
|
|
|
|
void *arg, bool physical)
|
|
|
|
{
|
|
|
|
struct drgn_program *prog = arg;
|
|
|
|
return linux_helper_read_vm(prog, prog->vmcoreinfo.swapper_pg_dir,
|
|
|
|
address, buf, count);
|
|
|
|
}
|
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
static inline bool linematch(const char **line, const char *prefix)
|
|
|
|
{
|
|
|
|
size_t len = strlen(prefix);
|
|
|
|
|
|
|
|
if (strncmp(*line, prefix, len) == 0) {
|
|
|
|
*line += len;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *line_to_u64(const char *line, const char *newline,
|
|
|
|
int base, uint64_t *ret)
|
|
|
|
{
|
|
|
|
unsigned long long value;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
value = strtoull(line, &end, base);
|
|
|
|
if (errno == ERANGE) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OVERFLOW,
|
|
|
|
"number in VMCOREINFO is too large");
|
|
|
|
} else if (errno || end == line || end != newline) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OVERFLOW,
|
|
|
|
"number in VMCOREINFO is invalid");
|
|
|
|
}
|
|
|
|
*ret = value;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct drgn_error *parse_vmcoreinfo(const char *desc, size_t descsz,
|
|
|
|
struct vmcoreinfo *ret)
|
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
const char *line = desc, *end = &desc[descsz];
|
|
|
|
|
|
|
|
ret->osrelease[0] = '\0';
|
|
|
|
ret->page_size = 0;
|
|
|
|
ret->kaslr_offset = 0;
|
2020-04-09 22:29:47 +01:00
|
|
|
ret->pgtable_l5_enabled = false;
|
2019-06-04 23:20:03 +01:00
|
|
|
while (line < end) {
|
|
|
|
const char *newline;
|
|
|
|
|
|
|
|
newline = memchr(line, '\n', end - line);
|
|
|
|
if (!newline)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (linematch(&line, "OSRELEASE=")) {
|
|
|
|
if ((size_t)(newline - line) >=
|
|
|
|
sizeof(ret->osrelease)) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"OSRELEASE in VMCOREINFO is too long");
|
|
|
|
}
|
|
|
|
memcpy(ret->osrelease, line, newline - line);
|
|
|
|
ret->osrelease[newline - line] = '\0';
|
|
|
|
} else if (linematch(&line, "PAGESIZE=")) {
|
|
|
|
err = line_to_u64(line, newline, 0, &ret->page_size);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
} else if (linematch(&line, "KERNELOFFSET=")) {
|
|
|
|
err = line_to_u64(line, newline, 16,
|
|
|
|
&ret->kaslr_offset);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-05-01 09:00:27 +01:00
|
|
|
} else if (linematch(&line, "SYMBOL(swapper_pg_dir)=")) {
|
|
|
|
err = line_to_u64(line, newline, 16,
|
|
|
|
&ret->swapper_pg_dir);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-04-09 22:29:47 +01:00
|
|
|
} else if (linematch(&line, "NUMBER(pgtable_l5_enabled)=")) {
|
|
|
|
uint64_t tmp;
|
|
|
|
|
|
|
|
err = line_to_u64(line, newline, 0, &tmp);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
ret->pgtable_l5_enabled = tmp;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
line = newline + 1;
|
|
|
|
}
|
|
|
|
if (!ret->osrelease[0]) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"VMCOREINFO does not contain valid OSRELEASE");
|
|
|
|
}
|
|
|
|
if (!ret->page_size) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"VMCOREINFO does not contain valid PAGESIZE");
|
|
|
|
}
|
2020-05-01 09:00:27 +01:00
|
|
|
if (!ret->swapper_pg_dir) {
|
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"VMCOREINFO does not contain valid swapper_pg_dir");
|
|
|
|
}
|
2020-04-09 22:29:47 +01:00
|
|
|
/* KERNELOFFSET and pgtable_l5_enabled are optional. */
|
2019-06-04 23:20:03 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-04 08:44:44 +01:00
|
|
|
struct drgn_error *proc_kallsyms_symbol_addr(const char *name,
|
|
|
|
unsigned long *ret)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
FILE *file;
|
|
|
|
char *line = NULL;
|
|
|
|
size_t n = 0;
|
|
|
|
|
|
|
|
file = fopen("/proc/kallsyms", "r");
|
|
|
|
if (!file)
|
2019-07-11 23:58:23 +01:00
|
|
|
return drgn_error_create_os("fopen", errno, "/proc/kallsyms");
|
2019-06-04 23:20:03 +01:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
char *addr_str, *sym_str, *saveptr, *end;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
if (getline(&line, &n, file) == -1) {
|
|
|
|
if (errno) {
|
2019-07-11 23:58:23 +01:00
|
|
|
err = drgn_error_create_os("getline", errno,
|
|
|
|
"/proc/kallsyms");
|
2019-06-04 23:20:03 +01:00
|
|
|
} else {
|
2020-05-04 08:44:44 +01:00
|
|
|
err = &drgn_not_found;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr_str = strtok_r(line, "\t ", &saveptr);
|
|
|
|
if (!addr_str || !*addr_str)
|
|
|
|
goto invalid;
|
|
|
|
if (!strtok_r(NULL, "\t ", &saveptr))
|
|
|
|
goto invalid;
|
|
|
|
sym_str = strtok_r(NULL, "\t\n ", &saveptr);
|
|
|
|
if (!sym_str)
|
|
|
|
goto invalid;
|
|
|
|
|
|
|
|
if (strcmp(sym_str, name) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
*ret = strtoul(line, &end, 16);
|
|
|
|
if (errno || *end) {
|
|
|
|
invalid:
|
|
|
|
err = drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"could not parse /proc/kallsyms");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
err = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
fclose(file);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before Linux kernel commit 23c85094fe18 ("proc/kcore: add vmcoreinfo note to
|
2020-05-04 08:44:44 +01:00
|
|
|
* /proc/kcore") (in v4.19), /proc/kcore didn't have a VMCOREINFO note. Instead,
|
2019-06-04 23:20:03 +01:00
|
|
|
* we can read from the physical address of the vmcoreinfo note exported in
|
2020-05-04 08:44:44 +01:00
|
|
|
* sysfs.
|
2019-06-04 23:20:03 +01:00
|
|
|
*/
|
|
|
|
struct drgn_error *read_vmcoreinfo_fallback(struct drgn_memory_reader *reader,
|
|
|
|
struct vmcoreinfo *ret)
|
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
FILE *file;
|
2020-05-04 18:23:32 +01:00
|
|
|
uint64_t address;
|
2019-06-04 23:20:03 +01:00
|
|
|
size_t size;
|
|
|
|
char *buf;
|
|
|
|
Elf64_Nhdr *nhdr;
|
|
|
|
|
|
|
|
file = fopen("/sys/kernel/vmcoreinfo", "r");
|
|
|
|
if (!file) {
|
2019-07-11 23:58:23 +01:00
|
|
|
return drgn_error_create_os("fopen", errno,
|
|
|
|
"/sys/kernel/vmcoreinfo");
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
2020-05-04 18:23:32 +01:00
|
|
|
if (fscanf(file, "%" SCNx64 "%zx", &address, &size) != 2) {
|
2019-06-04 23:20:03 +01:00
|
|
|
fclose(file);
|
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"could not parse /sys/kernel/vmcoreinfo");
|
|
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
buf = malloc(size);
|
|
|
|
if (!buf)
|
|
|
|
return &drgn_enomem;
|
|
|
|
|
2020-05-04 08:44:44 +01:00
|
|
|
err = drgn_memory_reader_read(reader, buf, address, size, true);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The first 12 bytes are the Elf{32,64}_Nhdr (it's the same in both
|
|
|
|
* formats). The name is padded up to 4 bytes, so the descriptor starts
|
|
|
|
* at byte 24.
|
|
|
|
*/
|
|
|
|
nhdr = (Elf64_Nhdr *)buf;
|
|
|
|
if (size < 24 || nhdr->n_namesz != 11 ||
|
|
|
|
memcmp(buf + sizeof(*nhdr), "VMCOREINFO", 10) != 0 ||
|
|
|
|
nhdr->n_descsz > size - 24) {
|
|
|
|
err = drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"VMCOREINFO is invalid");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = parse_vmcoreinfo(buf + 24, nhdr->n_descsz, ret);
|
|
|
|
out:
|
|
|
|
free(buf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-04-09 22:59:42 +01:00
|
|
|
struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
|
|
|
const char *filename,
|
|
|
|
enum drgn_find_object_flags flags,
|
|
|
|
void *arg, struct drgn_object *ret)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
struct drgn_program *prog = arg;
|
|
|
|
|
2019-07-24 00:26:29 +01:00
|
|
|
if (!filename && (flags & DRGN_FIND_OBJECT_CONSTANT)) {
|
|
|
|
struct drgn_qualified_type qualified_type = {};
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2020-04-09 22:59:42 +01:00
|
|
|
if (name_len == strlen("PAGE_OFFSET") &&
|
|
|
|
memcmp(name, "PAGE_OFFSET", name_len) == 0) {
|
2020-12-29 22:41:01 +00:00
|
|
|
if (prog->page_offset.kind == DRGN_OBJECT_ABSENT) {
|
2020-04-09 22:59:42 +01:00
|
|
|
if (!prog->has_platform ||
|
|
|
|
!prog->platform.arch->linux_kernel_get_page_offset)
|
|
|
|
return &drgn_not_found;
|
2020-12-10 10:40:07 +00:00
|
|
|
err = prog->platform.arch->linux_kernel_get_page_offset(&prog->page_offset);
|
|
|
|
if (err)
|
2020-04-09 22:59:42 +01:00
|
|
|
return err;
|
|
|
|
}
|
2020-12-10 10:40:07 +00:00
|
|
|
return drgn_object_copy(ret, &prog->page_offset);
|
2020-04-09 22:59:42 +01:00
|
|
|
} else if (name_len == strlen("PAGE_SHIFT") &&
|
|
|
|
memcmp(name, "PAGE_SHIFT", name_len) == 0) {
|
2020-04-23 00:23:26 +01:00
|
|
|
err = drgn_program_find_primitive_type(prog,
|
|
|
|
DRGN_C_TYPE_INT,
|
|
|
|
&qualified_type.type);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2019-07-24 00:26:29 +01:00
|
|
|
return drgn_object_set_signed(ret, qualified_type,
|
|
|
|
ctz(prog->vmcoreinfo.page_size),
|
|
|
|
0);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
} else if (name_len == strlen("PAGE_SIZE") &&
|
|
|
|
memcmp(name, "PAGE_SIZE", name_len) == 0) {
|
2020-04-23 00:23:26 +01:00
|
|
|
err = drgn_program_find_primitive_type(prog,
|
|
|
|
DRGN_C_TYPE_UNSIGNED_LONG,
|
|
|
|
&qualified_type.type);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2019-07-24 00:26:29 +01:00
|
|
|
return drgn_object_set_unsigned(ret, qualified_type,
|
|
|
|
prog->vmcoreinfo.page_size,
|
|
|
|
0);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
} else if (name_len == strlen("PAGE_MASK") &&
|
|
|
|
memcmp(name, "PAGE_MASK", name_len) == 0) {
|
2020-04-23 00:23:26 +01:00
|
|
|
err = drgn_program_find_primitive_type(prog,
|
|
|
|
DRGN_C_TYPE_UNSIGNED_LONG,
|
|
|
|
&qualified_type.type);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2019-07-24 00:26:29 +01:00
|
|
|
return drgn_object_set_unsigned(ret, qualified_type,
|
|
|
|
~(prog->vmcoreinfo.page_size - 1),
|
|
|
|
0);
|
2020-02-19 19:35:52 +00:00
|
|
|
} else if (name_len == strlen("UTS_RELEASE") &&
|
|
|
|
memcmp(name, "UTS_RELEASE", name_len) == 0) {
|
|
|
|
size_t len;
|
|
|
|
|
2020-04-23 00:23:26 +01:00
|
|
|
err = drgn_program_find_primitive_type(prog,
|
|
|
|
DRGN_C_TYPE_CHAR,
|
|
|
|
&qualified_type.type);
|
2020-02-19 19:35:52 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
qualified_type.qualifiers = DRGN_QUALIFIER_CONST;
|
|
|
|
len = strlen(prog->vmcoreinfo.osrelease);
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
err = drgn_array_type_create(prog, qualified_type,
|
|
|
|
len + 1, &drgn_language_c,
|
|
|
|
&qualified_type.type);
|
2020-02-19 19:35:52 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
qualified_type.qualifiers = 0;
|
2020-12-11 19:18:54 +00:00
|
|
|
return drgn_object_set_from_buffer(ret, qualified_type,
|
|
|
|
prog->vmcoreinfo.osrelease,
|
Track byte order in scalar types instead of objects
Currently, reference objects and buffer value objects have a byte order.
However, this doesn't always make sense for a couple of reasons:
- Byte order is only meaningful for scalars. What does it mean for a
struct to be big endian? A struct doesn't have a most or least
significant byte; its scalar members do.
- The DWARF specification allows either types or variables to have a
byte order (DW_AT_endianity). The only producer I could find that uses
this is GCC for the scalar_storage_order type attribute, and it only
uses it for base types, not variables. GDB only seems to use to check
it for base types, as well.
So, remove the byte order from objects, and move it to integer, boolean,
floating-point, and pointer types. This model makes more sense, and it
means that we can get the binary representation of any object now.
The only downside is that we can no longer support a bit offset for
non-scalars, but as far as I can tell, nothing needs that.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-18 00:13:23 +00:00
|
|
|
len + 1, 0, 0);
|
2020-04-09 23:37:46 +01:00
|
|
|
} else if (name_len == strlen("vmemmap") &&
|
|
|
|
memcmp(name, "vmemmap", name_len) == 0) {
|
2020-12-29 22:41:01 +00:00
|
|
|
if (prog->vmemmap.kind == DRGN_OBJECT_ABSENT) {
|
2020-04-09 23:37:46 +01:00
|
|
|
if (!prog->has_platform ||
|
|
|
|
!prog->platform.arch->linux_kernel_get_vmemmap)
|
|
|
|
return &drgn_not_found;
|
2020-12-10 10:40:07 +00:00
|
|
|
err = prog->platform.arch->linux_kernel_get_vmemmap(&prog->vmemmap);
|
|
|
|
if (err)
|
2020-04-09 23:37:46 +01:00
|
|
|
return err;
|
|
|
|
}
|
2020-12-10 10:40:07 +00:00
|
|
|
return drgn_object_copy(ret, &prog->vmemmap);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
}
|
2019-07-24 00:26:29 +01:00
|
|
|
return &drgn_not_found;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
struct kernel_module_iterator {
|
|
|
|
char *name;
|
2020-10-13 07:22:01 +01:00
|
|
|
/* /proc/modules file or NULL. */
|
|
|
|
FILE *modules_file;
|
2019-06-04 23:20:03 +01:00
|
|
|
union {
|
2020-10-13 07:22:01 +01:00
|
|
|
/* If using /proc/modules. */
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct {
|
|
|
|
size_t name_capacity;
|
|
|
|
uint64_t start, end;
|
|
|
|
};
|
2020-10-13 07:22:01 +01:00
|
|
|
/* If not using /proc/modules. */
|
2019-06-04 23:20:03 +01:00
|
|
|
struct {
|
|
|
|
struct drgn_qualified_type module_type;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct drgn_object mod, node, tmp1, tmp2, tmp3;
|
2019-06-04 23:20:03 +01:00
|
|
|
uint64_t head;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
static void kernel_module_iterator_deinit(struct kernel_module_iterator *it)
|
|
|
|
{
|
2020-10-13 07:22:01 +01:00
|
|
|
if (it->modules_file) {
|
|
|
|
fclose(it->modules_file);
|
2019-06-04 23:20:03 +01:00
|
|
|
} else {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
drgn_object_deinit(&it->tmp3);
|
|
|
|
drgn_object_deinit(&it->tmp2);
|
|
|
|
drgn_object_deinit(&it->tmp1);
|
2019-06-04 23:20:03 +01:00
|
|
|
drgn_object_deinit(&it->node);
|
|
|
|
drgn_object_deinit(&it->mod);
|
|
|
|
}
|
|
|
|
free(it->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
kernel_module_iterator_init(struct kernel_module_iterator *it,
|
2020-10-13 19:24:39 +01:00
|
|
|
struct drgn_program *prog, bool use_proc_and_sys)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
|
|
|
|
it->name = NULL;
|
2020-10-13 19:24:39 +01:00
|
|
|
if (use_proc_and_sys) {
|
2020-10-13 07:22:01 +01:00
|
|
|
it->modules_file = fopen("/proc/modules", "r");
|
|
|
|
if (!it->modules_file) {
|
2019-07-11 23:58:23 +01:00
|
|
|
return drgn_error_create_os("fopen", errno,
|
|
|
|
"/proc/modules");
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
it->name_capacity = 0;
|
|
|
|
} else {
|
2020-10-13 07:22:01 +01:00
|
|
|
it->modules_file = NULL;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
|
|
|
err = drgn_program_find_type(prog, "struct module", NULL,
|
|
|
|
&it->module_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
drgn_object_init(&it->mod, prog);
|
|
|
|
drgn_object_init(&it->node, prog);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
drgn_object_init(&it->tmp1, prog);
|
|
|
|
drgn_object_init(&it->tmp2, prog);
|
|
|
|
drgn_object_init(&it->tmp3, prog);
|
2019-06-04 23:20:03 +01:00
|
|
|
|
|
|
|
err = drgn_program_find_object(prog, "modules", NULL,
|
|
|
|
DRGN_FIND_OBJECT_VARIABLE,
|
|
|
|
&it->node);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
err = drgn_object_address_of(&it->node, &it->node);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
err = drgn_object_read(&it->node, &it->node);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
err = drgn_object_read_unsigned(&it->node, &it->head);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
err:
|
|
|
|
kernel_module_iterator_deinit(it);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
kernel_module_iterator_next_live(struct kernel_module_iterator *it)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
errno = 0;
|
2020-10-13 07:22:01 +01:00
|
|
|
ssize_t ret = getline(&it->name, &it->name_capacity, it->modules_file);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (ret == -1) {
|
|
|
|
if (errno) {
|
2019-07-11 23:58:23 +01:00
|
|
|
return drgn_error_create_os("getline", errno,
|
|
|
|
"/proc/modules");
|
2019-06-04 23:20:03 +01:00
|
|
|
} else {
|
|
|
|
return &drgn_stop;
|
|
|
|
}
|
|
|
|
}
|
2020-10-13 07:22:01 +01:00
|
|
|
char *p = strchr(it->name, ' ');
|
|
|
|
size_t size;
|
|
|
|
if (!p ||
|
|
|
|
sscanf(p + 1, "%zu %*s %*s %*s %" SCNx64, &size, &it->start) != 2) {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
|
|
"could not parse /proc/modules");
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
it->end = it->start + size;
|
2019-06-04 23:20:03 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-13 07:22:01 +01:00
|
|
|
/**
|
|
|
|
* Get the the next loaded kernel module.
|
|
|
|
*
|
|
|
|
* After this is called, @c it->name is set to the name of the kernel module,
|
|
|
|
* and @c it->start and @c it->end are set to the address range of the kernel
|
|
|
|
* module. These are valid until the next time this is called or the iterator is
|
|
|
|
* destroyed.
|
|
|
|
*
|
|
|
|
* @return @c NULL on success, non-@c NULL on error. In particular, when there
|
2021-03-05 20:46:06 +00:00
|
|
|
* are no more modules, returns &@ref drgn_stop.
|
2020-10-13 07:22:01 +01:00
|
|
|
*/
|
2019-06-04 23:20:03 +01:00
|
|
|
static struct drgn_error *
|
2020-10-13 07:22:01 +01:00
|
|
|
kernel_module_iterator_next(struct kernel_module_iterator *it)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2020-10-13 07:22:01 +01:00
|
|
|
if (it->modules_file)
|
|
|
|
return kernel_module_iterator_next_live(it);
|
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
struct drgn_error *err;
|
|
|
|
|
|
|
|
err = drgn_object_member_dereference(&it->node, &it->node, "next");
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
err = drgn_object_read(&it->node, &it->node);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 07:22:01 +01:00
|
|
|
uint64_t addr;
|
2019-06-04 23:20:03 +01:00
|
|
|
err = drgn_object_read_unsigned(&it->node, &addr);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (addr == it->head)
|
|
|
|
return &drgn_stop;
|
|
|
|
|
|
|
|
err = drgn_object_container_of(&it->mod, &it->node, it->module_type,
|
|
|
|
"list");
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = drgn_object_member_dereference(&it->tmp1, &it->mod, "name");
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 07:22:01 +01:00
|
|
|
char *name;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = drgn_object_read_c_string(&it->tmp1, &name);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
free(it->name);
|
|
|
|
it->name = name;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct kernel_module_section_iterator {
|
|
|
|
struct kernel_module_iterator *kmod_it;
|
2020-10-13 07:22:01 +01:00
|
|
|
/* /sys/module/$module/sections directory or NULL. */
|
|
|
|
DIR *sections_dir;
|
|
|
|
/* If not using /sys/module/$module/sections. */
|
|
|
|
uint64_t i;
|
|
|
|
uint64_t nsections;
|
|
|
|
char *name;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct drgn_error *
|
|
|
|
kernel_module_section_iterator_init(struct kernel_module_section_iterator *it,
|
|
|
|
struct kernel_module_iterator *kmod_it)
|
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
|
|
|
|
it->kmod_it = kmod_it;
|
2020-10-13 07:22:01 +01:00
|
|
|
if (kmod_it->modules_file) {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
char *path;
|
|
|
|
if (asprintf(&path, "/sys/module/%s/sections",
|
|
|
|
kmod_it->name) == -1)
|
|
|
|
return &drgn_enomem;
|
2020-10-13 07:22:01 +01:00
|
|
|
it->sections_dir = opendir(path);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
free(path);
|
2020-10-13 07:22:01 +01:00
|
|
|
if (!it->sections_dir) {
|
|
|
|
return drgn_error_format_os("opendir", errno,
|
|
|
|
"/sys/module/%s/sections",
|
|
|
|
kmod_it->name);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} else {
|
2020-10-13 07:22:01 +01:00
|
|
|
it->sections_dir = NULL;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
it->i = 0;
|
|
|
|
it->name = NULL;
|
|
|
|
/* it->nsections = mod->sect_attrs->nsections */
|
|
|
|
err = drgn_object_member_dereference(&kmod_it->tmp1,
|
|
|
|
&kmod_it->mod,
|
|
|
|
"sect_attrs");
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return err;
|
|
|
|
err = drgn_object_member_dereference(&kmod_it->tmp2,
|
|
|
|
&kmod_it->tmp1,
|
|
|
|
"nsections");
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return err;
|
|
|
|
err = drgn_object_read_unsigned(&kmod_it->tmp2,
|
|
|
|
&it->nsections);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return err;
|
|
|
|
/* kmod_it->tmp1 = mod->sect_attrs->attrs */
|
|
|
|
return drgn_object_member_dereference(&kmod_it->tmp1,
|
|
|
|
&kmod_it->tmp1, "attrs");
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-06-04 23:20:03 +01:00
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
static void
|
|
|
|
kernel_module_section_iterator_deinit(struct kernel_module_section_iterator *it)
|
|
|
|
{
|
2020-10-13 07:22:01 +01:00
|
|
|
if (it->sections_dir)
|
|
|
|
closedir(it->sections_dir);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
else
|
|
|
|
free(it->name);
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
kernel_module_section_iterator_next_live(struct kernel_module_section_iterator *it,
|
|
|
|
const char **name_ret,
|
|
|
|
uint64_t *address_ret)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct dirent *ent;
|
2020-10-13 07:22:01 +01:00
|
|
|
while ((errno = 0, ent = readdir(it->sections_dir))) {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (ent->d_type == DT_DIR)
|
|
|
|
continue;
|
|
|
|
if (ent->d_type == DT_UNKNOWN) {
|
|
|
|
struct stat st;
|
|
|
|
|
2020-10-13 07:22:01 +01:00
|
|
|
if (fstatat(dirfd(it->sections_dir), ent->d_name, &st,
|
|
|
|
0) == -1) {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return drgn_error_format_os("fstatat", errno,
|
|
|
|
"/sys/module/%s/sections/%s",
|
|
|
|
it->kmod_it->name,
|
|
|
|
ent->d_name);
|
|
|
|
}
|
|
|
|
if (S_ISDIR(st.st_mode))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-10-13 07:22:01 +01:00
|
|
|
int fd = openat(dirfd(it->sections_dir), ent->d_name, O_RDONLY);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (fd == -1) {
|
|
|
|
return drgn_error_format_os("openat", errno,
|
|
|
|
"/sys/module/%s/sections/%s",
|
|
|
|
it->kmod_it->name,
|
|
|
|
ent->d_name);
|
|
|
|
}
|
2020-10-13 07:22:01 +01:00
|
|
|
FILE *file = fdopen(fd, "r");
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (!file) {
|
|
|
|
close(fd);
|
|
|
|
return drgn_error_create_os("fdopen", errno, NULL);
|
|
|
|
}
|
2020-10-13 07:22:01 +01:00
|
|
|
int ret = fscanf(file, "%" SCNx64, address_ret);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
fclose(file);
|
|
|
|
if (ret != 1) {
|
|
|
|
return drgn_error_format(DRGN_ERROR_OTHER,
|
|
|
|
"could not parse /sys/module/%s/sections/%s",
|
|
|
|
it->kmod_it->name,
|
|
|
|
ent->d_name);
|
|
|
|
}
|
|
|
|
*name_ret = ent->d_name;
|
|
|
|
return NULL;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (errno) {
|
|
|
|
return drgn_error_format_os("readdir", errno,
|
|
|
|
"/sys/module/%s/sections",
|
|
|
|
it->kmod_it->name);
|
|
|
|
} else {
|
|
|
|
return &drgn_stop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
2020-10-13 07:22:01 +01:00
|
|
|
kernel_module_section_iterator_next(struct kernel_module_section_iterator *it,
|
|
|
|
const char **name_ret,
|
|
|
|
uint64_t *address_ret)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
2020-10-13 07:22:01 +01:00
|
|
|
if (it->sections_dir) {
|
|
|
|
return kernel_module_section_iterator_next_live(it, name_ret,
|
|
|
|
address_ret);
|
|
|
|
}
|
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct drgn_error *err;
|
|
|
|
struct kernel_module_iterator *kmod_it = it->kmod_it;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (it->i >= it->nsections)
|
|
|
|
return &drgn_stop;
|
|
|
|
err = drgn_object_subscript(&kmod_it->tmp2, &kmod_it->tmp1, it->i++);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = drgn_object_member(&kmod_it->tmp3, &kmod_it->tmp2, "address");
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
err = drgn_object_read_unsigned(&kmod_it->tmp3, address_ret);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 20:41:24 +01:00
|
|
|
/*
|
|
|
|
* Since Linux kernel commit ed66f991bb19 ("module: Refactor section
|
|
|
|
* attr into bin attribute") (in v5.8), the section name is
|
|
|
|
* module_sect_attr.battr.attr.name. Before that, it is simply
|
|
|
|
* module_sect_attr.name.
|
|
|
|
*/
|
|
|
|
err = drgn_object_member(&kmod_it->tmp2, &kmod_it->tmp2, "battr");
|
|
|
|
if (!err) {
|
|
|
|
err = drgn_object_member(&kmod_it->tmp2, &kmod_it->tmp2,
|
|
|
|
"attr");
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
} else {
|
|
|
|
if (err->code != DRGN_ERROR_LOOKUP)
|
|
|
|
return err;
|
|
|
|
drgn_error_destroy(err);
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = drgn_object_member(&kmod_it->tmp3, &kmod_it->tmp2, "name");
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 07:22:01 +01:00
|
|
|
char *name;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = drgn_object_read_c_string(&kmod_it->tmp3, &name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
free(it->name);
|
|
|
|
*name_ret = it->name = name;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
/*
|
|
|
|
* /lib/modules/$(uname -r)/modules.dep.bin maps all installed kernel modules to
|
|
|
|
* their filesystem path (and dependencies, which we don't care about). It is
|
|
|
|
* generated by depmod; the format is a fairly simple serialized radix tree.
|
|
|
|
*
|
|
|
|
* modules.dep(5) contains a warning: "These files are not intended for editing
|
|
|
|
* or use by any additional utilities as their format is subject to change in
|
|
|
|
* the future." But, the format hasn't changed since 2009, and pulling in
|
|
|
|
* libkmod is overkill since we only need a very small subset of its
|
|
|
|
* functionality (plus our minimal parser is more efficient). If the format
|
|
|
|
* changes in the future, we can reevaluate this.
|
|
|
|
*/
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
struct depmod_index {
|
|
|
|
void *addr;
|
|
|
|
size_t len;
|
|
|
|
char path[256];
|
2019-06-04 23:20:03 +01:00
|
|
|
};
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
static void depmod_index_deinit(struct depmod_index *depmod)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2020-10-29 00:35:09 +00:00
|
|
|
munmap(depmod->addr, depmod->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct depmod_index_buffer {
|
|
|
|
struct binary_buffer bb;
|
|
|
|
struct depmod_index *depmod;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct drgn_error *depmod_index_buffer_error(struct binary_buffer *bb,
|
|
|
|
const char *pos,
|
|
|
|
const char *message)
|
|
|
|
{
|
|
|
|
struct depmod_index_buffer *buffer =
|
|
|
|
container_of(bb, struct depmod_index_buffer, bb);
|
|
|
|
return drgn_error_format(DRGN_ERROR_OTHER, "%s: %#tx: %s",
|
|
|
|
buffer->depmod->path,
|
|
|
|
pos - (const char *)buffer->depmod->addr,
|
|
|
|
message);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void depmod_index_buffer_init(struct depmod_index_buffer *buffer,
|
|
|
|
struct depmod_index *depmod)
|
|
|
|
{
|
|
|
|
binary_buffer_init(&buffer->bb, depmod->addr, depmod->len, false,
|
|
|
|
depmod_index_buffer_error);
|
|
|
|
buffer->depmod = depmod;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *depmod_index_validate(struct depmod_index *depmod)
|
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
struct depmod_index_buffer buffer;
|
|
|
|
depmod_index_buffer_init(&buffer, depmod);
|
|
|
|
uint32_t magic;
|
|
|
|
if ((err = binary_buffer_next_u32(&buffer.bb, &magic)))
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
if (magic != 0xb007f457) {
|
2020-10-29 00:35:09 +00:00
|
|
|
return binary_buffer_error(&buffer.bb,
|
|
|
|
"invalid magic 0x%" PRIx32, magic);
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
2020-10-29 00:35:09 +00:00
|
|
|
uint32_t version;
|
|
|
|
if ((err = binary_buffer_next_u32(&buffer.bb, &version)))
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
if (version != 0x00020001) {
|
2020-10-29 00:35:09 +00:00
|
|
|
return binary_buffer_error(&buffer.bb,
|
|
|
|
"unknown version 0x%" PRIx32,
|
|
|
|
version);
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
static struct drgn_error *depmod_index_init(struct depmod_index *depmod,
|
|
|
|
const char *osrelease)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
snprintf(depmod->path, sizeof(depmod->path),
|
|
|
|
"/lib/modules/%s/modules.dep.bin", osrelease);
|
|
|
|
|
|
|
|
int fd = open(depmod->path, O_RDONLY);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (fd == -1)
|
2020-10-29 00:35:09 +00:00
|
|
|
return drgn_error_create_os("open", errno, depmod->path);
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
struct stat st;
|
2019-06-04 23:20:03 +01:00
|
|
|
if (fstat(fd, &st) == -1) {
|
2020-10-29 00:35:09 +00:00
|
|
|
err = drgn_error_create_os("fstat", errno, depmod->path);
|
2019-06-04 23:20:03 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (st.st_size < 0 || st.st_size > SIZE_MAX) {
|
|
|
|
err = &drgn_enomem;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
void *addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
if (addr == MAP_FAILED) {
|
|
|
|
err = drgn_error_create_os("mmap", errno, depmod->path);
|
2019-06-04 23:20:03 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
depmod->addr = addr;
|
|
|
|
depmod->len = st.st_size;
|
|
|
|
|
|
|
|
err = depmod_index_validate(depmod);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
2020-10-29 00:35:09 +00:00
|
|
|
depmod_index_deinit(depmod);
|
2019-06-04 23:20:03 +01:00
|
|
|
out:
|
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
/*
|
|
|
|
* Look up the path of the kernel module with the given name.
|
|
|
|
*
|
|
|
|
* @param[in] name Name of the kernel module.
|
|
|
|
* @param[out] path_ret Returned path of the kernel module, relative to
|
|
|
|
* /lib/modules/$(uname -r). This is @em not null-terminated. @c NULL if not
|
|
|
|
* found.
|
|
|
|
* @param[out] len_ret Returned length of @p path_ret.
|
|
|
|
*/
|
|
|
|
static struct drgn_error *depmod_index_find(struct depmod_index *depmod,
|
|
|
|
const char *name,
|
|
|
|
const char **path_ret,
|
|
|
|
size_t *len_ret)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2020-06-25 21:53:46 +01:00
|
|
|
static const uint32_t INDEX_NODE_MASK = UINT32_C(0x0fffffff);
|
|
|
|
static const uint32_t INDEX_NODE_CHILDS = UINT32_C(0x20000000);
|
|
|
|
static const uint32_t INDEX_NODE_VALUES = UINT32_C(0x40000000);
|
|
|
|
static const uint32_t INDEX_NODE_PREFIX = UINT32_C(0x80000000);
|
2020-07-07 01:44:39 +01:00
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
struct drgn_error *err;
|
|
|
|
struct depmod_index_buffer buffer;
|
|
|
|
depmod_index_buffer_init(&buffer, depmod);
|
|
|
|
|
|
|
|
/* depmod_index_validate() already checked that this is within bounds. */
|
|
|
|
buffer.bb.pos += 8;
|
2019-06-04 23:20:03 +01:00
|
|
|
uint32_t offset;
|
|
|
|
for (;;) {
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_next_u32(&buffer.bb, &offset)))
|
|
|
|
return err;
|
|
|
|
if ((offset & INDEX_NODE_MASK) > depmod->len) {
|
|
|
|
return binary_buffer_error(&buffer.bb,
|
|
|
|
"offset is out of bounds");
|
|
|
|
}
|
|
|
|
buffer.bb.pos = (const char *)depmod->addr + (offset & INDEX_NODE_MASK);
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-06-25 21:53:46 +01:00
|
|
|
if (offset & INDEX_NODE_PREFIX) {
|
2019-06-04 23:20:03 +01:00
|
|
|
const char *prefix;
|
|
|
|
size_t prefix_len;
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_next_string(&buffer.bb,
|
|
|
|
&prefix,
|
|
|
|
&prefix_len)))
|
|
|
|
return err;
|
|
|
|
if (strncmp(name, prefix, prefix_len) != 0)
|
|
|
|
goto not_found;
|
|
|
|
name += prefix_len;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-06-25 21:53:46 +01:00
|
|
|
if (offset & INDEX_NODE_CHILDS) {
|
2019-06-04 23:20:03 +01:00
|
|
|
uint8_t first, last;
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_next_u8(&buffer.bb, &first)) ||
|
|
|
|
(err = binary_buffer_next_u8(&buffer.bb, &last)))
|
|
|
|
return err;
|
|
|
|
if (*name) {
|
|
|
|
uint8_t cur = *name;
|
|
|
|
if (cur < first || cur > last)
|
|
|
|
goto not_found;
|
|
|
|
if ((err = binary_buffer_skip(&buffer.bb,
|
|
|
|
4 * (cur - first))))
|
|
|
|
return err;
|
|
|
|
name++;
|
2019-06-04 23:20:03 +01:00
|
|
|
continue;
|
|
|
|
} else {
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_skip(&buffer.bb,
|
|
|
|
4 * (last - first + 1))))
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-10-29 00:35:09 +00:00
|
|
|
} else if (*name) {
|
|
|
|
goto not_found;
|
2019-06-04 23:20:03 +01:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-06-25 21:53:46 +01:00
|
|
|
if (!(offset & INDEX_NODE_VALUES))
|
2020-10-29 00:35:09 +00:00
|
|
|
goto not_found;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-07-07 01:44:39 +01:00
|
|
|
uint32_t value_count;
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_next_u32(&buffer.bb, &value_count)))
|
|
|
|
return err;
|
|
|
|
if (!value_count)
|
|
|
|
goto not_found; /* Or is this malformed? */
|
2019-06-04 23:20:03 +01:00
|
|
|
|
|
|
|
/* Skip over priority. */
|
2020-10-29 00:35:09 +00:00
|
|
|
if ((err = binary_buffer_skip(&buffer.bb, 4)))
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
const char *colon = memchr(buffer.bb.pos, ':',
|
|
|
|
buffer.bb.end - buffer.bb.pos);
|
|
|
|
if (!colon) {
|
|
|
|
return binary_buffer_error(&buffer.bb,
|
|
|
|
"expected string containing ':'");
|
|
|
|
}
|
|
|
|
*path_ret = buffer.bb.pos;
|
|
|
|
*len_ret = colon - buffer.bb.pos;
|
|
|
|
return NULL;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-10-29 00:35:09 +00:00
|
|
|
not_found:
|
|
|
|
*path_ret = NULL;
|
|
|
|
return NULL;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
/*
|
2019-09-25 01:13:53 +01:00
|
|
|
* Identify an ELF file as a kernel module, vmlinux, or neither. A kernel module
|
|
|
|
* should have sections named .gnu.linkonce.this_module and .modinfo; we return
|
|
|
|
* those sections and classify the file as a kernel module if either is present.
|
|
|
|
*
|
|
|
|
* If neither is present, and the file has a section named .init.text, we
|
|
|
|
* classify it as vmlinux.
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
*/
|
2019-09-25 01:13:53 +01:00
|
|
|
static struct drgn_error *identify_kernel_elf(Elf *elf,
|
|
|
|
Elf_Scn **this_module_scn_ret,
|
|
|
|
Elf_Scn **modinfo_scn_ret,
|
|
|
|
bool *is_vmlinux_ret)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
size_t shstrndx;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
Elf_Scn *scn;
|
2019-09-25 01:13:53 +01:00
|
|
|
bool have_init_text = false;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (elf_getshdrstrndx(elf, &shstrndx))
|
2019-06-04 23:20:03 +01:00
|
|
|
return drgn_error_libelf();
|
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
scn = *this_module_scn_ret = *modinfo_scn_ret = NULL;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
while ((scn = elf_nextscn(elf, scn))) {
|
|
|
|
GElf_Shdr *shdr, shdr_mem;
|
|
|
|
const char *scnname;
|
|
|
|
|
|
|
|
shdr = gelf_getshdr(scn, &shdr_mem);
|
|
|
|
if (!shdr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
scnname = elf_strptr(elf, shstrndx, shdr->sh_name);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!scnname)
|
2021-03-26 21:28:16 +00:00
|
|
|
return drgn_error_libelf();
|
2019-09-25 01:13:53 +01:00
|
|
|
if (strcmp(scnname, ".gnu.linkonce.this_module") == 0)
|
|
|
|
*this_module_scn_ret = scn;
|
|
|
|
else if (strcmp(scnname, ".modinfo") == 0)
|
|
|
|
*modinfo_scn_ret = scn;
|
|
|
|
else if (strcmp(scnname, ".init.text") == 0)
|
|
|
|
have_init_text = true;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
*is_vmlinux_ret = (!*this_module_scn_ret && !*modinfo_scn_ret &&
|
|
|
|
have_init_text);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
/*
|
|
|
|
* Since Linux kernel commit 3e2e857f9c3a ("module: Add module name to modinfo")
|
|
|
|
* (in v4.13), we can get the module name from .modinfo.
|
|
|
|
*/
|
|
|
|
static struct drgn_error *
|
|
|
|
get_kernel_module_name_from_modinfo(Elf_Scn *modinfo_scn, const char **ret)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
2019-09-25 01:13:53 +01:00
|
|
|
Elf_Data *data;
|
|
|
|
const char *p, *end, *nul;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
if (modinfo_scn) {
|
|
|
|
err = read_elf_section(modinfo_scn, &data);
|
2019-07-17 22:16:38 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2019-09-25 01:13:53 +01:00
|
|
|
p = data->d_buf;
|
|
|
|
end = p + data->d_size;
|
|
|
|
while (p < end) {
|
|
|
|
nul = memchr(p, 0, end - p);
|
|
|
|
if (!nul)
|
|
|
|
break;
|
2019-12-13 23:58:34 +00:00
|
|
|
if (strstartswith(p, "name=")) {
|
2019-09-25 01:13:53 +01:00
|
|
|
*ret = p + 5;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
p = nul + 1;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
*ret = NULL;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
/*
|
|
|
|
* If the module name isn't in .modinfo, we need to get it from
|
|
|
|
* .gnu.linkonce.this_module, which contains a struct module. name_offset is
|
|
|
|
* offsetof(struct module, name).
|
|
|
|
*/
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
static struct drgn_error *
|
2019-09-25 01:13:53 +01:00
|
|
|
get_kernel_module_name_from_this_module(Elf_Scn *this_module_scn,
|
|
|
|
size_t name_offset, const char **ret)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
Elf_Data *data;
|
2019-09-25 01:13:53 +01:00
|
|
|
const char *p, *nul;
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
if (this_module_scn) {
|
|
|
|
err = read_elf_section(this_module_scn, &data);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (name_offset < data->d_size) {
|
|
|
|
p = data->d_buf + name_offset;
|
|
|
|
nul = memchr(p, 0, data->d_size - name_offset);
|
|
|
|
if (nul && nul != p) {
|
|
|
|
*ret = p;
|
|
|
|
return NULL;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*ret = NULL;
|
2019-06-04 23:20:03 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:06:23 +01:00
|
|
|
DEFINE_HASH_MAP(elf_scn_name_map, const char *, Elf_Scn *,
|
|
|
|
c_string_key_hash_pair, c_string_key_eq)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
static struct drgn_error *
|
2019-09-25 01:13:53 +01:00
|
|
|
cache_kernel_module_sections(struct kernel_module_iterator *kmod_it, Elf *elf,
|
|
|
|
uint64_t *start_ret, uint64_t *end_ret)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
size_t shstrndx;
|
2019-09-25 01:13:53 +01:00
|
|
|
if (elf_getshdrstrndx(elf, &shstrndx))
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return drgn_error_libelf();
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
struct elf_scn_name_map scn_map = HASH_TABLE_INIT;
|
|
|
|
Elf_Scn *scn = NULL;
|
2019-09-25 01:13:53 +01:00
|
|
|
while ((scn = elf_nextscn(elf, scn))) {
|
2020-07-01 20:37:16 +01:00
|
|
|
GElf_Shdr shdr_mem;
|
|
|
|
GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (!shdr) {
|
|
|
|
err = drgn_error_libelf();
|
2019-09-25 01:13:53 +01:00
|
|
|
goto out_scn_map;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
|
2019-12-12 21:33:52 +00:00
|
|
|
if (!(shdr->sh_flags & SHF_ALLOC))
|
|
|
|
continue;
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
struct elf_scn_name_map_entry entry = {
|
|
|
|
.key = elf_strptr(elf, shstrndx, shdr->sh_name),
|
|
|
|
.value = scn,
|
|
|
|
};
|
2021-03-26 21:28:16 +00:00
|
|
|
if (!entry.key) {
|
|
|
|
err = drgn_error_libelf();
|
|
|
|
goto out_scn_map;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
|
|
|
if (elf_scn_name_map_insert(&scn_map, &entry, NULL) == -1) {
|
|
|
|
err = &drgn_enomem;
|
2019-09-25 01:13:53 +01:00
|
|
|
goto out_scn_map;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
uint64_t start = UINT64_MAX, end = 0;
|
|
|
|
struct kernel_module_section_iterator section_it;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = kernel_module_section_iterator_init(§ion_it, kmod_it);
|
|
|
|
if (err)
|
2019-09-25 01:13:53 +01:00
|
|
|
goto out_scn_map;
|
2020-07-01 20:37:16 +01:00
|
|
|
const char *name;
|
|
|
|
uint64_t address;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
while (!(err = kernel_module_section_iterator_next(§ion_it, &name,
|
|
|
|
&address))) {
|
2020-07-01 20:37:16 +01:00
|
|
|
struct elf_scn_name_map_iterator it =
|
|
|
|
elf_scn_name_map_search(&scn_map, &name);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (it.entry) {
|
2020-07-01 20:37:16 +01:00
|
|
|
GElf_Shdr shdr_mem;
|
|
|
|
GElf_Shdr *shdr = gelf_getshdr(it.entry->value,
|
|
|
|
&shdr_mem);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (!shdr) {
|
|
|
|
err = drgn_error_libelf();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
shdr->sh_addr = address;
|
|
|
|
if (!gelf_update_shdr(it.entry->value, shdr)) {
|
|
|
|
err = drgn_error_libelf();
|
|
|
|
break;
|
|
|
|
}
|
2021-03-26 21:32:46 +00:00
|
|
|
/*
|
|
|
|
* .init sections are freed once the module is
|
|
|
|
* initialized, but they remain in the section list.
|
|
|
|
* Ignore them for the purpose of determining the
|
|
|
|
* module's address range.
|
|
|
|
*/
|
|
|
|
if (!strstartswith(name, ".init")) {
|
|
|
|
uint64_t section_end;
|
|
|
|
if (__builtin_add_overflow(address,
|
|
|
|
shdr->sh_size,
|
|
|
|
§ion_end))
|
|
|
|
section_end = UINT64_MAX;
|
|
|
|
if (address < section_end) {
|
|
|
|
if (address < start)
|
|
|
|
start = address;
|
|
|
|
if (section_end > end)
|
|
|
|
end = section_end;
|
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
}
|
2021-03-05 20:46:06 +00:00
|
|
|
if (err && err != &drgn_stop)
|
2019-09-25 01:13:53 +01:00
|
|
|
goto out_section_it;
|
|
|
|
err = NULL;
|
|
|
|
if (start >= end)
|
|
|
|
start = end = 0;
|
|
|
|
*start_ret = start;
|
|
|
|
*end_ret = end;
|
|
|
|
out_section_it:
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
kernel_module_section_iterator_deinit(§ion_it);
|
2019-09-25 01:13:53 +01:00
|
|
|
out_scn_map:
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
elf_scn_name_map_deinit(&scn_map);
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
struct kernel_module_file {
|
|
|
|
const char *path;
|
|
|
|
int fd;
|
|
|
|
Elf *elf;
|
|
|
|
/*
|
|
|
|
* Kernel module name. This is owned by the Elf handle. Because we use
|
|
|
|
* this as the key in the kernel_module_table, the file must always be
|
|
|
|
* removed from the table before it is reported to the DWARF index
|
|
|
|
* (which takes ownership of the Elf handle).
|
|
|
|
*/
|
|
|
|
const char *name;
|
|
|
|
Elf_Scn *this_module_scn;
|
|
|
|
/* Next file with the same name. */
|
|
|
|
struct kernel_module_file *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
kernel_module_table_key(struct kernel_module_file * const *entry)
|
|
|
|
{
|
|
|
|
return (*entry)->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_HASH_TABLE(kernel_module_table, struct kernel_module_file *,
|
2020-10-13 00:06:23 +01:00
|
|
|
kernel_module_table_key, c_string_key_hash_pair,
|
|
|
|
c_string_key_eq)
|
2019-09-25 01:13:53 +01:00
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
static struct drgn_error *
|
2020-09-16 01:42:53 +01:00
|
|
|
report_loaded_kernel_module(struct drgn_debug_info_load_state *load,
|
2019-09-25 01:13:53 +01:00
|
|
|
struct kernel_module_iterator *kmod_it,
|
|
|
|
struct kernel_module_table *kmod_table)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
|
|
|
struct drgn_error *err;
|
2019-09-25 01:13:53 +01:00
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
const char *name = kmod_it->name;
|
|
|
|
struct hash_pair hp = kernel_module_table_hash(&name);
|
|
|
|
struct kernel_module_table_iterator it =
|
|
|
|
kernel_module_table_search_hashed(kmod_table, &name, hp);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!it.entry)
|
|
|
|
return &drgn_not_found;
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
struct kernel_module_file *kmod = *it.entry;
|
2019-09-25 01:13:53 +01:00
|
|
|
kernel_module_table_delete_iterator_hashed(kmod_table, it, hp);
|
|
|
|
do {
|
|
|
|
uint64_t start, end;
|
|
|
|
err = cache_kernel_module_sections(kmod_it, kmod->elf, &start,
|
|
|
|
&end);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, kmod->path,
|
|
|
|
"could not get section addresses",
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 20:25:22 +01:00
|
|
|
goto next;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_elf(load, kmod->path, kmod->fd,
|
|
|
|
kmod->elf, start, end,
|
|
|
|
kmod->name, NULL);
|
2019-09-25 01:13:53 +01:00
|
|
|
kmod->elf = NULL;
|
|
|
|
kmod->fd = -1;
|
|
|
|
if (err)
|
|
|
|
return err;
|
2020-10-13 20:25:22 +01:00
|
|
|
next:
|
2019-09-25 01:13:53 +01:00
|
|
|
kmod = kmod->next;
|
|
|
|
} while (kmod);
|
2019-06-04 23:20:03 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct drgn_error *
|
2020-09-16 01:42:53 +01:00
|
|
|
report_default_kernel_module(struct drgn_debug_info_load_state *load,
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct kernel_module_iterator *kmod_it,
|
|
|
|
struct depmod_index *depmod)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2019-09-25 01:13:53 +01:00
|
|
|
static const char * const module_paths[] = {
|
2019-06-04 23:20:03 +01:00
|
|
|
"/usr/lib/debug/lib/modules/%s/%.*s",
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
"/usr/lib/debug/lib/modules/%s/%.*s.debug",
|
2019-09-25 01:13:53 +01:00
|
|
|
"/lib/modules/%s/%.*s%.*s",
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
NULL,
|
2019-06-04 23:20:03 +01:00
|
|
|
};
|
|
|
|
struct drgn_error *err;
|
2020-09-16 01:42:53 +01:00
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
const char *depmod_path;
|
|
|
|
size_t depmod_path_len;
|
2020-10-29 00:35:09 +00:00
|
|
|
err = depmod_index_find(depmod, kmod_it->name, &depmod_path,
|
|
|
|
&depmod_path_len);
|
|
|
|
if (err) {
|
|
|
|
return drgn_debug_info_report_error(load,
|
|
|
|
"kernel modules",
|
|
|
|
"could not parse depmod",
|
|
|
|
err);
|
|
|
|
} else if (!depmod_path) {
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, kmod_it->name,
|
|
|
|
"could not find module in depmod",
|
|
|
|
NULL);
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
size_t extension_len;
|
2019-09-25 01:13:53 +01:00
|
|
|
if (depmod_path_len >= 3 &&
|
|
|
|
(memcmp(depmod_path + depmod_path_len - 3, ".gz", 3) == 0 ||
|
|
|
|
memcmp(depmod_path + depmod_path_len - 3, ".xz", 3) == 0))
|
|
|
|
extension_len = 3;
|
|
|
|
else
|
|
|
|
extension_len = 0;
|
2020-09-16 01:42:53 +01:00
|
|
|
char *path;
|
|
|
|
int fd;
|
|
|
|
Elf *elf;
|
2019-09-25 01:13:53 +01:00
|
|
|
err = find_elf_file(&path, &fd, &elf, module_paths,
|
2020-09-16 01:42:53 +01:00
|
|
|
load->dbinfo->prog->vmcoreinfo.osrelease,
|
2019-09-25 01:13:53 +01:00
|
|
|
depmod_path_len - extension_len, depmod_path,
|
|
|
|
extension_len,
|
|
|
|
depmod_path + depmod_path_len - extension_len);
|
|
|
|
if (err)
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, NULL, NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!elf) {
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, kmod_it->name,
|
|
|
|
"could not find .ko",
|
|
|
|
NULL);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
uint64_t start, end;
|
2019-09-25 01:13:53 +01:00
|
|
|
err = cache_kernel_module_sections(kmod_it, elf, &start, &end);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err) {
|
2020-10-13 19:55:06 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path,
|
|
|
|
"could not get section addresses",
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
elf_end(elf);
|
|
|
|
close(fd);
|
|
|
|
free(path);
|
2020-10-13 19:55:06 +01:00
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_elf(load, path, fd, elf, start, end,
|
|
|
|
kmod_it->name, NULL);
|
2019-09-25 01:13:53 +01:00
|
|
|
free(path);
|
|
|
|
return err;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2019-06-04 23:20:03 +01:00
|
|
|
static struct drgn_error *
|
2020-09-16 01:42:53 +01:00
|
|
|
report_loaded_kernel_modules(struct drgn_debug_info_load_state *load,
|
2019-09-25 01:13:53 +01:00
|
|
|
struct kernel_module_table *kmod_table,
|
2020-10-13 19:24:39 +01:00
|
|
|
struct depmod_index *depmod,
|
|
|
|
bool use_proc_and_sys)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2020-09-16 01:42:53 +01:00
|
|
|
struct drgn_program *prog = load->dbinfo->prog;
|
2019-06-04 23:20:03 +01:00
|
|
|
struct drgn_error *err;
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
struct kernel_module_iterator kmod_it;
|
2020-10-13 19:24:39 +01:00
|
|
|
err = kernel_module_iterator_init(&kmod_it, prog, use_proc_and_sys);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err) {
|
2019-06-04 23:20:03 +01:00
|
|
|
kernel_module_iterator_error:
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, "kernel modules",
|
|
|
|
"could not find loaded kernel modules",
|
|
|
|
err);
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
for (;;) {
|
|
|
|
err = kernel_module_iterator_next(&kmod_it);
|
2021-03-05 20:46:06 +00:00
|
|
|
if (err == &drgn_stop) {
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
err = NULL;
|
|
|
|
break;
|
|
|
|
} else if (err) {
|
|
|
|
kernel_module_iterator_deinit(&kmod_it);
|
|
|
|
goto kernel_module_iterator_error;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
/* Look for an explicitly-reported file first. */
|
|
|
|
if (kmod_table) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = report_loaded_kernel_module(load, &kmod_it,
|
|
|
|
kmod_table);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!err)
|
|
|
|
continue;
|
|
|
|
else if (err != &drgn_not_found)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
break;
|
2019-09-25 01:13:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it was not reported explicitly and we're also reporting the
|
|
|
|
* defaults, look for the module at the standard locations unless we've
|
|
|
|
* already indexed that module.
|
|
|
|
*/
|
|
|
|
if (depmod &&
|
2020-09-16 01:42:53 +01:00
|
|
|
!drgn_debug_info_is_indexed(load->dbinfo, kmod_it.name)) {
|
2020-10-29 00:35:09 +00:00
|
|
|
if (!depmod->addr) {
|
2019-09-25 01:13:53 +01:00
|
|
|
err = depmod_index_init(depmod,
|
|
|
|
prog->vmcoreinfo.osrelease);
|
|
|
|
if (err) {
|
2020-10-29 00:35:09 +00:00
|
|
|
depmod->addr = NULL;
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load,
|
|
|
|
"kernel modules",
|
|
|
|
"could not read depmod",
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
depmod = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2020-09-16 01:42:53 +01:00
|
|
|
err = report_default_kernel_module(load, &kmod_it,
|
|
|
|
depmod);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kernel_module_iterator_deinit(&kmod_it);
|
2019-06-04 23:20:03 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
static struct drgn_error *
|
2020-09-16 01:42:53 +01:00
|
|
|
report_kernel_modules(struct drgn_debug_info_load_state *load,
|
2019-09-25 01:13:53 +01:00
|
|
|
struct kernel_module_file *kmods, size_t num_kmods,
|
2020-09-16 01:42:53 +01:00
|
|
|
bool need_module_definition, bool vmlinux_is_pending)
|
2019-06-04 23:20:03 +01:00
|
|
|
{
|
2020-09-16 01:42:53 +01:00
|
|
|
struct drgn_program *prog = load->dbinfo->prog;
|
2019-06-04 23:20:03 +01:00
|
|
|
struct drgn_error *err;
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
if (!num_kmods && !load->load_default)
|
2019-09-25 01:13:53 +01:00
|
|
|
return NULL;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
/*
|
2020-10-13 19:24:39 +01:00
|
|
|
* If we're debugging the running kernel, we can get the loaded kernel
|
|
|
|
* modules from /proc and /sys instead of from the core dump. This fast
|
|
|
|
* path can be disabled via an environment variable for testing.
|
|
|
|
*/
|
|
|
|
bool use_proc_and_sys = false;
|
|
|
|
if (prog->flags & DRGN_PROGRAM_IS_LIVE) {
|
|
|
|
char *env = getenv("DRGN_USE_PROC_AND_SYS_MODULES");
|
|
|
|
use_proc_and_sys = !env || atoi(env);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we're not using /proc and /sys, then we need to index vmlinux now
|
|
|
|
* so that we can walk the list of modules in the kernel.
|
2019-09-25 01:13:53 +01:00
|
|
|
*
|
|
|
|
* If we need the definition of struct module to get the name of any
|
|
|
|
* kernel modules, then we also need to index vmlinux now.
|
|
|
|
*/
|
|
|
|
if (vmlinux_is_pending &&
|
2020-10-13 19:24:39 +01:00
|
|
|
(!use_proc_and_sys || need_module_definition)) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_flush(load);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
2019-09-25 01:13:53 +01:00
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
size_t module_name_offset = 0;
|
2019-09-25 01:13:53 +01:00
|
|
|
if (need_module_definition) {
|
|
|
|
struct drgn_qualified_type module_type;
|
2020-12-15 01:58:44 +00:00
|
|
|
struct drgn_type_member *name_member;
|
|
|
|
uint64_t name_bit_offset;
|
2019-09-25 01:13:53 +01:00
|
|
|
err = drgn_program_find_type(prog, "struct module", NULL,
|
|
|
|
&module_type);
|
|
|
|
if (!err) {
|
2020-12-15 01:58:44 +00:00
|
|
|
err = drgn_type_find_member(module_type.type, "name",
|
|
|
|
&name_member,
|
|
|
|
&name_bit_offset);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load,
|
|
|
|
"kernel modules",
|
|
|
|
"could not get kernel module names",
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
}
|
2020-12-15 01:58:44 +00:00
|
|
|
module_name_offset = name_bit_offset / 8;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
struct kernel_module_table kmod_table = HASH_TABLE_INIT;
|
|
|
|
struct depmod_index depmod;
|
2020-10-29 00:35:09 +00:00
|
|
|
depmod.addr = NULL;
|
2020-07-01 20:37:16 +01:00
|
|
|
struct kernel_module_table_iterator it;
|
|
|
|
for (size_t i = 0; i < num_kmods; i++) {
|
2019-09-25 01:13:53 +01:00
|
|
|
struct kernel_module_file *kmod = &kmods[i];
|
|
|
|
if (!kmod->name) {
|
|
|
|
err = get_kernel_module_name_from_this_module(kmod->this_module_scn,
|
|
|
|
module_name_offset,
|
|
|
|
&kmod->name);
|
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load,
|
|
|
|
kmod->path,
|
|
|
|
NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!kmod->name) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load,
|
|
|
|
kmod->path,
|
|
|
|
"could not find kernel module name",
|
|
|
|
NULL);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-07-01 20:37:16 +01:00
|
|
|
struct hash_pair hp = kernel_module_table_hash(&kmod->name);
|
2019-09-25 01:13:53 +01:00
|
|
|
it = kernel_module_table_search_hashed(&kmod_table, &kmod->name,
|
|
|
|
hp);
|
|
|
|
if (it.entry) {
|
|
|
|
kmod->next = *it.entry;
|
|
|
|
*it.entry = kmod;
|
|
|
|
} else {
|
|
|
|
if (kernel_module_table_insert_searched(&kmod_table,
|
|
|
|
&kmod, hp,
|
|
|
|
NULL) == -1) {
|
|
|
|
err = &drgn_enomem;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
kmod->next = NULL;
|
|
|
|
}
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
err = report_loaded_kernel_modules(load,
|
2019-09-25 01:13:53 +01:00
|
|
|
num_kmods ? &kmod_table : NULL,
|
2020-10-13 19:24:39 +01:00
|
|
|
load->load_default ? &depmod : NULL,
|
|
|
|
use_proc_and_sys);
|
2019-06-04 23:20:03 +01:00
|
|
|
if (err)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
goto out;
|
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
/* Anything left over was not loaded. */
|
|
|
|
for (it = kernel_module_table_first(&kmod_table); it.entry; ) {
|
|
|
|
struct kernel_module_file *kmod = *it.entry;
|
|
|
|
it = kernel_module_table_delete_iterator(&kmod_table, it);
|
|
|
|
do {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_elf(load, kmod->path,
|
|
|
|
kmod->fd, kmod->elf, 0,
|
|
|
|
0, kmod->name, NULL);
|
2019-09-25 01:13:53 +01:00
|
|
|
kmod->elf = NULL;
|
|
|
|
kmod->fd = -1;
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
kmod = kmod->next;
|
|
|
|
} while (kmod);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|
2019-09-25 01:13:53 +01:00
|
|
|
err = NULL;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
out:
|
2020-10-29 00:35:09 +00:00
|
|
|
if (depmod.addr)
|
2019-09-25 01:13:53 +01:00
|
|
|
depmod_index_deinit(&depmod);
|
|
|
|
kernel_module_table_deinit(&kmod_table);
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
return err;
|
|
|
|
}
|
2019-06-04 23:20:03 +01:00
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
static struct drgn_error *
|
|
|
|
report_vmlinux(struct drgn_debug_info_load_state *load,
|
|
|
|
bool *vmlinux_is_pending)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
2019-09-25 01:13:53 +01:00
|
|
|
static const char * const vmlinux_paths[] = {
|
|
|
|
/*
|
|
|
|
* The files under /usr/lib/debug should always have debug
|
|
|
|
* information, so check for those first.
|
|
|
|
*/
|
|
|
|
"/usr/lib/debug/boot/vmlinux-%s",
|
|
|
|
"/usr/lib/debug/lib/modules/%s/vmlinux",
|
|
|
|
"/boot/vmlinux-%s",
|
|
|
|
"/lib/modules/%s/build/vmlinux",
|
|
|
|
"/lib/modules/%s/vmlinux",
|
|
|
|
NULL,
|
|
|
|
};
|
2020-09-16 01:42:53 +01:00
|
|
|
struct drgn_program *prog = load->dbinfo->prog;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct drgn_error *err;
|
2020-09-16 01:42:53 +01:00
|
|
|
|
2019-09-25 01:13:53 +01:00
|
|
|
char *path;
|
|
|
|
int fd;
|
|
|
|
Elf *elf;
|
|
|
|
err = find_elf_file(&path, &fd, &elf, vmlinux_paths,
|
|
|
|
prog->vmcoreinfo.osrelease);
|
|
|
|
if (err)
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, NULL, NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!elf) {
|
|
|
|
err = drgn_error_format(DRGN_ERROR_OTHER,
|
|
|
|
"could not find vmlinux for %s",
|
|
|
|
prog->vmcoreinfo.osrelease);
|
2020-09-16 01:42:53 +01:00
|
|
|
return drgn_debug_info_report_error(load, "kernel", NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
uint64_t start, end;
|
2019-09-25 01:13:53 +01:00
|
|
|
err = elf_address_range(elf, prog->vmcoreinfo.kaslr_offset, &start,
|
|
|
|
&end);
|
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path, NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
elf_end(elf);
|
|
|
|
close(fd);
|
|
|
|
free(path);
|
|
|
|
return err;
|
2019-06-04 23:20:03 +01:00
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_elf(load, path, fd, elf, start, end,
|
|
|
|
"kernel", vmlinux_is_pending);
|
2019-09-25 01:13:53 +01:00
|
|
|
free(path);
|
2019-06-04 23:20:03 +01:00
|
|
|
return err;
|
|
|
|
}
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
|
|
|
|
struct drgn_error *
|
2020-09-16 01:42:53 +01:00
|
|
|
linux_kernel_report_debug_info(struct drgn_debug_info_load_state *load)
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
{
|
2020-09-16 01:42:53 +01:00
|
|
|
struct drgn_program *prog = load->dbinfo->prog;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
struct drgn_error *err;
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
struct kernel_module_file *kmods;
|
|
|
|
if (load->num_paths) {
|
|
|
|
kmods = malloc_array(load->num_paths, sizeof(*kmods));
|
2019-09-25 01:13:53 +01:00
|
|
|
if (!kmods)
|
|
|
|
return &drgn_enomem;
|
|
|
|
} else {
|
|
|
|
kmods = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We may need to index vmlinux before we can properly report kernel
|
|
|
|
* modules. So, this sets aside kernel modules and reports everything
|
|
|
|
* else.
|
|
|
|
*/
|
2020-09-16 01:42:53 +01:00
|
|
|
size_t num_kmods = 0;
|
|
|
|
bool need_module_definition = false;
|
|
|
|
bool vmlinux_is_pending = false;
|
|
|
|
for (size_t i = 0; i < load->num_paths; i++) {
|
|
|
|
const char *path = load->paths[i];
|
2019-09-25 01:13:53 +01:00
|
|
|
int fd;
|
|
|
|
Elf *elf;
|
|
|
|
err = open_elf_file(path, &fd, &elf);
|
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path, NULL,
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
Elf_Scn *this_module_scn, *modinfo_scn;
|
|
|
|
bool is_vmlinux;
|
2019-09-25 01:13:53 +01:00
|
|
|
err = identify_kernel_elf(elf, &this_module_scn, &modinfo_scn,
|
|
|
|
&is_vmlinux);
|
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path, NULL,
|
|
|
|
err);
|
2019-09-25 01:13:53 +01:00
|
|
|
elf_end(elf);
|
|
|
|
close(fd);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (this_module_scn || modinfo_scn) {
|
|
|
|
struct kernel_module_file *kmod = &kmods[num_kmods++];
|
|
|
|
kmod->path = path;
|
|
|
|
kmod->fd = fd;
|
|
|
|
kmod->elf = elf;
|
|
|
|
err = get_kernel_module_name_from_modinfo(modinfo_scn,
|
|
|
|
&kmod->name);
|
|
|
|
if (err) {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path,
|
|
|
|
NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!kmod->name) {
|
|
|
|
kmod->this_module_scn = this_module_scn;
|
|
|
|
need_module_definition = true;
|
|
|
|
}
|
|
|
|
} else if (is_vmlinux) {
|
|
|
|
uint64_t start, end;
|
|
|
|
err = elf_address_range(elf,
|
|
|
|
prog->vmcoreinfo.kaslr_offset,
|
|
|
|
&start, &end);
|
|
|
|
if (err) {
|
|
|
|
elf_end(elf);
|
|
|
|
close(fd);
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_error(load, path,
|
|
|
|
NULL, err);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
bool is_new;
|
|
|
|
err = drgn_debug_info_report_elf(load, path, fd, elf,
|
|
|
|
start, end, "kernel",
|
|
|
|
&is_new);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
if (is_new)
|
|
|
|
vmlinux_is_pending = true;
|
|
|
|
} else {
|
2020-09-16 01:42:53 +01:00
|
|
|
err = drgn_debug_info_report_elf(load, path, fd, elf, 0,
|
|
|
|
0, NULL, NULL);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
if (load->load_main && !vmlinux_is_pending &&
|
|
|
|
!drgn_debug_info_is_indexed(load->dbinfo, "kernel")) {
|
|
|
|
err = report_vmlinux(load, &vmlinux_is_pending);
|
2019-09-25 01:13:53 +01:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-09-16 01:42:53 +01:00
|
|
|
err = report_kernel_modules(load, kmods, num_kmods,
|
|
|
|
need_module_definition, vmlinux_is_pending);
|
2019-09-25 01:13:53 +01:00
|
|
|
out:
|
2020-09-16 01:42:53 +01:00
|
|
|
for (size_t i = 0; i < num_kmods; i++) {
|
2019-09-25 01:13:53 +01:00
|
|
|
elf_end(kmods[i].elf);
|
|
|
|
if (kmods[i].fd != -1)
|
|
|
|
close(kmods[i].fd);
|
|
|
|
}
|
|
|
|
free(kmods);
|
|
|
|
return err;
|
libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:
- It only supports finding debug information for the running kernel, not
vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
for every module.
- It doesn't find kernel modules with names containing both dashes and
underscores (e.g., aes-x86_64).
Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.
The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 08:51:30 +01:00
|
|
|
}
|