@@ -7747,10 +7747,14 @@ int __init __weak ftrace_dyn_arch_init(void)
return 0;
}
+/* This is set in scripts/sorttable.c */
+int ftrace_mcount_skip __initdata;
+
void __init ftrace_init(void)
{
extern unsigned long __start_mcount_loc[];
extern unsigned long __stop_mcount_loc[];
+ unsigned long *start_addr = __start_mcount_loc;
unsigned long count, flags;
int ret;
@@ -7761,6 +7765,14 @@ void __init ftrace_init(void)
goto failed;
count = __stop_mcount_loc - __start_mcount_loc;
+
+ /*
+ * scripts/sorttable.c will set ftrace_mcount_skip to state
+ * how many functions to skip in the __mcount_loc section.
+ * These would have been weak functions.
+ */
+ count -= ftrace_mcount_skip;
+ start_addr += ftrace_mcount_skip;
if (!count) {
pr_info("ftrace: No functions to be traced?\n");
goto failed;
@@ -7769,9 +7781,7 @@ void __init ftrace_init(void)
pr_info("ftrace: allocating %ld entries in %ld pages\n",
count, DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
- ret = ftrace_process_locs(NULL,
- __start_mcount_loc,
- __stop_mcount_loc);
+ ret = ftrace_process_locs(NULL, start_addr, __stop_mcount_loc);
if (ret) {
pr_warn("ftrace: failed to allocate entries for functions\n");
goto failed;
@@ -543,6 +543,7 @@ static pthread_t mcount_sort_thread;
struct elf_mcount_loc {
Elf_Ehdr *ehdr;
Elf_Shdr *init_data_sec;
+ Elf_Sym *ftrace_skip_sym;
uint64_t start_mcount_loc;
uint64_t stop_mcount_loc;
};
@@ -554,9 +555,17 @@ static void *sort_mcount_loc(void *arg)
uint64_t offset = emloc->start_mcount_loc - shdr_addr(emloc->init_data_sec)
+ shdr_offset(emloc->init_data_sec);
uint64_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
+ uint32_t *skip_addr = NULL;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
void *end_loc = start_loc + count;
+ if (emloc->ftrace_skip_sym) {
+ offset = sym_value(emloc->ftrace_skip_sym) -
+ shdr_addr(emloc->init_data_sec) +
+ shdr_offset(emloc->init_data_sec);
+ skip_addr = (void *)emloc->ehdr + offset;
+ }
+
/* zero out any locations not found by function list */
if (function_list_size) {
for (void *ptr = start_loc; ptr < end_loc; ptr += long_size) {
@@ -573,6 +582,25 @@ static void *sort_mcount_loc(void *arg)
}
qsort(start_loc, count/long_size, long_size, compare_extable);
+
+ /* Now set how many functions need to be skipped */
+ for (void *ptr = start_loc; skip_addr && ptr < end_loc; ptr += long_size) {
+ uint64_t val;
+
+ if (long_size == 4)
+ val = *(uint32_t *)ptr;
+ else
+ val = *(uint64_t *)ptr;
+ if (val) {
+ uint32_t skip;
+
+ /* Update the ftrace_mcount_skip to skip these functions */
+ val = ptr - (void *)start_loc;
+ skip = val / long_size;
+ w(r(&skip), skip_addr);
+ break;
+ }
+ }
return NULL;
}
@@ -590,11 +618,15 @@ static void get_mcount_loc(struct elf_mcount_loc *emloc, Elf_Shdr *symtab_sec,
while (sym < end_sym) {
if (!strcmp(strtab + sym_name(sym), "__start_mcount_loc")) {
emloc->start_mcount_loc = sym_value(sym);
- if (++found == 2)
+ if (++found == 3)
break;
} else if (!strcmp(strtab + sym_name(sym), "__stop_mcount_loc")) {
emloc->stop_mcount_loc = sym_value(sym);
- if (++found == 2)
+ if (++found == 3)
+ break;
+ } else if (!strcmp(strtab + sym_name(sym), "ftrace_mcount_skip")) {
+ emloc->ftrace_skip_sym = sym;
+ if (++found == 3)
break;
}
sym = (void *)sym + symentsize;