/* * We only allocate and copy the strings needed by the parts of symtab * we keep. This is simple, but has the effect of making multiple * copies of duplicates. We could be more sophisticated, see * linux-kernel thread starting with * <73defb5e4bca04a6431392cc341112b1@localhost>.
*/ void layout_symtab(struct module *mod, struct load_info *info)
{
Elf_Shdr *symsect = info->sechdrs + info->index.sym;
Elf_Shdr *strsect = info->sechdrs + info->index.str; const Elf_Sym *src; unsignedint i, nsrc, ndst, strtab_size = 0; struct module_memory *mod_mem_data = &mod->mem[MOD_DATA]; struct module_memory *mod_mem_init_data = &mod->mem[MOD_INIT_DATA];
/* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC;
symsect->sh_entsize = module_get_offset_and_type(mod, MOD_INIT_DATA,
symsect, info->index.sym);
pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
/* Compute total space required for the core symbols' strtab. */ for (ndst = i = 0; i < nsrc; i++) { if (i == 0 || is_livepatch_module(mod) ||
is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
info->index.pcpu)) {
strtab_size += strlen(&info->strtab[src[i].st_name]) + 1;
ndst++;
}
}
/* Append room for core symbols at end of core part. */
info->symoffs = ALIGN(mod_mem_data->size, symsect->sh_addralign ?: 1);
info->stroffs = mod_mem_data->size = info->symoffs + ndst * sizeof(Elf_Sym);
mod_mem_data->size += strtab_size; /* Note add_kallsyms() computes strtab_size as core_typeoffs - stroffs */
info->core_typeoffs = mod_mem_data->size;
mod_mem_data->size += ndst * sizeof(char);
/* Put string table section at end of init part of module. */
strsect->sh_flags |= SHF_ALLOC;
strsect->sh_entsize = module_get_offset_and_type(mod, MOD_INIT_DATA,
strsect, info->index.str);
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
/* We'll tack temporary mod_kallsyms on the end. */
mod_mem_init_data->size = ALIGN(mod_mem_init_data->size,
__alignof__(struct mod_kallsyms));
info->mod_kallsyms_init_off = mod_mem_init_data->size;
/* * We use the full symtab and strtab which layout_symtab arranged to * be appended to the init section. Later we switch to the cut-down * core-only ones.
*/ void add_kallsyms(struct module *mod, conststruct load_info *info)
{ unsignedint i, ndst; const Elf_Sym *src;
Elf_Sym *dst; char *s;
Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; unsignedlong strtab_size; void *data_base = mod->mem[MOD_DATA].base; void *init_data_base = mod->mem[MOD_INIT_DATA].base; struct mod_kallsyms *kallsyms;
kallsyms->symtab = (void *)symsec->sh_addr;
kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); /* Make sure we get permanent strtab: don't use info->strtab. */
kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
kallsyms->typetab = init_data_base + info->init_typeoffs;
/* * Now populate the cut down core kallsyms for after init * and set types up while we still have access to sections.
*/
mod->core_kallsyms.symtab = dst = data_base + info->symoffs;
mod->core_kallsyms.strtab = s = data_base + info->stroffs;
mod->core_kallsyms.typetab = data_base + info->core_typeoffs;
strtab_size = info->core_typeoffs - info->stroffs;
src = kallsyms->symtab; for (ndst = i = 0; i < kallsyms->num_symtab; i++) {
kallsyms->typetab[i] = elf_type(src + i, info); if (i == 0 || is_livepatch_module(mod) ||
is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
info->index.pcpu)) {
ssize_t ret;
mod->core_kallsyms.typetab[ndst] =
kallsyms->typetab[i];
dst[ndst] = src[i];
dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
ret = strscpy(s, &kallsyms->strtab[src[i].st_name],
strtab_size); if (ret < 0) break;
s += ret + 1;
strtab_size -= ret + 1;
}
}
/* Set up to point into init section. */
rcu_assign_pointer(mod->kallsyms, kallsyms);
mod->core_kallsyms.num_symtab = ndst;
}
/* * Given a module and address, find the corresponding symbol and return its name * while providing its size and offset if needed.
*/ staticconstchar *find_kallsyms_symbol(struct module *mod, unsignedlong addr, unsignedlong *size, unsignedlong *offset)
{ unsignedint i, best = 0; unsignedlong nextval, bestval; struct mod_kallsyms *kallsyms = rcu_dereference(mod->kallsyms); struct module_memory *mod_mem;
/* At worse, next value is at end of module */ if (within_module_init(addr, mod))
mod_mem = &mod->mem[MOD_INIT_TEXT]; else
mod_mem = &mod->mem[MOD_TEXT];
/* * Scan for closest preceding symbol, and next symbol. (ELF * starts real symbols at 1).
*/ for (i = 1; i < kallsyms->num_symtab; i++) { const Elf_Sym *sym = &kallsyms->symtab[i]; unsignedlong thisval = kallsyms_symbol_value(sym);
if (sym->st_shndx == SHN_UNDEF) continue;
/* * We ignore unnamed symbols: they're uninformative * and inserted at a whim.
*/ if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
is_mapping_symbol(kallsyms_symbol_name(kallsyms, i))) continue;
if (thisval <= addr && thisval > bestval) {
best = i;
bestval = thisval;
} if (thisval > addr && thisval < nextval)
nextval = thisval;
}
if (!best) return NULL;
if (size)
*size = nextval - bestval; if (offset)
*offset = addr - bestval;
/* * For kallsyms to ask for address resolution. NULL means not found. Careful * not to lock to avoid deadlock on oopses, RCU is enough.
*/ int module_address_lookup(unsignedlong addr, unsignedlong *size, unsignedlong *offset, char **modname, constunsignedchar **modbuildid, char *namebuf)
{ constchar *sym; int ret = 0; struct module *mod;
guard(rcu)();
mod = __module_address(addr); if (mod) { if (modname)
*modname = mod->name; if (modbuildid) { #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
*modbuildid = mod->build_id; #else
*modbuildid = NULL; #endif
}
/* Given a module and name of symbol, find and return the symbol's value */ staticunsignedlong __find_kallsyms_symbol_value(struct module *mod, constchar *name)
{ unsignedint i; struct mod_kallsyms *kallsyms = rcu_dereference(mod->kallsyms);
for (i = 0; i < kallsyms->num_symtab; i++) { const Elf_Sym *sym = &kallsyms->symtab[i];
if (mod->state == MODULE_STATE_UNFORMED) continue;
ret = __find_kallsyms_symbol_value(mod, name); if (ret) return ret;
} return 0;
}
/* Look for this name: can be of form module:name. */ unsignedlong module_kallsyms_lookup_name(constchar *name)
{ /* Don't lock: we're in enough trouble already. */
guard(rcu)(); return __module_kallsyms_lookup_name(name);
}
for (i = 0; i < kallsyms->num_symtab; i++) { const Elf_Sym *sym = &kallsyms->symtab[i];
if (sym->st_shndx == SHN_UNDEF) continue;
ret = fn(data, kallsyms_symbol_name(kallsyms, i),
kallsyms_symbol_value(sym)); if (ret != 0) goto out;
}
/* * The given module is found, the subsequent modules do not * need to be compared.
*/ if (modname) break;
}
out:
mutex_unlock(&module_mutex); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.