[RFC PATCH 01/15] Add support for struct module_memory on Linux 6.4 and later

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Supported:
- startup without "--no_modules"
- "mod" command (without options)

Signed-off-by: Kazuhito Hagio <k-hagio-ab@xxxxxxx>
---
 defs.h    |  36 ++++
 kernel.c  |  26 ++-
 symbols.c | 482 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 527 insertions(+), 17 deletions(-)

diff --git a/defs.h b/defs.h
index 12ad6aaa0998..655cd2add163 100644
--- a/defs.h
+++ b/defs.h
@@ -675,6 +675,7 @@ struct new_utsname {
 #define IRQ_DESC_TREE_RADIX        (0x40ULL)
 #define IRQ_DESC_TREE_XARRAY       (0x80ULL)
 #define KMOD_PAX                  (0x100ULL)
+#define KMOD_MEMORY               (0x200ULL)
 
 #define XEN()       (kt->flags & ARCH_XEN)
 #define OPENVZ()    (kt->flags & ARCH_OPENVZ)
@@ -682,6 +683,7 @@ struct new_utsname {
 #define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN)
 
 #define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX)
+#define MODULE_MEMORY()    (kt->flags2 & KMOD_MEMORY)
 
 #define XEN_MACHINE_TO_MFN(m)    ((ulonglong)(m) >> PAGESHIFT())
 #define XEN_PFN_TO_PSEUDO(p)     ((ulonglong)(p) << PAGESHIFT())
@@ -2216,6 +2218,9 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long in6_addr_in6_u;
 	long kset_kobj;
 	long subsys_private_subsys;
+	long module_mem;
+	long module_memory_base;
+	long module_memory_size;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -2389,6 +2394,7 @@ struct size_table {         /* stash of commonly-used sizes */
 	long percpu_counter;
 	long maple_tree;
 	long maple_node;
+	long module_memory;
 };
 
 struct array_table {
@@ -2921,6 +2927,25 @@ struct mod_section_data {
         int flags;
 };
 
+/* This is unlikely to change, so imported from kernel for now. */
+enum mod_mem_type {
+	MOD_TEXT = 0,
+	MOD_DATA,
+	MOD_RODATA,
+	MOD_RO_AFTER_INIT,
+	MOD_INIT_TEXT,
+	MOD_INIT_DATA,
+	MOD_INIT_RODATA,
+
+	MOD_MEM_NUM_TYPES,
+	MOD_INVALID = -1,
+};
+
+struct module_memory {
+	ulong base;
+	uint size;
+};
+
 struct load_module {
         ulong mod_base;
 	ulong module_struct;
@@ -2954,13 +2979,23 @@ struct load_module {
 	ulong mod_percpu;
 	ulong mod_percpu_size;
 	struct objfile *loaded_objfile;
+
+	/* For 6.4 module_memory */
+	struct module_memory mem[MOD_MEM_NUM_TYPES];
+	struct syment *symtable[MOD_MEM_NUM_TYPES];
+	struct syment *symend[MOD_MEM_NUM_TYPES];
 };
 
+#define IN_MODULE(A,L)		(_in_module(A, L, MOD_TEXT))
+#define IN_MODULE_INIT(A,L)	(_in_module(A, L, MOD_INIT_TEXT))
+
+/*
 #define IN_MODULE(A,L) \
  (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size)))
 
 #define IN_MODULE_INIT(A,L) \
  (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size)))
+*/
 
 #define IN_MODULE_PERCPU(A,L) \
  (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size)))
@@ -5581,6 +5616,7 @@ void dump_struct_member(char *, ulong, unsigned);
 void dump_union(char *, ulong, unsigned);
 void store_module_symbols_v1(ulong, int);
 void store_module_symbols_v2(ulong, int);
+void store_module_symbols_v3(ulong, int);
 int is_datatype_command(void);
 int is_typedef(char *);
 int arg_to_datatype(char *, struct datatype_member *, ulong);
diff --git a/kernel.c b/kernel.c
index 6e98f5f6f6b1..62afff25bca8 100644
--- a/kernel.c
+++ b/kernel.c
@@ -3571,7 +3571,18 @@ module_init(void)
         	MEMBER_OFFSET_INIT(module_num_gpl_syms, "module", 
 			"num_gpl_syms");
 
-		if (MEMBER_EXISTS("module", "module_core")) {
+		if (MEMBER_EXISTS("module", "mem")) {	/* 6.4 and later */
+			kt->flags2 |= KMOD_MEMORY;	/* MODULE_MEMORY() can be used. */
+
+			MEMBER_OFFSET_INIT(module_mem, "module", "mem");
+			MEMBER_OFFSET_INIT(module_memory_base, "module_memory", "base");
+			MEMBER_OFFSET_INIT(module_memory_size, "module_memory", "size");
+			STRUCT_SIZE_INIT(module_memory, "module_memory");
+
+			if (get_array_length("module.mem", NULL, 0) != MOD_MEM_NUM_TYPES)
+				error(WARNING, "module memory types have changed!\n");
+
+		} else if (MEMBER_EXISTS("module", "module_core")) {
 			MEMBER_OFFSET_INIT(module_core_size, "module",
 					   "core_size");
 			MEMBER_OFFSET_INIT(module_init_size, "module",
@@ -3757,6 +3768,8 @@ module_init(void)
 		total += nsyms;
 		total += 2;  /* store the module's start/ending addresses */
 		total += 2;  /* and the init start/ending addresses */
+		if (MODULE_MEMORY()) /* 7 regions at most -> 14 */
+			total += 10;
 
 		/*
 		 *  If the module has kallsyms, set up to grab them as well.
@@ -3784,7 +3797,11 @@ module_init(void)
 		case KALLSYMS_V2:
 			if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
 				numksyms = UINT(modbuf + OFFSET(module_num_symtab));
-				size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
+				if (MODULE_MEMORY())
+					/* check mem[MOD_TEXT].size only */
+					size = UINT(modbuf + OFFSET(module_mem) + OFFSET(module_memory_size));
+				else
+					size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
 			} else {
 				numksyms = ULONG(modbuf + OFFSET(module_num_symtab));
 				size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx));
@@ -3822,7 +3839,10 @@ module_init(void)
 		store_module_symbols_v1(total, kt->mods_installed);
 		break;
 	case KMOD_V2:
-		store_module_symbols_v2(total, kt->mods_installed);
+		if (MODULE_MEMORY())
+			store_module_symbols_v3(total, kt->mods_installed);
+		else
+			store_module_symbols_v2(total, kt->mods_installed);
 		break;
 	}
 
diff --git a/symbols.c b/symbols.c
index f0721023816d..88849833bada 100644
--- a/symbols.c
+++ b/symbols.c
@@ -103,6 +103,8 @@ static void free_structure(struct struct_elem *);
 static unsigned char is_right_brace(const char *);
 static struct struct_elem *find_node(struct struct_elem *, char *);
 static void dump_node(struct struct_elem *, char *, unsigned char, unsigned char);
+static int _in_module(ulong, struct load_module *, int);
+static ulong module_mem_end(ulong, struct load_module *);
 
 
 /*
@@ -1788,6 +1790,387 @@ modsym_value(ulong syms, union kernel_symbol *modsym, int i)
 	return 0;
 }
 
+static const char *module_start_tags[] = {
+	"_MODULE_TEXT_START_",
+	"_MODULE_DATA_START_",
+	"_MODULE_RODATA_START_",
+	"_MODULE_RO_AFTER_INIT_START_",
+	"_MODULE_INIT_TEXT_START_",
+	"_MODULE_INIT_DATA_START_",
+	"_MODULE_INIT_RODATA_START_"
+};
+static const char *module_end_tags[] = {
+	"_MODULE_TEXT_END_",
+	"_MODULE_DATA_END_",
+	"_MODULE_RODATA_END_",
+	"_MODULE_RO_AFTER_INIT_END_",
+	"_MODULE_INIT_TEXT_END_",
+	"_MODULE_INIT_DATA_END_",
+	"_MODULE_INIT_RODATA_END_"
+};
+
+/*
+ * Linux 6.4 introduced module.mem memory layout
+ */
+void
+store_module_symbols_v3(ulong total, int mods_installed)
+{
+	int i, m;
+	ulong mod, mod_next;
+	char *mod_name;
+	uint nsyms, ngplsyms;
+	ulong syms, gpl_syms;
+	ulong nksyms;
+	long strbuflen;
+	ulong size;
+	int mcnt, lm_mcnt;
+	union kernel_symbol *modsym;
+	size_t kernel_symbol_size;
+	struct load_module *lm;
+	char buf1[BUFSIZE];
+	char buf2[BUFSIZE];
+	char *strbuf, *modbuf, *modsymbuf;
+	struct syment *sp;
+	ulong first, last;
+
+	st->mods_installed = mods_installed;
+
+	if (!st->mods_installed) {
+		st->flags &= ~MODULE_SYMS;
+		return;
+	}
+
+	/*
+	 *  If we've been here before, free up everything and start over.
+	 */
+	if (st->flags & MODULE_SYMS)
+		error(FATAL, "re-initialization of module symbols not implemented yet!\n");
+
+	kernel_symbol_size = kernel_symbol_type_init();
+
+	if ((st->ext_module_symtable = (struct syment *)
+	    calloc(total, sizeof(struct syment))) == NULL)
+		error(FATAL, "v2 module syment space malloc (%ld symbols): %s\n",
+			total, strerror(errno));
+
+	if (!namespace_ctl(NAMESPACE_INIT, &st->ext_module_namespace,
+	    (void *)total, NULL))
+		error(FATAL, "module namespace malloc: %s\n", strerror(errno));
+
+	if ((st->load_modules = (struct load_module *)calloc
+	    (st->mods_installed, sizeof(struct load_module))) == NULL)
+		error(FATAL, "load_module array malloc: %s\n", strerror(errno));
+
+	modbuf = GETBUF(SIZE(module));
+	modsymbuf = NULL;
+	m = mcnt = mod_next = 0;
+
+	for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) {
+
+		readmem(mod, KVADDR, modbuf, SIZE(module),
+			"module buffer", FAULT_ON_ERROR);
+
+		syms = ULONG(modbuf + OFFSET(module_syms));
+		gpl_syms = ULONG(modbuf + OFFSET(module_gpl_syms));
+		nsyms = UINT(modbuf + OFFSET(module_num_syms));
+		ngplsyms = UINT(modbuf + OFFSET(module_num_gpl_syms));
+
+		nksyms = UINT(modbuf + OFFSET(module_num_symtab));
+
+		mod_name = modbuf + OFFSET(module_name);
+
+		lm = &st->load_modules[m++];
+		BZERO(lm, sizeof(struct load_module));
+
+		size = 0;
+		for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
+			lm->mem[i].base = ULONG(modbuf + OFFSET(module_mem) +
+						SIZE(module_memory) * i + OFFSET(module_memory_base));
+			lm->mem[i].size = UINT(modbuf + OFFSET(module_mem) +
+						SIZE(module_memory) * i + OFFSET(module_memory_size));
+			if (i < MOD_INIT_TEXT)
+				size += lm->mem[i].size;
+		}
+		/* mem[MOD_TEXT].base for now */
+		lm->mod_base = lm->mem[MOD_TEXT].base;
+		/* The entire module size */
+		lm->mod_size = size;
+		lm->module_struct = mod;
+
+		if (strlen(mod_name) < MAX_MOD_NAME)
+			strcpy(lm->mod_name, mod_name);
+		else {
+			error(INFO, "module name greater than MAX_MOD_NAME: %s\n", mod_name);
+			strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1);
+		}
+		if (CRASHDEBUG(3))
+			fprintf(fp, "%lx (%lx): %s syms: %d gplsyms: %d ksyms: %ld\n",
+				mod, lm->mod_base, lm->mod_name, nsyms, ngplsyms, nksyms);
+
+		lm->mod_flags = MOD_EXT_SYMS;
+		lm->mod_ext_symcnt = mcnt;
+
+		lm->mod_text_start = lm->mod_base;
+		lm->mod_etext_guess = lm->mod_base + lm->mem[MOD_TEXT].size;
+
+		lm->mod_init_module_ptr = lm->mem[MOD_INIT_TEXT].base;
+		lm->mod_init_size = lm->mem[MOD_INIT_TEXT].size; /* tentative.. */
+		lm->mod_init_text_size = lm->mem[MOD_INIT_TEXT].size;
+
+		if (VALID_MEMBER(module_percpu))
+			lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu));
+
+		lm_mcnt = mcnt;
+		for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
+			if (!lm->mem[i].base)
+				continue;
+
+			st->ext_module_symtable[mcnt].value = lm->mem[i].base;
+			st->ext_module_symtable[mcnt].type = 'm';
+			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
+			sprintf(buf2, "%s%s", module_start_tags[i], mod_name);
+			namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace,
+				&st->ext_module_symtable[mcnt], buf2);
+			lm_mcnt = mcnt;
+			mcnt++;
+
+			if (i >= MOD_INIT_TEXT)
+				lm->mod_flags |= MOD_INIT;
+		}
+
+		if (nsyms && !IN_MODULE(syms, lm)) {
+			error(WARNING,
+			    "[%s] module.syms outside of module " "address space (%lx)\n\n",
+				lm->mod_name, syms);
+			nsyms = 0;
+		}
+
+		if (nsyms) {
+			modsymbuf = GETBUF(kernel_symbol_size*nsyms);
+			readmem((ulong)syms, KVADDR, modsymbuf,
+				nsyms * kernel_symbol_size,
+				"module symbols", FAULT_ON_ERROR);
+		}
+
+		for (i = first = last = 0; i < nsyms; i++) {
+			modsym = (union kernel_symbol *)
+			    (modsymbuf + (i * kernel_symbol_size));
+			if (!first
+			    || first > modsym_name(syms, modsym, i))
+				first = modsym_name(syms, modsym, i);
+			if (modsym_name(syms, modsym, i) > last)
+				last = modsym_name(syms, modsym, i);
+		}
+
+		if (last > first) {
+			/* The buffer should not go over the block. */
+			ulong end = module_mem_end(first, lm);
+
+			strbuflen = (last-first) + BUFSIZE;
+			if ((first + strbuflen) >= end) {
+				strbuflen = end - first;
+
+			}
+			strbuf = GETBUF(strbuflen);
+
+			if (!readmem(first, KVADDR, strbuf, strbuflen,
+			    "module symbol strings", RETURN_ON_ERROR)) {
+				FREEBUF(strbuf);
+				strbuf = NULL;
+			}
+		} else
+			strbuf = NULL;
+
+
+		for (i = 0; i < nsyms; i++) {
+			modsym = (union kernel_symbol *)(modsymbuf + (i * kernel_symbol_size));
+
+			BZERO(buf1, BUFSIZE);
+
+			if (strbuf)
+				strcpy(buf1, &strbuf[modsym_name(syms, modsym, i) - first]);
+			else
+				read_string(modsym_name(syms, modsym, i), buf1, BUFSIZE-1);
+
+			if (strlen(buf1)) {
+				st->ext_module_symtable[mcnt].value =
+					modsym_value(syms, modsym, i);
+				st->ext_module_symtable[mcnt].type = '?';
+				st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
+				strip_module_symbol_end(buf1);
+				strip_symbol_end(buf1, NULL);
+				namespace_ctl(NAMESPACE_INSTALL,
+				    &st->ext_module_namespace,
+				    &st->ext_module_symtable[mcnt], buf1);
+
+				mcnt++;
+			}
+		}
+
+		if (modsymbuf) {
+			FREEBUF(modsymbuf);
+			modsymbuf = NULL;
+		}
+
+		if (strbuf)
+			FREEBUF(strbuf);
+
+		if (ngplsyms) {
+			modsymbuf = GETBUF(kernel_symbol_size * ngplsyms);
+			readmem((ulong)gpl_syms, KVADDR, modsymbuf,
+				ngplsyms * kernel_symbol_size,
+				"module gpl symbols", FAULT_ON_ERROR);
+		}
+
+		for (i = first = last = 0; i < ngplsyms; i++) {
+			modsym = (union kernel_symbol *)
+			    (modsymbuf + (i * kernel_symbol_size));
+			if (!first
+			    || first > modsym_name(gpl_syms, modsym, i))
+				first = modsym_name(gpl_syms, modsym, i);
+			if (modsym_name(gpl_syms, modsym, i) > last)
+				last = modsym_name(gpl_syms, modsym, i);
+		}
+
+		if (last > first) {
+			ulong end = module_mem_end(first, lm);
+
+			strbuflen = (last-first) + BUFSIZE;
+			if ((first + strbuflen) >= end) {
+				strbuflen = end - first;
+
+			}
+			strbuf = GETBUF(strbuflen);
+
+			if (!readmem(first, KVADDR, strbuf, strbuflen,
+			    "module gpl symbol strings", RETURN_ON_ERROR)) {
+				FREEBUF(strbuf);
+				strbuf = NULL;
+			}
+		} else
+			strbuf = NULL;
+
+		for (i = 0; i < ngplsyms; i++) {
+			modsym = (union kernel_symbol *) (modsymbuf + (i * kernel_symbol_size));
+
+			BZERO(buf1, BUFSIZE);
+
+			if (strbuf)
+				strcpy(buf1, &strbuf[modsym_name(gpl_syms, modsym, i) - first]);
+			else
+				read_string(modsym_name(gpl_syms, modsym, i), buf1, BUFSIZE-1);
+
+			if (strlen(buf1)) {
+				st->ext_module_symtable[mcnt].value =
+					modsym_value(gpl_syms, modsym, i);
+				st->ext_module_symtable[mcnt].type = '?';
+				st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
+				strip_module_symbol_end(buf1);
+				strip_symbol_end(buf1, NULL);
+				namespace_ctl(NAMESPACE_INSTALL,
+				    &st->ext_module_namespace,
+				    &st->ext_module_symtable[mcnt], buf1);
+
+				mcnt++;
+			}
+		}
+
+		if (modsymbuf) {
+			FREEBUF(modsymbuf);
+			modsymbuf = NULL;
+		}
+
+		if (strbuf)
+			FREEBUF(strbuf);
+
+		/*
+		 *  If the module was compiled with kallsyms, add them in.
+		 */
+		switch (kt->flags & (KALLSYMS_V1|KALLSYMS_V2))
+		{
+		case KALLSYMS_V1:  /* impossible, I hope... */
+			mcnt += store_module_kallsyms_v1(lm, lm_mcnt, mcnt, modbuf);
+			break;
+		case KALLSYMS_V2:
+			mcnt += store_module_kallsyms_v2(lm, lm_mcnt, mcnt, modbuf);
+			break;
+		}
+
+		for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
+			if (!lm->mem[i].base)
+				continue;
+
+			st->ext_module_symtable[mcnt].value = lm->mem[i].base + lm->mem[i].size;
+			st->ext_module_symtable[mcnt].type = 'm';
+			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
+			sprintf(buf2, "%s%s", module_end_tags[i], mod_name);
+			namespace_ctl(NAMESPACE_INSTALL,
+				&st->ext_module_namespace,
+				&st->ext_module_symtable[mcnt], buf2);
+			mcnt++;
+		}
+
+		lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt;
+
+		if (!lm->mod_etext_guess)
+			find_mod_etext(lm);
+
+		NEXT_MODULE(mod_next, modbuf);
+	}
+
+	FREEBUF(modbuf);
+
+	st->ext_module_symcnt = mcnt;
+	st->ext_module_symend = &st->ext_module_symtable[mcnt];
+
+	namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace,
+		st->ext_module_symtable, st->ext_module_symend);
+
+	qsort(st->ext_module_symtable, mcnt, sizeof(struct syment),
+		compare_syms);
+
+	/* not sure whether this sort is meaningful anymore. */
+	qsort(st->load_modules, m, sizeof(struct load_module), compare_mods);
+
+	for (m = 0; m < st->mods_installed; m++) {
+		lm = &st->load_modules[m];
+
+		/* TODO: make more efficient */
+		for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
+			if (!lm->mem[i].base)
+				continue;
+
+			sprintf(buf1, "%s%s", module_start_tags[i], lm->mod_name);
+			sprintf(buf2, "%s%s", module_end_tags[i], lm->mod_name);
+
+			for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) {
+				if (STREQ(sp->name, buf1)) {
+					lm->symtable[i] = sp;
+					break;
+				}
+			}
+			for ( ; sp < st->ext_module_symend; sp++) {
+				if (STREQ(sp->name, buf2)) {
+					lm->symend[i] = sp;
+					break;
+				}
+			}
+
+			if (lm->symtable[i] && lm->symend[i])
+				mod_symtable_hash_install_range(lm->symtable[i], lm->symend[i]);
+		}
+	}
+
+	st->flags |= MODULE_SYMS;
+
+	/* probably not needed anymore */
+	if (symbol_query("__insmod_", NULL, NULL))
+		st->flags |= INSMOD_BUILTIN;
+
+	if (mcnt > total)
+		error(FATAL, "store_module_symbols_v3: total: %ld mcnt: %d\n", total, mcnt);
+}
+
 void
 store_module_symbols_v2(ulong total, int mods_installed)
 {
@@ -2384,6 +2767,7 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
         int mcnt;
         int mcnt_idx;
 	char *module_buf_init = NULL;
+	ulong base, base_init, size, size_init;
 
 	if (!(kt->flags & KALLSYMS_V2))
 		return 0;
@@ -2394,9 +2778,22 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
         ns = &st->ext_module_namespace;
 	ec = &elf_common;
 
-        module_buf = GETBUF(lm->mod_size);
+	/* kallsyms data looks to be in MOD_DATA region. */
+	if (MODULE_MEMORY()) {
+		base = lm->mem[MOD_DATA].base;
+		size = lm->mem[MOD_DATA].size;
+		base_init = lm->mem[MOD_INIT_DATA].base;
+		size_init = lm->mem[MOD_INIT_DATA].size;
+	} else {
+		base = lm->mod_base;
+		size = lm->mod_size;
+		base_init = lm->mod_init_module_ptr;
+		size_init = lm->mod_init_size;
+	}
+
+	module_buf = GETBUF(size);
 
-        if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size,
+        if (!readmem(base, KVADDR, module_buf, size,
             "module (kallsyms)", RETURN_ON_ERROR|QUIET)) {
                 error(WARNING,"cannot access module kallsyms\n");
                 FREEBUF(module_buf);
@@ -2404,10 +2801,10 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
         }
 
 	if (lm->mod_init_size > 0) {
-		module_buf_init = GETBUF(lm->mod_init_size);
+		module_buf_init = GETBUF(size_init);
 
-		if (!readmem(lm->mod_init_module_ptr, KVADDR, module_buf_init, lm->mod_init_size,
-					"module init (kallsyms)", RETURN_ON_ERROR|QUIET)) {
+		if (!readmem(base_init, KVADDR, module_buf_init, size_init,
+				"module init (kallsyms)", RETURN_ON_ERROR|QUIET)) {
 			error(WARNING,"cannot access module init kallsyms\n");
 			FREEBUF(module_buf_init);
 		}
@@ -2429,9 +2826,9 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
 		return 0;
 	} 
 	if (IN_MODULE(ksymtab, lm))
-		locsymtab = module_buf + (ksymtab - lm->mod_base);
+		locsymtab = module_buf + (ksymtab - base);
 	else
-		locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr);
+		locsymtab = module_buf_init + (ksymtab - base_init);
 
 	kstrtab = ULONG(modbuf + OFFSET(module_strtab));
 	if (!IN_MODULE(kstrtab, lm) && !IN_MODULE_INIT(kstrtab, lm)) {
@@ -2444,9 +2841,9 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
 		return 0;
 	}
 	if (IN_MODULE(kstrtab, lm))
-		locstrtab = module_buf + (kstrtab - lm->mod_base);
+		locstrtab = module_buf + (kstrtab - base);
 	else
-		locstrtab = module_buf_init + (kstrtab - lm->mod_init_module_ptr);
+		locstrtab = module_buf_init + (kstrtab - base_init);
 
 	for (i = 1; i < nksyms; i++) {  /* ELF starts real symbols at 1 */
 		switch (BITS())
@@ -2461,11 +2858,8 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
 			break;
 		}
 
-		if (((ec->st_value < lm->mod_base) ||
-		    (ec->st_value >  (lm->mod_base + lm->mod_size))) &&
-		    ((ec->st_value < lm->mod_init_module_ptr) ||
-		    (ec->st_value > (lm->mod_init_module_ptr + lm->mod_init_size))))
-				continue;
+		if (!IN_MODULE(ec->st_value, lm) && !IN_MODULE_INIT(ec->st_value, lm))
+			continue;
 
 		if (ec->st_shndx == SHN_UNDEF)
                         continue;
@@ -3531,6 +3925,13 @@ dump_symbol_table(void)
 			(ulong)lm->mod_section_data,
 			lm->mod_section_data ? "" : "(not allocated)");
 
+		if (MODULE_MEMORY()) {
+			int j;
+			for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) {
+				fprintf(fp, "                mem[%d]: %lx (%x)\n",
+					j, lm->mem[j].base, lm->mem[j].size);
+			}
+		}
 
 		for (s = 0; s < lm->mod_sections; s++) {
 			fprintf(fp, 
@@ -9228,6 +9629,9 @@ dump_offset_table(char *spec, ulong makestruct)
 		OFFSET(module_strtab));
 	fprintf(fp, "                 module_percpu: %ld\n",
 		OFFSET(module_percpu));
+	fprintf(fp, "                    module_mem: %ld\n", OFFSET(module_mem));
+	fprintf(fp, "            module_memory_base: %ld\n", OFFSET(module_memory_base));
+	fprintf(fp, "            module_memory_size: %ld\n", OFFSET(module_memory_size));
 
 	fprintf(fp, "             module_sect_attrs: %ld\n",
 		OFFSET(module_sect_attrs));
@@ -10851,6 +11255,7 @@ dump_offset_table(char *spec, ulong makestruct)
 		SIZE(super_block)); 
 	fprintf(fp, "                       irqdesc: %ld\n", SIZE(irqdesc));
 	fprintf(fp, "                        module: %ld\n", SIZE(module));
+	fprintf(fp, "                 module_memory: %ld\n", SIZE(module_memory));
 	fprintf(fp, "              module_sect_attr: %ld\n", SIZE(module_sect_attr));
 	fprintf(fp, "                     list_head: %ld\n", SIZE(list_head));
 	fprintf(fp, "                    hlist_head: %ld\n", SIZE(hlist_head));
@@ -13520,3 +13925,52 @@ symbol_complete_match(const char *match, struct syment *sp_last)
 
 	return NULL;
 }
+
+static int
+_in_module(ulong addr, struct load_module *lm, int type)
+{
+	ulong base, size;
+	int i, last;
+
+	if (MODULE_MEMORY()) {
+		if (type == MOD_TEXT)
+			last = MOD_RO_AFTER_INIT;
+		else
+			last = MOD_INIT_RODATA;
+		for (i = type ; i <= last; i++) {
+			base = lm->mem[i].base;
+			size = lm->mem[i].size;
+			if (!base)
+				continue;
+			if ((addr >= base) && (addr < (base + size)))
+				return TRUE;
+		}
+		return FALSE;
+	}
+
+	if (type == MOD_TEXT) {
+		base = lm->mod_base;
+		size = lm->mod_size;
+	} else {
+		base = lm->mod_init_module_ptr;
+		size = lm->mod_init_size;
+	}
+	return ((addr >= base) && (addr < (base + size)));
+}
+
+/* Returns the end address of the module memory region. */
+static ulong
+module_mem_end(ulong addr, struct load_module *lm)
+{
+	ulong base, end;
+	int i;
+	for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
+		base = lm->mem[i].base;
+		if (!base)
+			continue;
+		end = base + lm->mem[i].size;
+		if ((addr >= base) && (addr < end))
+			return end;
+	}
+	return 0;
+}
-- 
2.31.1

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://listman.redhat.com/mailman/listinfo/crash-utility
Contribution Guidelines: https://github.com/crash-utility/crash/wiki




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux