Skip to content

Commit a636944

Browse files
author
Suraj Jitindar Singh
committed
create-diff-object: Create __patchable_function_entries section for aarch64
The mcount_loc section contains the addresses of patchable ftrace sites which is used by the ftrace infrastructure in the kernel to create a list of tracable functions and to know where to patch to enable tracing of them. On aarch64 this section is called __patchable_function_entries and is generated by the compiler. Modify kpatch_create_mcount_sections() to create the __patchable_function_entries section on aarch64 rather than an mcount_loc section. Either name will be recognised by the kernel but keep the name which is expected. In order to verify which functions should have an entry in the __patchable_function_entries section, preserve the section from the kelf_patched file. Note that any symbols not included in the output elf must be NULLed in the relocation section as it would be unsafe to access them after they're freed. Also check for the 2 required NOP instructions on function entry to be pedantic. Signed-off-by: Suraj Jitindar Singh <surajjs@amazon.com>
1 parent 2a21437 commit a636944

File tree

1 file changed

+71
-3
lines changed

1 file changed

+71
-3
lines changed

kpatch-build/create-diff-object.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,30 @@ static void kpatch_migrate_included_elements(struct kpatch_elf *kelf, struct kpa
19381938
sec->secsym = NULL;
19391939
}
19401940

1941+
#ifdef __aarch64__
1942+
{
1943+
/*
1944+
* On aarch64 the __patchable_function_entries section is used to store
1945+
* information about patchable functions which we will use in
1946+
* kpatch_create_mcount_sections(). Since this section isn't included it
1947+
* will be freed in kpatch_elf_teardown(), so we preserve it in the main
1948+
* function. However the relas->sym of any relocation will be freed if
1949+
* that symbol isn't included and thus it is unsafe to dereference it
1950+
* later. Zero the "sym" field for any symbol not included.
1951+
*/
1952+
struct rela *rela;
1953+
struct section *patchable_sec;
1954+
1955+
patchable_sec = find_section_by_name(&kelf->sections,
1956+
"__patchable_function_entries");
1957+
if (patchable_sec) {
1958+
list_for_each_entry(rela, &patchable_sec->rela->relas, list) {
1959+
if (!rela->sym->include)
1960+
rela->sym = NULL;
1961+
}
1962+
}
1963+
}
1964+
#endif
19411965
/* migrate included symbols from kelf to out */
19421966
list_for_each_entry_safe(sym, safesym, &kelf->symbols, list) {
19431967
if (!sym->include)
@@ -3410,7 +3434,8 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char *
34103434
* TODO: Eventually we can modify recordmount so that it recognizes our bundled
34113435
* sections as valid and does this work for us.
34123436
*/
3413-
static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
3437+
static void kpatch_create_mcount_sections(struct kpatch_elf *kelf,
3438+
struct section *patchable_sec)
34143439
{
34153440
int nr, index;
34163441
struct section *sec, *relasec;
@@ -3426,7 +3451,11 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
34263451
nr++;
34273452

34283453
/* create text/rela section pair */
3454+
#ifdef __aarch64__
3455+
sec = create_section_pair(kelf, "__patchable_function_entries", sizeof(void*), nr);
3456+
#else /* !__aarch64__ */
34293457
sec = create_section_pair(kelf, "__mcount_loc", sizeof(void*), nr);
3458+
#endif
34303459
relasec = sec->rela;
34313460

34323461
/* populate sections */
@@ -3484,6 +3513,37 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
34843513
rela->type = R_X86_64_PC32;
34853514
}
34863515

3516+
#elif defined(__aarch64__)
3517+
{
3518+
unsigned char *insn;
3519+
bool found = false;
3520+
int i;
3521+
3522+
if (!patchable_sec)
3523+
ERROR("%s: unexpected missing __patchable_function_entries section", __func__);
3524+
3525+
/* We search the patchable_sec to ensure that the symbol is patchable. */
3526+
list_for_each_entry(rela, &patchable_sec->relas, list) {
3527+
if (rela->sym && rela->sym->sec && sym->sec ==
3528+
rela->sym->sec) {
3529+
found = true;
3530+
break;
3531+
}
3532+
}
3533+
if (!found)
3534+
ERROR("%s: unexpected missing __patchable_function_entries entry", sym->name);
3535+
3536+
/* Then to be pedantic we also check for the 2 NOPs at function entry. */
3537+
insn = sym->sec->data->d_buf + rela->addend;
3538+
for (i = 0; i < 8; i += 4) {
3539+
/* We expect a NOP i.e. 0xd503201f (little endian) */
3540+
if (insn[i] != 0x1f || insn[i + 1] != 0x20 ||
3541+
insn[i + 2] != 0x03 || insn [i + 3] != 0xd5)
3542+
ERROR("%s: unexpected instruction in patch section of function", sym->name);
3543+
}
3544+
3545+
insn_offset = rela->addend;
3546+
}
34873547
#else /* __powerpc64__ */
34883548
{
34893549
bool found = false;
@@ -3706,7 +3766,7 @@ int main(int argc, char *argv[])
37063766
struct arguments arguments;
37073767
int num_changed, callbacks_exist, new_globals_exist;
37083768
struct lookup_table *lookup;
3709-
struct section *sec, *symtab;
3769+
struct section *sec, *symtab, *patchable_sec;
37103770
char *orig_obj, *patched_obj, *parent_name;
37113771
char *parent_symtab, *mod_symvers, *patch_name, *output_obj;
37123772

@@ -3790,6 +3850,14 @@ int main(int argc, char *argv[])
37903850
/* this is destructive to kelf_patched */
37913851
kpatch_migrate_included_elements(kelf_patched, &kelf_out);
37923852

3853+
/* Preserve the patchable_function_entries sec before it's torn down */
3854+
patchable_sec = find_section_by_name(&kelf_patched->sections,
3855+
"__patchable_function_entries");
3856+
if (patchable_sec) {
3857+
patchable_sec = patchable_sec->rela;
3858+
list_del(&patchable_sec->list);
3859+
}
3860+
37933861
/*
37943862
* Teardown kelf_patched since we shouldn't access sections or symbols
37953863
* through it anymore. Don't free however, since our section and symbol
@@ -3808,7 +3876,7 @@ int main(int argc, char *argv[])
38083876
kpatch_create_callbacks_objname_rela(kelf_out, parent_name);
38093877
kpatch_build_strings_section_data(kelf_out);
38103878

3811-
kpatch_create_mcount_sections(kelf_out);
3879+
kpatch_create_mcount_sections(kelf_out, patchable_sec);
38123880

38133881
/*
38143882
* At this point, the set of output sections and symbols is

0 commit comments

Comments
 (0)