summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/kallsyms.c86
-rw-r--r--kernel/kallsyms_internal.h1
-rw-r--r--scripts/kallsyms.c37
3 files changed, 113 insertions, 11 deletions
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 60c20f301a6b..ba351dfa109b 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -187,26 +187,90 @@ static bool cleanup_symbol_name(char *s)
return false;
}
+static int compare_symbol_name(const char *name, char *namebuf)
+{
+ int ret;
+
+ ret = strcmp(name, namebuf);
+ if (!ret)
+ return ret;
+
+ if (cleanup_symbol_name(namebuf) && !strcmp(name, namebuf))
+ return 0;
+
+ return ret;
+}
+
+static int kallsyms_lookup_names(const char *name,
+ unsigned int *start,
+ unsigned int *end)
+{
+ int ret;
+ int low, mid, high;
+ unsigned int seq, off;
+ char namebuf[KSYM_NAME_LEN];
+
+ low = 0;
+ high = kallsyms_num_syms - 1;
+
+ while (low <= high) {
+ mid = low + (high - low) / 2;
+ seq = kallsyms_seqs_of_names[mid];
+ off = get_symbol_offset(seq);
+ kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
+ ret = compare_symbol_name(name, namebuf);
+ if (ret > 0)
+ low = mid + 1;
+ else if (ret < 0)
+ high = mid - 1;
+ else
+ break;
+ }
+
+ if (low > high)
+ return -ESRCH;
+
+ low = mid;
+ while (low) {
+ seq = kallsyms_seqs_of_names[low - 1];
+ off = get_symbol_offset(seq);
+ kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
+ if (compare_symbol_name(name, namebuf))
+ break;
+ low--;
+ }
+ *start = low;
+
+ if (end) {
+ high = mid;
+ while (high < kallsyms_num_syms - 1) {
+ seq = kallsyms_seqs_of_names[high + 1];
+ off = get_symbol_offset(seq);
+ kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
+ if (compare_symbol_name(name, namebuf))
+ break;
+ high++;
+ }
+ *end = high;
+ }
+
+ return 0;
+}
+
/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
- char namebuf[KSYM_NAME_LEN];
- unsigned long i;
- unsigned int off;
+ int ret;
+ unsigned int i;
/* Skip the search for empty string. */
if (!*name)
return 0;
- for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
- off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
-
- if (strcmp(namebuf, name) == 0)
- return kallsyms_sym_address(i);
+ ret = kallsyms_lookup_names(name, &i, NULL);
+ if (!ret)
+ return kallsyms_sym_address(kallsyms_seqs_of_names[i]);
- if (cleanup_symbol_name(namebuf) && strcmp(namebuf, name) == 0)
- return kallsyms_sym_address(i);
- }
return module_kallsyms_lookup_name(name);
}
diff --git a/kernel/kallsyms_internal.h b/kernel/kallsyms_internal.h
index 2d0c6f2f0243..a04b7a5cb1e3 100644
--- a/kernel/kallsyms_internal.h
+++ b/kernel/kallsyms_internal.h
@@ -26,5 +26,6 @@ extern const char kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;
extern const unsigned int kallsyms_markers[] __weak;
+extern const unsigned int kallsyms_seqs_of_names[] __weak;
#endif // LINUX_KALLSYMS_INTERNAL_H_
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index ab105bdde4ef..df2d93fb0e8d 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -49,6 +49,7 @@ _Static_assert(
struct sym_entry {
unsigned long long addr;
unsigned int len;
+ unsigned int seq;
unsigned int start_pos;
unsigned int percpu_absolute;
unsigned char sym[];
@@ -410,6 +411,35 @@ static int symbol_absolute(const struct sym_entry *s)
return s->percpu_absolute;
}
+static int compare_names(const void *a, const void *b)
+{
+ int ret;
+ char sa_namebuf[KSYM_NAME_LEN];
+ char sb_namebuf[KSYM_NAME_LEN];
+ const struct sym_entry *sa = *(const struct sym_entry **)a;
+ const struct sym_entry *sb = *(const struct sym_entry **)b;
+
+ expand_symbol(sa->sym, sa->len, sa_namebuf);
+ expand_symbol(sb->sym, sb->len, sb_namebuf);
+ ret = strcmp(&sa_namebuf[1], &sb_namebuf[1]);
+ if (!ret) {
+ if (sa->addr > sb->addr)
+ return 1;
+ else if (sa->addr < sb->addr)
+ return -1;
+
+ /* keep old order */
+ return (int)(sa->seq - sb->seq);
+ }
+
+ return ret;
+}
+
+static void sort_symbols_by_name(void)
+{
+ qsort(table, table_cnt, sizeof(table[0]), compare_names);
+}
+
static void write_src(void)
{
unsigned int i, k, off;
@@ -495,6 +525,7 @@ static void write_src(void)
for (i = 0; i < table_cnt; i++) {
if ((i & 0xFF) == 0)
markers[i >> 8] = off;
+ table[i]->seq = i;
/* There cannot be any symbol of length zero. */
if (table[i]->len == 0) {
@@ -535,6 +566,12 @@ static void write_src(void)
free(markers);
+ sort_symbols_by_name();
+ output_label("kallsyms_seqs_of_names");
+ for (i = 0; i < table_cnt; i++)
+ printf("\t.long\t%u\n", table[i]->seq);
+ printf("\n");
+
output_label("kallsyms_token_table");
off = 0;
for (i = 0; i < 256; i++) {