Support "mod -s|-S" with introducing lm->load_sym{table,end}
but many functions like "mod -d|-D" are still not supported.
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
---
defs.h | 9 +-
gdb-10.2.patch | 16 +++
symbols.c | 350 ++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 340 insertions(+), 35 deletions(-)
diff --git a/defs.h b/defs.h
index 95e44e8cb87c..b2478b6741ec 100644
--- a/defs.h
+++ b/defs.h
@@ -2925,6 +2925,7 @@ struct mod_section_data {
ulong size;
int priority;
int flags;
+ ulong addr;
Is it possible to reuse the member offset in module memory patches? I noticed that the offset is not used in the calculate_load_order_v3(). If it is doable to reuse the offset, that may avoid modifying the gdb patch? I haven't investigated the details.
};
/* This is unlikely to change, so imported from kernel for now. */
@@ -2982,8 +2983,12 @@ struct load_module {
/* 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];
+ struct syment **symtable;
+ struct syment **symend;
Some similar member definitions are in the struct symbol_table_data and struct load_module, it looks confusing to me. But I'm not sure if it is better to move some of them to the struct symbol_talbe_data.
+ struct syment *ext_symtable[MOD_MEM_NUM_TYPES];
+ struct syment *ext_symend[MOD_MEM_NUM_TYPES];
+ struct syment *load_symtable[MOD_MEM_NUM_TYPES];
+ struct syment *load_symend[MOD_MEM_NUM_TYPES];
int address_order[MOD_MEM_NUM_TYPES];
int nr_mems;
};
diff --git a/gdb-10.2.patch b/gdb-10.2.patch
index 835aae9859be..b3f6d8b086eb 100644
--- a/gdb-10.2.patch
+++ b/gdb-10.2.patch
@@ -3120,3 +3120,19 @@ exit 0
return result;
}
+--- gdb-10.2/gdb/symtab.c.orig
++++ gdb-10.2/gdb/symtab.c
+@@ -7515,8 +7515,11 @@ gdb_add_symbol_file(struct gnu_request *
+ secname = lm->mod_section_data[i].name;
+ if ((lm->mod_section_data[i].flags & SEC_FOUND) &&
+ !STREQ(secname, ".text")) {
+- sprintf(buf, " -s %s 0x%lx", secname,
+- lm->mod_section_data[i].offset + lm->mod_base);
++ if (lm->mod_section_data[i].addr)
++ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr);
++ else
++ sprintf(buf, " -s %s 0x%lx", secname,
++ lm->mod_section_data[i].offset + lm->mod_base);
+ strcat(req->buf, buf);
+ }
+ }
diff --git a/symbols.c b/symbols.c
index ef00ce0b79ca..8343081f51f7 100644
--- a/symbols.c
+++ b/symbols.c
@@ -50,6 +50,8 @@ static void store_section_data(struct load_module *, bfd *, asection *);
static void calculate_load_order_v1(struct load_module *, bfd *);
static void calculate_load_order_v2(struct load_module *, bfd *, int,
void *, long, unsigned int);
+static void calculate_load_order_v3(struct load_module *, bfd *, int,
+ void *, long, unsigned int);
static void check_insmod_builtin(struct load_module *, int, ulong *);
static int is_insmod_builtin(struct load_module *, struct syment *);
struct load_module;
@@ -2288,20 +2290,22 @@ store_module_symbols_v3(ulong total, int mods_installed)
for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) {
if (STREQ(sp->name, buf1)) {
- lm->symtable[i] = sp;
+ lm->ext_symtable[i] = sp;
break;
}
}
for ( ; sp < st->ext_module_symend; sp++) {
if (STREQ(sp->name, buf2)) {
- lm->symend[i] = sp;
+ lm->ext_symend[i] = sp;
break;
}
}
- if (lm->symtable[i] && lm->symend[i])
- mod_symtable_hash_install_range(lm->symtable[i], lm->symend[i]);
+ if (lm->ext_symtable[i] && lm->ext_symend[i])
+ mod_symtable_hash_install_range(lm->ext_symtable[i], lm->ext_symend[i]);
}
+ lm->symtable = lm->ext_symtable;
+ lm->symend = lm->ext_symend;
}
st->flags |= MODULE_SYMS;
@@ -4090,15 +4094,27 @@ dump_symbol_table(void)
for (j = 0; j < lm->nr_mems; j++)
fprintf(fp, " %d", lm->address_order[j]);
fprintf(fp, "\n");
+ fprintf(fp, " symtable: %lx\n", (ulong)lm->symtable);
+ fprintf(fp, " ext_symtable: %lx\n", (ulong)lm->ext_symtable);
+ for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) {
+ fprintf(fp, " ext_symtable[%d]: %lx - %lx\n",
+ j, (ulong)lm->ext_symtable[j], (ulong)lm->ext_symend[j]);
+ }
+ fprintf(fp, " load_symtable: %lx\n", (ulong)lm->load_symtable);
+ for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) {
+ fprintf(fp, " load_symtable[%d]: %lx - %lx\n",
+ j, (ulong)lm->load_symtable[j], (ulong)lm->load_symend[j]);
+ }
}
for (s = 0; s < lm->mod_sections; s++) {
fprintf(fp,
- " %12s prio: %x flags: %05x offset: %-8lx size: %lx\n",
+ " %20s prio: %x flags: %08x offset: %-8lx addr: %-16lx size: %lx\n",
lm->mod_section_data[s].name,
lm->mod_section_data[s].priority,
lm->mod_section_data[s].flags,
lm->mod_section_data[s].offset,
+ lm->mod_section_data[s].addr,
lm->mod_section_data[s].size);
}
@@ -12122,6 +12138,7 @@ store_section_data(struct load_module *lm, bfd *bfd, asection *section)
}
lm->mod_section_data[i].size = bfd_section_size(section);
lm->mod_section_data[i].offset = 0;
+ lm->mod_section_data[i].addr = 0;
if (strlen(name) < MAX_MOD_SEC_NAME)
strcpy(lm->mod_section_data[i].name, name);
else
@@ -12367,6 +12384,133 @@ calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic,
}
}
+/* Linux 6.4 and later */
+static void
+calculate_load_order_v3(struct load_module *lm, bfd *bfd, int dynamic,
+ void *minisyms, long symcount, unsigned int size)
+{
+ struct syment *s1, *s2;
+ ulong sec_start;
+ bfd_byte *from, *fromend;
+ asymbol *store;
+ asymbol *sym;
+ symbol_info syminfo;
+ char *secname;
+ int i, j;
+
+ if ((store = bfd_make_empty_symbol(bfd)) == NULL)
+ error(FATAL, "bfd_make_empty_symbol() failed\n");
+
+ for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) {
+
The above for-loop is frequently used in these patches, can we introduce the following macro definition from the kernel?
#define for_each_mod_mem_type(type) \
for (enum mod_mem_type (type) = 0; \
(type) < MOD_MEM_NUM_TYPES; (type)++)
Looks more convenient to me.
+ s1 = lm->symtable[j];
+ s2 = lm->symend[j];
+ while (s1 < s2) {
+
+ if (MODULE_PSEUDO_SYMBOL(s1)) {
+ s1++;
+ continue;
+ }
+
+ /* Skip over symbols whose sections have been identified. */
+ for (i = 0; i < lm->mod_sections; i++) {
+ if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0)
+ continue;
+
+ if (s1->value >= lm->mod_section_data[i].addr
+ && s1->value < lm->mod_section_data[i].addr
+ + lm->mod_section_data[i].size) {
+ break;
+ }
+ }
+
+ /* Matched one of the sections. Skip symbol. */
+ if (i < lm->mod_sections) {
+ if (CRASHDEBUG(2)) {
+ fprintf(fp, "skip %lx %s %s\n", s1->value, s1->name,
+ lm->mod_section_data[i].name);
+ }
+ s1++;
+ continue;
+ }
+
+ /* Find the symbol in the object file. */
+ from = (bfd_byte *) minisyms;
+ fromend = from + symcount * size;
+ secname = NULL;
+ for (; from < fromend; from += size) {
+ if ((sym = bfd_minisymbol_to_symbol(bfd, dynamic, from,
+ store)) == NULL)
+ error(FATAL,
+ "bfd_minisymbol_to_symbol() failed\n");
+
+ bfd_get_symbol_info(bfd, sym, &syminfo);
+ if (CRASHDEBUG(3)) {
+ fprintf(fp,"matching sym %s %lx against bfd %s %lx\n",
+ s1->name, (long) s1->value, syminfo.name,
+ (long) syminfo.value);
+ }
+ if (strcmp(syminfo.name, s1->name) == 0) {
+ secname = (char *)bfd_section_name(sym->section);
+ break;
+ }
+
+ }
+ if (secname == NULL) {
+ if (CRASHDEBUG(1)) {
+ fprintf(fp, "symbol %s not found in module\n", s1->name);
+ }
+ s1++;
+ continue;
+ }
+
+ /* Match the section it came in. */
+ for (i = 0; i < lm->mod_sections; i++) {
+ if (STREQ(lm->mod_section_data[i].name, secname)) {
+ break;
+ }
+ }
+
+ if (i == lm->mod_sections) {
+ fprintf(fp, "?? Section %s not found for symbol %s\n",
+ secname, s1->name);
+ s1++;
+ continue;
+ }
+
+ if (lm->mod_section_data[i].flags & SEC_FOUND) {
+ s1++;
+ continue;
+ }
+
+ /* Update the offset information for the section */
+ sec_start = s1->value - syminfo.value;
+ //lm->mod_section_data[i].offset = sec_start - lm->mem[j].base;
+ /* keep the address instead of offset */
+ lm->mod_section_data[i].addr = sec_start;
+ lm->mod_section_data[i].flags |= SEC_FOUND;
+
+ if (CRASHDEBUG(2)) {
+ fprintf(fp, "update sec offset sym %s @ %lx val %lx section %s\n",
+ s1->name, s1->value, (ulong)syminfo.value, secname);
+ }
+
+ if (strcmp(secname, ".text") == 0)
+ lm->mod_text_start = sec_start;
+
+ if (strcmp(secname, ".bss") == 0)
+ lm->mod_bss_start = sec_start;
+
+ if (strcmp(secname, ".data") == 0)
+ lm->mod_data_start = sec_start;
+
+ if (strcmp(secname, ".rodata") == 0)
+ lm->mod_rodata_start = sec_start;
+ s1++;
+ }
+ }
+}
+
/*
* Later versons of insmod store basic address information of each
* module in a format that looks like the following example of the
@@ -12561,6 +12705,7 @@ add_symbol_file(struct load_module *lm)
req = &request;
BZERO(req, sizeof(struct gnu_request));
+ /* TODO: ugh, module section data structures changed? */
if ((lm->mod_flags & MOD_KALLSYMS) &&
add_symbol_file_kallsyms(lm, req))
return TRUE;
@@ -12572,8 +12717,11 @@ add_symbol_file(struct load_module *lm)
(!STREQ(secname, ".text") &&
!STREQ(secname, ".data.percpu") &&
!STREQ(secname, ".data..percpu"))) {
- sprintf(buf, " -s %s 0x%lx", secname,
- lm->mod_section_data[i].offset + lm->mod_base);
+ if (MODULE_MEMORY())
+ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr);
+ else
+ sprintf(buf, " -s %s 0x%lx", secname,
+ lm->mod_section_data[i].offset + lm->mod_base);
len += strlen(buf);
}
}
@@ -12914,24 +13062,43 @@ static struct syment *
kallsyms_module_symbol(struct load_module *lm, symbol_info *syminfo)
{
struct syment *sp, *spx;
- int cnt;
+ int i, cnt;
if (!(lm->mod_flags & MOD_KALLSYMS))
return NULL;
sp = NULL;
cnt = 0;
- for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) {
- if (!STREQ(spx->name, syminfo->name))
- continue;
- if (spx->cnt) {
- cnt++;
- continue;
- }
+ if (MODULE_MEMORY()) {
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
+ if (!lm->ext_symtable[i])
+ continue;
+ for (spx = lm->ext_symtable[i]; spx <= lm->ext_symend[i]; spx++) {
+ if (!STREQ(spx->name, syminfo->name))
+ continue;
+ if (spx->cnt) {
+ cnt++;
+ continue;
+ }
- spx->cnt++;
- sp = spx;
- break;
+ spx->cnt++;
+ sp = spx;
+ break;
+ }
+ }
+ } else {
+ for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) {
+ if (!STREQ(spx->name, syminfo->name))
+ continue;
+ if (spx->cnt) {
+ cnt++;
+ continue;
+ }
+
+ spx->cnt++;
+ sp = spx;
+ break;
+ }
}
if (CRASHDEBUG(2)) {
@@ -12968,7 +13135,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
char *nameptr, *secname;
long index;
long symalloc;
- int found;
+ int found = FALSE;
if ((store = bfd_make_empty_symbol(bfd)) == NULL)
error(FATAL, "bfd_make_empty_symbol() failed\n");
@@ -13025,8 +13192,17 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
lm->mod_rodata_start = lm->mod_bss_start = 0;
lm->mod_load_symcnt = 0;
lm->mod_sections = 0;
- for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++)
- spx->cnt = 0;
+ if (MODULE_MEMORY()) {
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
+ if (!lm->ext_symtable[i])
+ continue;
+ for (spx = lm->ext_symtable[i]; spx <= lm->ext_symend[i]; spx++)
+ spx->cnt = 0;
+ }
+ } else {
+ for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++)
+ spx->cnt = 0;
+ }
sp = lm->mod_load_symtable;
if (!(lm->mod_section_data = (struct mod_section_data *)
@@ -13037,7 +13213,17 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS);
- if (kt->flags & KMOD_V1)
+ /* for debug
+ for (i = 0; i < lm->mod_sections; i++) {
+ struct mod_section_data *m = &lm->mod_section_data[i];
+ fprintf(fp, "%d: name %s offset %ld size %ld flags %x\n",
+ i, m->name, m->offset, m->size, m->flags);
+ }
+ */
+
+ if (MODULE_MEMORY())
+ calculate_load_order_v3(lm, bfd, dynamic, minisyms, symcount, size);
+ else if (kt->flags & KMOD_V1)
calculate_load_order_v1(lm, bfd);
else
calculate_load_order_v2(lm, bfd, dynamic, minisyms,
@@ -13146,7 +13332,10 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
syminfo.value += lm->mod_percpu;
found = TRUE;
} else {
- syminfo.value += lm->mod_section_data[i].offset + lm->mod_base;
+ if (MODULE_MEMORY())
+ syminfo.value += lm->mod_section_data[i].addr;
+ else
+ syminfo.value += lm->mod_section_data[i].offset + lm->mod_base;
found = TRUE;
}
}
@@ -13181,6 +13370,51 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
* syminfo data types accepted above, plus the two pseudo symbols.
* Note that the new syment name pointers haven't been resolved yet.
*/
+ if (MODULE_MEMORY()) {
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
+ if (!lm->ext_symtable[i])
+ continue;
+ for (spx = lm->ext_symtable[i]; spx <= lm->ext_symend[i]; spx++) {
+ found = FALSE;
+ for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) {
+ index = (long)sp->name;
+ nameptr = &lm->mod_load_namespace.address[index];
+ if (STREQ(spx->name, nameptr)) {
+ found = TRUE;
+ if (spx->value == sp->value) {
+ if (CRASHDEBUG(2))
+ fprintf(fp, "%s: %s matches!\n",
+ lm->mod_name, nameptr);
+ } else {
+ if (CRASHDEBUG(2))
+ fprintf(fp,
+ "[%s] %s: %lx != extern'd value: %lx\n",
+ lm->mod_name,
+ nameptr, sp->value,
+ spx->value);
+ }
+ break;
+ }
+ }
+ if (!found) {
+ if (CRASHDEBUG(2))
+ fprintf(fp, "append ext %s (%lx)\n", spx->name, spx->value);
+ /* append it here... */
+ namespace_ctl(NAMESPACE_INSTALL,
+ &lm->mod_load_namespace,
+ lm->mod_load_symend, spx->name);
+
+ lm->mod_load_symend->value = spx->value;
+ lm->mod_load_symend->type = spx->type;
+ lm->mod_load_symend->flags |= MODULE_SYMBOL;
+ lm->mod_load_symend++;
+ lm->mod_load_symcnt++;
+ }
+ }
+ }
+ goto append_section_symbols;
+ }
+
for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) {
found = FALSE;
for (sp = lm->mod_load_symtable;
@@ -13223,6 +13457,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
}
}
+append_section_symbols:
/*
* Append helpful pseudo symbols about found out sections.
* Use 'S' as its type which is never seen in existing symbols.
@@ -13232,8 +13467,11 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
if (!(lm->mod_section_data[i].flags & SEC_FOUND))
continue;
/* Section start */
- lm->mod_load_symend->value = lm->mod_base +
- lm->mod_section_data[i].offset;
+ if (MODULE_MEMORY())
+ lm->mod_load_symend->value = lm->mod_section_data[i].addr;
+ else
+ lm->mod_load_symend->value = lm->mod_base +
+ lm->mod_section_data[i].offset;
lm->mod_load_symend->type = 'S';
lm->mod_load_symend->flags |= MODULE_SYMBOL;
sprintf(name, "_MODULE_SECTION_START [%s]",
@@ -13244,9 +13482,12 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
lm->mod_load_symcnt++;
/* Section end */
- lm->mod_load_symend->value = lm->mod_base +
- lm->mod_section_data[i].offset +
- lm->mod_section_data[i].size;
+ if (MODULE_MEMORY())
+ lm->mod_load_symend->value = lm->mod_section_data[i].addr;
+ else
+ lm->mod_load_symend->value = lm->mod_base +
+ lm->mod_section_data[i].offset;
+ lm->mod_load_symend->value += lm->mod_section_data[i].size;
lm->mod_load_symend->type = 'S';
lm->mod_load_symend->flags |= MODULE_SYMBOL;
sprintf(name, "_MODULE_SECTION_END [%s]",
@@ -13263,16 +13504,59 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
qsort(lm->mod_load_symtable, lm->mod_load_symcnt, sizeof(struct syment),
compare_syms);
+ /* keep load symtable addresses to lm->load_symtable[] */
+ /* TODO: make more efficient */
+ for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) {
+ char buf1[BUFSIZE], buf2[BUFSIZE];
+
+ if (CRASHDEBUG(1))
+ fprintf(fp, "DEBUG: value %16lx name %s\n", sp->value, sp->name);
+ if (!MODULE_PSEUDO_SYMBOL(sp))
+ continue;
+
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
+ 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);
+
+ if (STREQ(sp->name, buf1)) {
+ lm->load_symtable[i] = sp;
+ break;
+ } else if (STREQ(sp->name, buf2)) {
+ lm->load_symend[i] = sp;
+ break;
+ }
+ }
+ }
+
+ /* TODO: add check for 6.4 and later */
lm->mod_load_symend--;
- if (!MODULE_END(lm->mod_load_symend) &&
+ if (!MODULE_MEMORY() && !MODULE_END(lm->mod_load_symend) &&
!IN_MODULE_PERCPU(lm->mod_load_symend->value, lm))
error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n",
lm->mod_name, lm->mod_load_symend->name, lm->mod_name);
- mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend);
- lm->mod_symtable = lm->mod_load_symtable;
- lm->mod_symend = lm->mod_load_symend;
- mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
+ if (MODULE_MEMORY()) {
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
+ if (!lm->symtable[i])
+ continue;
+ mod_symtable_hash_remove_range(lm->symtable[i], lm->symend[i]);
+ }
+ lm->symtable = lm->load_symtable;
+ lm->symend = lm->load_symend;
+ for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) {
Ditto.
Thanks.
Lianbo
+ if (!lm->symtable[i])
+ continue;
+ mod_symtable_hash_install_range(lm->symtable[i], lm->symend[i]);
+ }
+ } else {
+ mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend);
+ lm->mod_symtable = lm->mod_load_symtable;
+ lm->mod_symend = lm->mod_load_symend;
+ mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
+ }
lm->mod_flags &= ~MOD_EXT_SYMS;
lm->mod_flags |= MOD_LOAD_SYMS;
--
2.31.1