public inbox for kexec@lists.infradead.org
 help / color / mirror / Atom feed
From: Stephen Brennan <stephen.s.brennan@oracle.com>
To: Tao Liu <ltao@redhat.com>,
	yamazaki-msmt@nec.com, k-hagio-ab@nec.com,
	kexec@lists.infradead.org
Cc: aravinda@linux.vnet.ibm.com, Tao Liu <ltao@redhat.com>
Subject: Re: [PATCH v4][makedumpfile 3/7] Implement kernel btf resolving
Date: Thu, 02 Apr 2026 16:41:41 -0700	[thread overview]
Message-ID: <87zf3ldj62.fsf@oracle.com> (raw)
In-Reply-To: <20260317150743.69590-4-ltao@redhat.com>

Tao Liu <ltao@redhat.com> writes:
> This patch will parse kernel's btf data using libbpf. The kernel's
> btf data is located between __start_BTF and __stop_BTF symbols which
> are resolved by kallsyms of the previous patch. Same as the previous
> one, the .init_ktypes section of makedumpfile and the extensions will
> be iterated, and any types which belongs to vmlinux can be resolved
> at this time.
>
> Another primary function implemented in this patch, is recursively
> diving into anonymous struct/union when encountered any, to find a
> member by given its name.
>
> Suggested-by: Stephen Brennan <stephen.s.brennan@oracle.com>
> Signed-off-by: Tao Liu <ltao@redhat.com>

Reviewed-by: Stephen Brennan <stephen.s.brennan@oracle.com>

> ---
>  Makefile   |   4 +-
>  btf_info.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  btf_info.h |  90 +++++++++++++++++++++
>  3 files changed, 325 insertions(+), 2 deletions(-)
>  create mode 100644 btf_info.c
>  create mode 100644 btf_info.h
>
> diff --git a/Makefile b/Makefile
> index a57185e..320677d 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -45,12 +45,12 @@ CFLAGS_ARCH += -m32
>  endif
>  
>  SRC_BASE = makedumpfile.c makedumpfile.h diskdump_mod.h sadump_mod.h sadump_info.h
> -SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c detect_cycle.c kallsyms.c
> +SRC_PART = print_info.c dwarf_info.c elf_info.c erase_info.c sadump_info.c cache.c tools.c printk.c detect_cycle.c kallsyms.c btf_info.c
>  OBJ_PART=$(patsubst %.c,%.o,$(SRC_PART))
>  SRC_ARCH = arch/arm.c arch/arm64.c arch/x86.c arch/x86_64.c arch/ia64.c arch/ppc64.c arch/s390x.c arch/ppc.c arch/sparc64.c arch/mips64.c arch/loongarch64.c arch/riscv64.c
>  OBJ_ARCH=$(patsubst %.c,%.o,$(SRC_ARCH))
>  
> -LIBS = -ldw -lbz2 -ldl -lelf -lz
> +LIBS = -ldw -lbz2 -ldl -lelf -lz -lbpf
>  ifneq ($(LINKTYPE), dynamic)
>  LIBS := -static $(LIBS) -llzma
>  endif
> diff --git a/btf_info.c b/btf_info.c
> new file mode 100644
> index 0000000..1cb66e2
> --- /dev/null
> +++ b/btf_info.c
> @@ -0,0 +1,233 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <bpf/btf.h>
> +#include <bpf/libbpf_legacy.h>
> +#include "makedumpfile.h"
> +#include "kallsyms.h"
> +#include "btf_info.h"
> +
> +struct btf_arr_elem {
> +	struct btf *btf;
> +	char *module;
> +};
> +
> +static struct btf_arr_elem **btf_arr = NULL;
> +static int btf_arr_len = 0;
> +static int btf_arr_cap = 0;
> +
> +/* makedumpfile & extensions' .init_ktypes section range array */
> +static struct section_range **sr = NULL;
> +static int sr_len = 0;
> +static int sr_cap = 0;
> +
> +/* Which mod's btf should be inited? */
> +static char **mods = NULL;
> +static int mods_len = 0;
> +static int mods_cap = 0;
> +
> +static bool add_ktype_modname(char *modname)
> +{
> +	return push_uniq_str((void ***)&mods, &mods_len, &mods_cap, modname);
> +}
> +
> +bool check_ktypes_require_modname(char *modname, int *total)
> +{
> +	if (total)
> +		*total = mods_len;
> +	for (int i = 0; i < mods_len; i++) {
> +		if (!strcmp(modname, mods[i]))
> +			return true;
> +	}
> +	return false;
> +}
> +
> +static void cleanup_ktypes_modname(void)
> +{
> +	if (mods) {
> +		free(mods);
> +		mods = NULL;
> +	}
> +	mods_len = 0;
> +	mods_cap = 0;
> +}
> +
> +/*
> + * Used by makedumpfile and extensions, to register their .init_ktypes section,
> + * so btf_info can know which module/type should be inited.
> +*/
> +REGISTER_SECTION(ktype)
> +
> +static void cleanup_ktypes_section_range(void)
> +{
> +	for (int i = 0; i < sr_len; i++) {
> +		free(sr[i]);
> +	}
> +	if (sr) {
> +		free(sr);
> +		sr = NULL;
> +	}
> +	sr_len = 0;
> +	sr_cap = 0;
> +}
> +
> +static void find_member_recursive(struct btf *btf, int struct_typeid,
> +				  int base_offset, struct ktype_info *ki)
> +{
> +	const struct btf_type *st;
> +	struct btf_member *bm;
> +	int i, vlen;
> +
> +	struct_typeid = btf__resolve_type(btf, struct_typeid);
> +	st = btf__type_by_id(btf, struct_typeid);
> +
> +	if (!st)
> +		return;
> +
> +	if (BTF_INFO_KIND(st->info) != BTF_KIND_STRUCT &&
> +	    BTF_INFO_KIND(st->info) != BTF_KIND_UNION)
> +		return;
> +
> +	vlen = BTF_INFO_VLEN(st->info);
> +	bm = btf_members(st);
> +
> +	for (i = 0; i < vlen; i++, bm++) {
> +		const char *name = btf__name_by_offset(btf, bm->name_off);
> +		int member_bit_offset = btf_member_bit_offset(st, i) + base_offset;
> +		int member_typeid = btf__resolve_type(btf, bm->type);
> +		const struct btf_type *mt = btf__type_by_id(btf, member_typeid);
> +
> +		if (name && strcmp(name, ki->member_name) == 0) {
> +			ki->member_bit_offset = member_bit_offset;
> +			ki->member_bit_sz = btf_member_bitfield_size(st, i);
> +			ki->member_size = btf__resolve_size(btf, member_typeid);
> +			ki->index = i;
> +			return;
> +		}
> +
> +		if (!name || !name[0]) {
> +			if (BTF_INFO_KIND(mt->info) == BTF_KIND_STRUCT ||
> +			    BTF_INFO_KIND(mt->info) == BTF_KIND_UNION) {
> +				find_member_recursive(btf, member_typeid,
> +						      member_bit_offset, ki);
> +			}
> +		}
> +	}
> +}
> +
> +static void get_ktype_info(struct ktype_info *ki, char *mod_to_resolve)
> +{
> +	int i, j, start_id;
> +
> +	if (mod_to_resolve != NULL) {
> +		if (strcmp(ki->modname, mod_to_resolve) != 0)
> +			/* Exit safely */
> +			return;
> +	}
> +
> +	for (i = 0; i < btf_arr_len; i++) {
> +		if (strcmp(btf_arr[i]->module, ki->modname) != 0)
> +			continue;
> +		/*
> +		 * vmlinux(btf_arr[0])'s typeid is 1~vmlinux_type_cnt,
> +		 * modules(btf_arr[1...])'s typeid is vmlinux_type_cnt~btf__type_cnt
> +		 */
> +		start_id = (i == 0 ? 1 : btf__type_cnt(btf_arr[0]->btf));
> +
> +		for (j = start_id; j < btf__type_cnt(btf_arr[i]->btf); j++) {
> +			const struct btf_type *bt =
> +				btf__type_by_id(btf_arr[i]->btf, j);
> +			const char *name =
> +				btf__name_by_offset(btf_arr[i]->btf, bt->name_off);
> +
> +			if (name && strcmp(ki->struct_name, name) == 0) {
> +				if (ki->member_name != NULL) {
> +					/* Retrieve member info */
> +					find_member_recursive(btf_arr[i]->btf, j, 0, ki);
> +				} else {
> +					ki->index = j;
> +				}
> +				ki->struct_size = btf__resolve_size(btf_arr[i]->btf, j);
> +				return;
> +			}
> +		}
> +	}
> +}
> +
> +static bool add_to_btf_arr(struct btf *btf, char *module_name)
> +{
> +	struct btf_arr_elem *new_p;
> +
> +	new_p = malloc(sizeof(struct btf_arr_elem));
> +	if (!new_p)
> +		goto no_mem;
> +
> +	new_p->btf = btf;
> +	new_p->module = module_name;
> +
> +	return add_to_arr((void ***)&btf_arr, &btf_arr_len, &btf_arr_cap, new_p);
> +
> +no_mem:
> +	fprintf(stderr, "%s: Not enough memory!\n", __func__);
> +	return false;
> +}
> +
> +INIT_KERN_SYM(__start_BTF);
> +INIT_KERN_SYM(__stop_BTF);
> +
> +/*
> + * Makedumpfile's .init_ktypes section
> +*/
> +extern struct ktype_info *__start_init_ktypes[];
> +extern struct ktype_info *__stop_init_ktypes[];
> +
> +bool init_kernel_btf(void)
> +{
> +	uint64_t size;
> +	struct btf *btf;
> +	int i;
> +	struct ktype_info **p;
> +	char *buf = NULL;
> +	bool ret = false;
> +
> +	uint64_t start_btf = GET_KERN_SYM(__start_BTF);
> +	uint64_t stop_btf = GET_KERN_SYM(__stop_BTF);
> +	if (!KERN_SYM_EXIST(__start_BTF) ||
> +	    !KERN_SYM_EXIST(__stop_BTF)) {
> +		fprintf(stderr, "%s: symbol __start/stop_BTF not found!\n", __func__);
> +		goto out;
> +	}
> +
> +	if (!register_ktype_section((char *)__start_init_ktypes,
> +				    (char *)__stop_init_ktypes))
> +		return ret;
> +
> +	size = stop_btf - start_btf;
> +	buf = (char *)malloc(size);
> +	if (!buf) {
> +		fprintf(stderr, "%s: Not enough memory!\n", __func__);
> +		goto out;
> +	}
> +	readmem(VADDR, start_btf, buf, size);
> +	btf = btf__new(buf, size);
> +
> +	if (libbpf_get_error(btf) != 0 ||
> +	    add_to_btf_arr(btf, strdup("vmlinux")) == false) {	
> +		fprintf(stderr, "%s: init vmlinux btf fail\n", __func__);
> +		goto out;
> +	}
> +
> +	for (i = 0; i < sr_len; i++) {
> +		for (p = (struct ktype_info **)(sr[i]->start);
> +		     p < (struct ktype_info **)(sr[i]->stop);
> +		     p++) {
> +			get_ktype_info(*p, "vmlinux");
> +		}
> +	}
> +
> +	ret = true;
> +out:
> +	if (buf)
> +		free(buf);
> +	return ret;
> +}
> \ No newline at end of file
> diff --git a/btf_info.h b/btf_info.h
> new file mode 100644
> index 0000000..2cf6b07
> --- /dev/null
> +++ b/btf_info.h
> @@ -0,0 +1,90 @@
> +#ifndef _BTF_INFO_H
> +#define _BTF_INFO_H
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +struct ktype_info {
> +	/********in******/
> +	char *modname;		// Set to search within the module, in case
> +				// name conflict of different modules
> +	char *struct_name;	// Search by struct name
> +	char *member_name;	// Search by member name
> +	bool struct_required : 1;
> +	bool member_required : 1;
> +	/********out*****/
> +	uint32_t member_bit_offset;	// member offset in bits
> +	uint32_t member_bit_sz;	// member width in bits
> +	uint32_t member_size;	// member size in bytes
> +	uint32_t struct_size;	// struct size in bytes
> +	int index;		// -1 if type not found
> +};
> +
> +bool check_ktypes_require_modname(char *modname, int *total);
> +bool register_ktype_section(char *start, char *stop);
> +bool init_kernel_btf(void);
> +
> +#define QUATE(x) #x
> +#define INIT_MOD_STRUCT_MEMBER_RQD(MOD, S, M, R)			\
> +	struct ktype_info _##MOD##_##S##_##M = {			\
> +		QUATE(MOD), QUATE(S), QUATE(M), R, R, 0, 0, 0, 0, -1	\
> +	};								\
> +	__attribute__((section(".init_ktypes"), used))			\
> +	struct ktype_info * _ptr_##MOD##_##S##_##M = &_##MOD##_##S##_##M
> +
> +/*
> + * Required types will be checked automatically before extension running.
> + * Optinal types should be checked manually at extension runtime.
> + */
> +#define INIT_MOD_STRUCT_MEMBER(MOD, S, M) \
> +	INIT_MOD_STRUCT_MEMBER_RQD(MOD, S, M, 1)
> +#define INIT_OPT_MOD_STRUCT_MEMBER(MOD, S, M) \
> +	INIT_MOD_STRUCT_MEMBER_RQD(MOD, S, M, 0)
> +
> +#define DECLARE_MOD_STRUCT_MEMBER(MOD, S, M) \
> +	extern struct ktype_info _##MOD##_##S##_##M
> +
> +#define GET_MOD_STRUCT_MEMBER_MOFF(MOD, S, M)  (_##MOD##_##S##_##M.member_bit_offset)
> +#define GET_MOD_STRUCT_MEMBER_MSIZE(MOD, S, M) (_##MOD##_##S##_##M.member_size)
> +#define GET_MOD_STRUCT_MEMBER_SSIZE(MOD, S, M) (_##MOD##_##S##_##M.struct_size)
> +#define MOD_STRUCT_MEMBER_EXIST(MOD, S, M) (_##MOD##_##S##_##M.index >= 0)
> +#define TYPE_EXIST(p) ((p)->index >= 0)
> +
> +#define INIT_KERN_STRUCT_MEMBER(S, M) \
> +	INIT_MOD_STRUCT_MEMBER(vmlinux, S, M)
> +#define INIT_OPT_KERN_STRUCT_MEMBER(S, M) \
> +	INIT_OPT_MOD_STRUCT_MEMBER(vmlinux, S, M)
> +
> +#define DECLARE_KERN_STRUCT_MEMBER(S, M) \
> +	DECLARE_MOD_STRUCT_MEMBER(vmlinux, S, M)
> +
> +#define GET_KERN_STRUCT_MEMBER_MOFF(S, M)  GET_MOD_STRUCT_MEMBER_MOFF(vmlinux, S, M)
> +#define GET_KERN_STRUCT_MEMBER_MSIZE(S, M) GET_MOD_STRUCT_MEMBER_MSIZE(vmlinux, S, M)
> +#define GET_KERN_STRUCT_MEMBER_SSIZE(S, M) GET_MOD_STRUCT_MEMBER_SSIZE(vmlinux, S, M)
> +#define KERN_STRUCT_MEMBER_EXIST(S, M) MOD_STRUCT_MEMBER_EXIST(vmlinux, S, M)
> +
> +#define INIT_MOD_STRUCT_RQD(MOD, S, R)				\
> +	struct ktype_info _##MOD##_##S = {			\
> +		QUATE(MOD), QUATE(S), 0, R, 0, 0, 0, 0, 0, -1	\
> +	};							\
> +	__attribute__((section(".init_ktypes"), used))		\
> +	struct ktype_info * _ptr_##MOD##_##S = &_##MOD##_##S
> +
> +#define INIT_MOD_STRUCT(MOD, S) INIT_MOD_STRUCT_RQD(MOD, S, 1)
> +#define INIT_OPT_MOD_STRUCT(MOD, S) INIT_MOD_STRUCT_RQD(MOD, S, 0)
> +
> +#define DECLARE_MOD_STRUCT(MOD, S) \
> +	extern struct ktype_info _##MOD##_##S;
> +
> +#define GET_MOD_STRUCT_SSIZE(MOD, S) (_##MOD##_##S.struct_size)
> +#define MOD_STRUCT_EXIST(MOD, S) (_##MOD##_##S.index >= 0)
> +
> +#define INIT_KERN_STRUCT(S) INIT_MOD_STRUCT(vmlinux, S)
> +#define INIT_OPT_KERN_STRUCT(S) INIT_OPT_MOD_STRUCT(vmlinux, S)
> +
> +#define DECLARE_KERN_STRUCT(S) \
> +	DECLARE_MOD_STRUCT(vmlinux, S)
> +
> +#define GET_KERN_STRUCT_SSIZE(S) GET_MOD_STRUCT_SSIZE(vmlinux, S)
> +#define KERN_STRUCT_EXIST(S) MOD_STRUCT_EXIST(vmlinux, S)
> +
> +#endif /* _BTF_INFO_H */
> \ No newline at end of file
> -- 
> 2.47.0


  reply	other threads:[~2026-04-02 23:41 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-17 15:07 [PATCH v4][makedumpfile 0/7] btf/kallsyms based makedumpfile extension for mm page filtering Tao Liu
2026-03-17 15:07 ` [PATCH v4][makedumpfile 1/7] Reserve sections for makedumpfile and extenions Tao Liu
2026-04-02 23:31   ` Stephen Brennan
2026-04-03  8:10   ` HAGIO KAZUHITO(萩尾 一仁)
2026-03-17 15:07 ` [PATCH v4][makedumpfile 2/7] Implement kernel kallsyms resolving Tao Liu
2026-04-02 23:32   ` Stephen Brennan
2026-04-03  8:12   ` HAGIO KAZUHITO(萩尾 一仁)
2026-03-17 15:07 ` [PATCH v4][makedumpfile 3/7] Implement kernel btf resolving Tao Liu
2026-04-02 23:41   ` Stephen Brennan [this message]
2026-04-03  8:13   ` HAGIO KAZUHITO(萩尾 一仁)
2026-03-17 15:07 ` [PATCH v4][makedumpfile 4/7] Implement kernel module's kallsyms resolving Tao Liu
2026-04-02 23:54   ` Stephen Brennan
2026-03-17 15:07 ` [PATCH v4][makedumpfile 5/7] Implement kernel module's btf resolving Tao Liu
2026-04-02 23:56   ` Stephen Brennan
2026-03-17 15:07 ` [PATCH v4][makedumpfile 6/7] Add makedumpfile extensions support Tao Liu
2026-04-03  0:11   ` Stephen Brennan
2026-04-03  8:14   ` HAGIO KAZUHITO(萩尾 一仁)
2026-03-17 15:07 ` [PATCH v4][makedumpfile 7/7] Filter amdgpu mm pages Tao Liu
2026-04-03  0:16   ` Stephen Brennan
2026-04-03  8:06 ` [PATCH v4][makedumpfile 0/7] btf/kallsyms based makedumpfile extension for mm page filtering HAGIO KAZUHITO(萩尾 一仁)
2026-04-03 18:26 ` Stephen Brennan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87zf3ldj62.fsf@oracle.com \
    --to=stephen.s.brennan@oracle.com \
    --cc=aravinda@linux.vnet.ibm.com \
    --cc=k-hagio-ab@nec.com \
    --cc=kexec@lists.infradead.org \
    --cc=ltao@redhat.com \
    --cc=yamazaki-msmt@nec.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox