Michel Lind de7e84
From 1a3af2aaee85bd475bda44993b3e8dc1335497d5 Mon Sep 17 00:00:00 2001
Michel Lind de7e84
From: Joe Lawrence <joe.lawrence@redhat.com>
Michel Lind de7e84
Date: Thu, 10 Oct 2024 16:58:58 -0400
Michel Lind de7e84
Subject: [PATCH 101/118] aarch64: create-diff-object implementation
Michel Lind de7e84
Michel Lind de7e84
TODO
Michel Lind de7e84
Michel Lind de7e84
Signed-off-by: Suraj Jitindar Singh <surajjs@amazon.com>
Michel Lind de7e84
Signed-off-by: Pete Swain <swine@google.com>
Michel Lind de7e84
Signed-off-by: Mihails Strasuns <mstrasun@amazon.com>
Michel Lind de7e84
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
Michel Lind de7e84
---
Michel Lind de7e84
 kpatch-build/create-diff-object.c | 104 ++++++++++++++++++++++++++----
Michel Lind de7e84
 kpatch-build/kpatch-elf.c         |   8 +++
Michel Lind de7e84
 kpatch-build/kpatch-elf.h         |   1 +
Michel Lind de7e84
 3 files changed, 101 insertions(+), 12 deletions(-)
Michel Lind de7e84
Michel Lind de7e84
diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c
Michel Lind de7e84
index 8170b18..e62880b 100644
Michel Lind de7e84
--- a/kpatch-build/create-diff-object.c
Michel Lind de7e84
+++ b/kpatch-build/create-diff-object.c
Michel Lind de7e84
@@ -173,6 +173,8 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf,
Michel Lind de7e84
 					  struct symbol *sym)
Michel Lind de7e84
 {
Michel Lind de7e84
 	switch(kelf->arch) {
Michel Lind de7e84
+	case AARCH64:
Michel Lind de7e84
+		return false;
Michel Lind de7e84
 	case PPC64:
Michel Lind de7e84
 		return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) &&
Michel Lind de7e84
 			sym->sym.st_value == 8);
Michel Lind de7e84
@@ -230,6 +232,25 @@ static struct rela *toc_rela(const struct rela *rela)
Michel Lind de7e84
 				   (unsigned int)rela->addend);
Michel Lind de7e84
 }
Michel Lind de7e84
 
Michel Lind de7e84
+/*
Michel Lind de7e84
+ * Mapping symbols are used to mark and label the transitions between code and
Michel Lind de7e84
+ * data in elf files. They begin with a "$" dollar symbol. Don't correlate them
Michel Lind de7e84
+ * as they often all have the same name either "$x" to mark the start of code
Michel Lind de7e84
+ * or "$d" to mark the start of data.
Michel Lind de7e84
+ */
Michel Lind de7e84
+static bool kpatch_is_mapping_symbol(struct kpatch_elf *kelf, struct symbol *sym)
Michel Lind de7e84
+{
Michel Lind de7e84
+	if (kelf->arch != AARCH64)
Michel Lind de7e84
+		return false;
Michel Lind de7e84
+
Michel Lind de7e84
+	if (sym->name && sym->name[0] == '$' &&
Michel Lind de7e84
+	    sym->type == STT_NOTYPE &&
Michel Lind de7e84
+	    sym->bind == STB_LOCAL)
Michel Lind de7e84
+		return true;
Michel Lind de7e84
+
Michel Lind de7e84
+	return false;
Michel Lind de7e84
+}
Michel Lind de7e84
+
Michel Lind de7e84
 /*
Michel Lind de7e84
  * When compiling with -ffunction-sections and -fdata-sections, almost every
Michel Lind de7e84
  * symbol gets its own dedicated section.  We call such symbols "bundled"
Michel Lind de7e84
@@ -667,6 +688,12 @@ static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr)
Michel Lind de7e84
 
Michel Lind de7e84
 	switch(kelf->arch) {
Michel Lind de7e84
 
Michel Lind de7e84
+	case AARCH64:
Michel Lind de7e84
+		/* Verify mov w2 <line number> */
Michel Lind de7e84
+		if ((insn[0] & 0b11111) == 0x2 && insn[3] == 0x52)
Michel Lind de7e84
+			return true;
Michel Lind de7e84
+		break;
Michel Lind de7e84
+
Michel Lind de7e84
 	case X86_64:
Michel Lind de7e84
 		/* arg2: mov $imm, %esi */
Michel Lind de7e84
 		if (insn[0] == 0xbe)
Michel Lind de7e84
@@ -1076,15 +1103,15 @@ static void kpatch_correlate_sections(struct list_head *seclist_orig,
Michel Lind de7e84
 	}
Michel Lind de7e84
 }
Michel Lind de7e84
 
Michel Lind de7e84
-static void kpatch_correlate_symbols(struct list_head *symlist_orig,
Michel Lind de7e84
-		struct list_head *symlist_patched)
Michel Lind de7e84
+static void kpatch_correlate_symbols(struct kpatch_elf *kelf_orig,
Michel Lind de7e84
+		struct kpatch_elf *kelf_patched)
Michel Lind de7e84
 {
Michel Lind de7e84
 	struct symbol *sym_orig, *sym_patched;
Michel Lind de7e84
 
Michel Lind de7e84
-	list_for_each_entry(sym_orig, symlist_orig, list) {
Michel Lind de7e84
+	list_for_each_entry(sym_orig, &kelf_orig->symbols, list) {
Michel Lind de7e84
 		if (sym_orig->twin)
Michel Lind de7e84
 			continue;
Michel Lind de7e84
-		list_for_each_entry(sym_patched, symlist_patched, list) {
Michel Lind de7e84
+		list_for_each_entry(sym_patched, &kelf_patched->symbols, list) {
Michel Lind de7e84
 			if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) ||
Michel Lind de7e84
 			    sym_orig->type != sym_patched->type || sym_patched->twin)
Michel Lind de7e84
 				continue;
Michel Lind de7e84
@@ -1104,6 +1131,9 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig,
Michel Lind de7e84
 			    !strncmp(sym_orig->name, ".LC", 3))
Michel Lind de7e84
 				continue;
Michel Lind de7e84
 
Michel Lind de7e84
+			if (kpatch_is_mapping_symbol(kelf_orig, sym_orig))
Michel Lind de7e84
+				continue;
Michel Lind de7e84
+
Michel Lind de7e84
 			/* group section symbols must have correlated sections */
Michel Lind de7e84
 			if (sym_orig->sec &&
Michel Lind de7e84
 			    sym_orig->sec->sh.sh_type == SHT_GROUP &&
Michel Lind de7e84
@@ -1509,7 +1539,7 @@ static void kpatch_correlate_elfs(struct kpatch_elf *kelf_orig,
Michel Lind de7e84
 		struct kpatch_elf *kelf_patched)
Michel Lind de7e84
 {
Michel Lind de7e84
 	kpatch_correlate_sections(&kelf_orig->sections, &kelf_patched->sections);
Michel Lind de7e84
-	kpatch_correlate_symbols(&kelf_orig->symbols, &kelf_patched->symbols);
Michel Lind de7e84
+	kpatch_correlate_symbols(kelf_orig, kelf_patched);
Michel Lind de7e84
 }
Michel Lind de7e84
 
Michel Lind de7e84
 static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf)
Michel Lind de7e84
@@ -1625,7 +1655,8 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
Michel Lind de7e84
 
Michel Lind de7e84
 				if (is_text_section(relasec->base) &&
Michel Lind de7e84
 				    !is_text_section(sym->sec) &&
Michel Lind de7e84
-				    is_arch(X86_64) && rela->type == R_X86_64_32S &&
Michel Lind de7e84
+				    ((is_arch(X86_64) && rela->type == R_X86_64_32S) ||
Michel Lind de7e84
+				     (is_arch(AARCH64) && rela->type == R_AARCH64_ABS64)) &&
Michel Lind de7e84
 				    rela->addend == (long)sym->sec->sh.sh_size &&
Michel Lind de7e84
 				    end == (long)sym->sec->sh.sh_size) {
Michel Lind de7e84
 
Michel Lind de7e84
@@ -1662,6 +1693,9 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
Michel Lind de7e84
 					 */
Michel Lind de7e84
 				} else if (target_off == start && target_off == end) {
Michel Lind de7e84
 
Michel Lind de7e84
+					if(kpatch_is_mapping_symbol(kelf, sym))
Michel Lind de7e84
+						continue;
Michel Lind de7e84
+
Michel Lind de7e84
 					/*
Michel Lind de7e84
 					 * Allow replacement for references to
Michel Lind de7e84
 					 * empty symbols.
Michel Lind de7e84
@@ -2422,28 +2456,28 @@ static bool static_call_sites_group_filter(struct lookup_table *lookup,
Michel Lind de7e84
 static struct special_section special_sections[] = {
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= "__bug_table",
Michel Lind de7e84
-		.arch		= X86_64 | PPC64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | PPC64 | S390,
Michel Lind de7e84
 		.group_size	= bug_table_group_size,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= ".fixup",
Michel Lind de7e84
-		.arch		= X86_64 | PPC64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | PPC64 | S390,
Michel Lind de7e84
 		.group_size	= fixup_group_size,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= "__ex_table", /* must come after .fixup */
Michel Lind de7e84
-		.arch		= X86_64 | PPC64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | PPC64 | S390,
Michel Lind de7e84
 		.group_size	= ex_table_group_size,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= "__jump_table",
Michel Lind de7e84
-		.arch		= X86_64 | PPC64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | PPC64 | S390,
Michel Lind de7e84
 		.group_size	= jump_table_group_size,
Michel Lind de7e84
 		.group_filter	= jump_table_group_filter,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= ".printk_index",
Michel Lind de7e84
-		.arch		= X86_64 | PPC64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | PPC64 | S390,
Michel Lind de7e84
 		.group_size	= printk_index_group_size,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
@@ -2458,7 +2492,7 @@ static struct special_section special_sections[] = {
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
 		.name		= ".altinstructions",
Michel Lind de7e84
-		.arch		= X86_64 | S390,
Michel Lind de7e84
+		.arch		= AARCH64 | X86_64 | S390,
Michel Lind de7e84
 		.group_size	= altinstructions_group_size,
Michel Lind de7e84
 	},
Michel Lind de7e84
 	{
Michel Lind de7e84
@@ -3774,6 +3808,47 @@ static void kpatch_create_ftrace_callsite_sections(struct kpatch_elf *kelf, bool
Michel Lind de7e84
 		}
Michel Lind de7e84
 
Michel Lind de7e84
 		switch(kelf->arch) {
Michel Lind de7e84
+		case AARCH64:
Michel Lind de7e84
+			unsigned char *insn;
Michel Lind de7e84
+
Michel Lind de7e84
+			/*
Michel Lind de7e84
+			 * Assume ppc64le is built with -fpatchable-function-entry=2, which means that all 2 nops are
Michel Lind de7e84
+			 * after the entry point of the function.
Michel Lind de7e84
+			 *
Michel Lind de7e84
+			 * Disassembly of section .text.cmdline_proc_show:
Michel Lind de7e84
+			 *
Michel Lind de7e84
+			 * 0000000000000000 <cmdline_proc_show>:
Michel Lind de7e84
+			 *    0:   d503201f        nop                                   << <<
Michel Lind de7e84
+			 *    4:   d503201f        nop
Michel Lind de7e84
+			 *
Michel Lind de7e84
+			 * Relocation section '.rela__patchable_function_entries'
Michel Lind de7e84
+			 *     Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
Michel Lind de7e84
+			 * 0000000000000008  0000000f00000101 R_AARCH64_ABS64        0000000000000000 .text.cmdline_proc_show + 0
Michel Lind de7e84
+			 *                                                                                                      ^
Michel Lind de7e84
+			 */
Michel Lind de7e84
+			insn_offset = 0;
Michel Lind de7e84
+			insn = sym->sec->data->d_buf + insn_offset;
Michel Lind de7e84
+
Michel Lind de7e84
+			/*
Michel Lind de7e84
+			 * If BTI (Branch Target Identification) is enabled then there
Michel Lind de7e84
+			 * might be an additional 'BTI C' instruction before the two
Michel Lind de7e84
+			 * patchable function entry 'NOP's.
Michel Lind de7e84
+			 * i.e. 0xd503245f (little endian)
Michel Lind de7e84
+			 */
Michel Lind de7e84
+			if (insn[0] == 0x5f) {
Michel Lind de7e84
+				if (insn[1] != 0x24 || insn[2] != 0x03 || insn[3] != 0xd5)
Michel Lind de7e84
+					ERROR("%s: unexpected instruction in patch section of function\n", sym->name);
Michel Lind de7e84
+				insn_offset += 4;
Michel Lind de7e84
+				insn += 4;
Michel Lind de7e84
+			}
Michel Lind de7e84
+			for (int i=0; i<8; i+=4) {
Michel Lind de7e84
+				/* We expect a NOP i.e. 0xd503201f (little endian) */
Michel Lind de7e84
+				if (insn[i] != 0x1f || insn[i + 1] != 0x20 ||
Michel Lind de7e84
+				    insn[i + 2] != 0x03 || insn [i + 3] != 0xd5)
Michel Lind de7e84
+					ERROR("%s: unexpected instruction in patch section of function\n", sym->name);
Michel Lind de7e84
+			}
Michel Lind de7e84
+
Michel Lind de7e84
+			break;
Michel Lind de7e84
 		case PPC64: {
Michel Lind de7e84
 			unsigned char *insn;
Michel Lind de7e84
 
Michel Lind de7e84
@@ -4067,6 +4142,11 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
Michel Lind de7e84
 			continue;
Michel Lind de7e84
 
Michel Lind de7e84
 		switch(kelf->arch) {
Michel Lind de7e84
+		case AARCH64:
Michel Lind de7e84
+			if (kpatch_symbol_has_pfe_entry(kelf, sym)) {
Michel Lind de7e84
+				sym->has_func_profiling = 1;
Michel Lind de7e84
+			}
Michel Lind de7e84
+			break;
Michel Lind de7e84
 		case PPC64:
Michel Lind de7e84
 			if (kpatch_symbol_has_pfe_entry(kelf, sym)) {
Michel Lind de7e84
 				sym->has_func_profiling = 1;
Michel Lind de7e84
diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c
Michel Lind de7e84
index 073b808..17c0491 100755
Michel Lind de7e84
--- a/kpatch-build/kpatch-elf.c
Michel Lind de7e84
+++ b/kpatch-build/kpatch-elf.c
Michel Lind de7e84
@@ -156,6 +156,8 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset)
Michel Lind de7e84
 unsigned int absolute_rela_type(struct kpatch_elf *kelf)
Michel Lind de7e84
 {
Michel Lind de7e84
 	switch(kelf->arch) {
Michel Lind de7e84
+	case AARCH64:
Michel Lind de7e84
+		return R_AARCH64_ABS64;
Michel Lind de7e84
 	case PPC64:
Michel Lind de7e84
 		return R_PPC64_ADDR64;
Michel Lind de7e84
 	case X86_64:
Michel Lind de7e84
@@ -225,6 +227,7 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
Michel Lind de7e84
 	struct section *sec = relasec->base;
Michel Lind de7e84
 
Michel Lind de7e84
 	switch(kelf->arch) {
Michel Lind de7e84
+	case AARCH64:
Michel Lind de7e84
 	case PPC64:
Michel Lind de7e84
 		add_off = 0;
Michel Lind de7e84
 		break;
Michel Lind de7e84
@@ -274,6 +277,8 @@ unsigned int insn_length(struct kpatch_elf *kelf, void *addr)
Michel Lind de7e84
 	char *insn = addr;
Michel Lind de7e84
 
Michel Lind de7e84
 	switch(kelf->arch) {
Michel Lind de7e84
+	case AARCH64:
Michel Lind de7e84
+		return 4;
Michel Lind de7e84
 
Michel Lind de7e84
 	case X86_64:
Michel Lind de7e84
 		insn_init(&decoded_insn, addr, 1);
Michel Lind de7e84
@@ -604,6 +609,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
Michel Lind de7e84
 	if (!gelf_getehdr(kelf->elf, &ehdr))
Michel Lind de7e84
 		ERROR("gelf_getehdr");
Michel Lind de7e84
 	switch (ehdr.e_machine) {
Michel Lind de7e84
+	case EM_AARCH64:
Michel Lind de7e84
+		kelf->arch = AARCH64;
Michel Lind de7e84
+		break;
Michel Lind de7e84
 	case EM_PPC64:
Michel Lind de7e84
 		kelf->arch = PPC64;
Michel Lind de7e84
 		break;
Michel Lind de7e84
diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h
Michel Lind de7e84
index 3389dfe..4a3617d 100644
Michel Lind de7e84
--- a/kpatch-build/kpatch-elf.h
Michel Lind de7e84
+++ b/kpatch-build/kpatch-elf.h
Michel Lind de7e84
@@ -116,6 +116,7 @@ enum architecture {
Michel Lind de7e84
 	PPC64  = 0x1 << 0,
Michel Lind de7e84
 	X86_64 = 0x1 << 1,
Michel Lind de7e84
 	S390   = 0x1 << 2,
Michel Lind de7e84
+	AARCH64 = 0x1 << 3,
Michel Lind de7e84
 };
Michel Lind de7e84
 
Michel Lind de7e84
 struct kpatch_elf {
Michel Lind de7e84
-- 
Michel Lind de7e84
2.48.1
Michel Lind de7e84