@@ -85,6 +85,8 @@ struct section {
struct symbol {
struct list_head list;
struct symbol *twin;
+ struct symbol *parent;
+ struct symbol *child;
struct section *sec;
GElf_Sym sym;
char *name;
@@ -327,6 +327,38 @@ static void kpatch_rename_mangled_functions(struct kpatch_elf *base,
}
}
+/*
+ * During optimization gcc may move unlikely execution branches into *.cold
+ * subfunctions. kpatch_detect_child_functions detects such subfunctions and
+ * crossreferences them with their parent functions through parent/child
+ * pointers.
+ */
+static void kpatch_detect_child_functions(struct kpatch_elf *kelf)
+{
+ struct symbol *sym;
+
+ list_for_each_entry(sym, &kelf->symbols, list) {
+ char *coldstr;
+
+ coldstr = strstr(sym->name, ".cold.");
+ if (coldstr != NULL) {
+ char *pname;
+
+ pname = strndup(sym->name, coldstr - sym->name);
+ if (!pname)
+ ERROR("strndup");
+
+ sym->parent = find_symbol_by_name(&kelf->symbols, pname);
+ free(pname);
+
+ if (!sym->parent)
+ ERROR("failed to find parent function for %s", sym->name);
+
+ sym->parent->child = sym;
+ }
+ }
+}
+
/*
* This function detects whether the given symbol is a "special" static local
* variable (for lack of a better term).
@@ -2329,6 +2361,9 @@ int main(int argc, char *argv[])
log_debug("Open patched\n");
kelf_patched = kpatch_elf_open(arguments.args[1]);
+ kpatch_detect_child_functions(kelf_base);
+ kpatch_detect_child_functions(kelf_patched);
+
log_debug("Compare elf headers\n");
kpatch_compare_elf_headers(kelf_base->elf, kelf_patched->elf);
log_debug("Check program headers of base\n");