This methods are used by AKKstub-ARM Kernel Kstub.

We need to implement an automatic kernel-method mock that streamlines the
mocking process during kernel-method testing and enables fully automated
operations. This mechanism must traverse the binary instructions of the
target function in memory, locate the appropriate instruction, and replace
it. To perform the traversal, it must know the function’s entry address and
the size of its instruction range.

Bug:
Change-Id: I5a318f762d4412e70b0c8dcf2dfed326312bdc65
Signed-off-by: Yunjin Kim <[email protected]>
---
 include/linux/kallsyms.h |  2 ++
 include/linux/module.h   |  2 ++
 kernel/kallsyms.c        | 38 ++++++++++++++++++++++++++
 kernel/module/kallsyms.c | 58 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 100 insertions(+)

diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 1c6a6c1704d8..ec59f25259f2 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -78,6 +78,8 @@ int kallsyms_on_each_match_symbol(int (*fn)(void *, unsigned 
long),
 /* Lookup the address for a symbol. Returns 0 if not found. */
 unsigned long kallsyms_lookup_name(const char *name);

+unsigned long kallsyms_lookup_address_and_size(const char *name, unsigned long 
*address, unsigned long * size);
+
 extern int kallsyms_lookup_size_offset(unsigned long addr,
                                  unsigned long *symbolsize,
                                  unsigned long *offset);
diff --git a/include/linux/module.h b/include/linux/module.h
index 5beb39d56197..47fb46bd1b92 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -976,6 +976,8 @@ int module_get_kallsym(unsigned int symnum, unsigned long 
*value, char *type,
 /* Look for this name: can be of form module:name. */
 unsigned long module_kallsyms_lookup_name(const char *name);

+unsigned long module_kallsyms_lookup_address_and_size(const char *name, 
unsigned long *address, unsigned long *size);
+
 unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);

 #else  /* CONFIG_MODULES && CONFIG_KALLSYMS */
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index a9a0ca605d4a..5533816794da 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -160,6 +160,22 @@ unsigned long kallsyms_sym_address(int idx)
        return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
 }

+unsigned long kallsyms_sym_address_and_size(int idx, unsigned long *size)
+{
+       /* values are unsigned offsets if --absolute-percpu is not in effect */
+       *size = kallsyms_offsets[idx+1] - kallsyms_offsets[idx];
+
+       if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
+               return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
+
+       /* ...otherwise, positive offsets are absolute values */
+       if (kallsyms_offsets[idx] >= 0)
+               return kallsyms_offsets[idx];
+
+       /* ...and negative offsets are relative to kallsyms_relative_base - 1 */
+       return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
+}
+
 static unsigned int get_symbol_seq(int index)
 {
        unsigned int i, seq = 0;
@@ -242,6 +258,27 @@ unsigned long kallsyms_lookup_name(const char *name)

        return module_kallsyms_lookup_name(name);
 }
+EXPORT_SYMBOL(kallsyms_lookup_name);
+
+unsigned long kallsyms_lookup_address_and_size(const char *name, unsigned long 
*address, unsigned long * size)
+{
+       int ret;
+       unsigned int i;
+
+       /* Skip the search for empty string. */
+       if (!*name)
+               return 0;
+
+       ret = kallsyms_lookup_names(name, &i, NULL);
+       if (!ret){
+               *address = kallsyms_sym_address_and_size(get_symbol_seq(i), 
size);
+               return *address;
+       }
+
+       //return module_kallsyms_lookup_name(name);
+       return module_kallsyms_lookup_address_and_size(name, address, size);
+}
+EXPORT_SYMBOL(kallsyms_lookup_address_and_size);

 /*
  * Iterate over all symbols in vmlinux.  For symbols from modules use
@@ -430,6 +467,7 @@ int lookup_symbol_name(unsigned long addr, char *symname)
        /* See if it's in a module. */
        return lookup_module_symbol_name(addr, symname);
 }
+EXPORT_SYMBOL(lookup_symbol_name);

 /* Look up a kernel symbol and return it in a text buffer. */
 static int __sprint_symbol(char *buffer, unsigned long address,
diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
index bf65e0c3c86f..e8552f5e64c8 100644
--- a/kernel/module/kallsyms.c
+++ b/kernel/module/kallsyms.c
@@ -462,6 +462,64 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        return ret;
 }

+static unsigned long __find_kallsyms_symbol_address_and_size_value(struct 
module *mod, const char *name, unsigned long *address, unsigned long* size)
+{
+       unsigned int i;
+       struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
+       unsigned long ret = 0;
+
+       for (i = 0; i < kallsyms->num_symtab; i++) {
+               const Elf_Sym *sym = &kallsyms->symtab[i];
+
+               if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
+                   sym->st_shndx != SHN_UNDEF){
+                       ret = kallsyms_symbol_value(sym);
+                       *address = ret;
+                       *size = sym->st_size;
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static unsigned long __module_kallsyms_lookup_address_and_size(const char 
*name, unsigned long *address, unsigned long *size)
+{
+       struct module *mod;
+       char *colon;
+
+       colon = strnchr(name, MODULE_NAME_LEN, ':');
+       if (colon) {
+               mod = find_module_all(name, colon - name, false);
+               if (mod)
+                       return 
__find_kallsyms_symbol_address_and_size_value(mod, colon + 1, address, size);
+               return 0;
+       }
+
+       list_for_each_entry_rcu(mod, &modules, list) {
+               unsigned long ret;
+
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
+               ret = __find_kallsyms_symbol_address_and_size_value(mod, name, 
address, size);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/* Look for this name: can be of form module:name. */
+unsigned long module_kallsyms_lookup_address_and_size(const char *name, 
unsigned long *address, unsigned long *size)
+{
+       unsigned long ret;
+
+       /* Don't lock: we're in enough trouble already. */
+       preempt_disable();
+       ret = __module_kallsyms_lookup_address_and_size(name, address, size);
+       preempt_enable();
+       return ret;
+}
+
+
 unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
 {
        unsigned long ret;
--
2.34.1

Reply via email to