Skip to content

Commit 7b6fee6

Browse files
committed
create-diff-object: Create __patchable_function_entries sections
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 some kernel configurations, section is called __patchable_function_entries and is generated by the compiler. Either of __mcount_loc or __patchable_function_entries is recognised by the kernel but for these configurations, use __patchable_function_entries as it is what is expected. The x86_64 arch is special (of course). Unlike other arches (ppc64le and aarch64) a x86_64 kernel built with -fpatchable-function-entry will generate nops AND create rela__patchable_function_entries for functions even marked as notrace. For this arch, always create __mount_loc sections and rely on __fentry__ relocations to indicate ftrace call sites. Note: this patch is a refactoring of original code by Pete Swain <[email protected]> for aarch64. At the same time, this version squashes several follow up commits from him and zimao <[email protected]>. The intent is minimize the eventual changeset for aarch64 support now that other arches are making use of __patchable_function_entries sections. Signed-off-by: Joe Lawrence <[email protected]>
1 parent 17b795b commit 7b6fee6

File tree

3 files changed

+171
-46
lines changed

3 files changed

+171
-46
lines changed

kpatch-build/create-diff-object.c

Lines changed: 148 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,14 @@ static void kpatch_compare_correlated_section(struct section *sec)
615615
!is_text_section(sec1)))
616616
DIFF_FATAL("%s section header details differ from %s", sec1->name, sec2->name);
617617

618-
/* Short circuit for mcount sections, we rebuild regardless */
618+
/*
619+
* Short circuit for mcount and patchable_function_entries
620+
* sections, we rebuild regardless
621+
*/
619622
if (!strcmp(sec->name, ".rela__mcount_loc") ||
620-
!strcmp(sec->name, "__mcount_loc")) {
623+
!strcmp(sec->name, "__mcount_loc") ||
624+
!strcmp(sec->name, ".rela__patchable_function_entries") ||
625+
!strcmp(sec->name, "__patchable_function_entries")) {
621626
sec->status = SAME;
622627
goto out;
623628
}
@@ -3676,31 +3681,66 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char *
36763681
}
36773682
}
36783683

3684+
/*
3685+
* Create links between text sections and their corresponding
3686+
* __patchable_function_entries sections (as there may be multiple pfe
3687+
* sections).
3688+
*/
3689+
static void kpatch_set_pfe_link(struct kpatch_elf *kelf)
3690+
{
3691+
struct section* sec;
3692+
struct rela *rela;
3693+
3694+
if (!kelf->has_pfe)
3695+
return;
3696+
3697+
list_for_each_entry(sec, &kelf->sections, list) {
3698+
if (strcmp(sec->name, "__patchable_function_entries"))
3699+
continue;
3700+
3701+
if (!sec->rela)
3702+
continue;
3703+
3704+
list_for_each_entry(rela, &sec->rela->relas, list)
3705+
rela->sym->pfe = sec;
3706+
}
3707+
}
3708+
36793709
/*
36803710
* This function basically reimplements the functionality of the Linux
36813711
* recordmcount script, so that patched functions can be recognized by ftrace.
36823712
*
36833713
* TODO: Eventually we can modify recordmount so that it recognizes our bundled
36843714
* sections as valid and does this work for us.
36853715
*/
3686-
static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
3716+
static void kpatch_create_ftrace_callsite_sections(struct kpatch_elf *kelf, bool has_pfe)
36873717
{
36883718
int nr, index;
3689-
struct section *sec, *relasec;
3690-
struct symbol *sym;
3691-
struct rela *rela, *mcount_rela;
3719+
struct section *sec = NULL;
3720+
struct symbol *sym, *rela_sym;
3721+
struct rela *rela;
36923722
void **funcs;
36933723
unsigned long insn_offset = 0;
3724+
unsigned int rela_offset;
36943725

36953726
nr = 0;
36963727
list_for_each_entry(sym, &kelf->symbols, list)
36973728
if (sym->type == STT_FUNC && sym->status != SAME &&
36983729
sym->has_func_profiling)
36993730
nr++;
37003731

3701-
/* create text/rela section pair */
3702-
sec = create_section_pair(kelf, "__mcount_loc", sizeof(void*), nr);
3703-
relasec = sec->rela;
3732+
if (has_pfe)
3733+
/*
3734+
* Create separate __patchable_function_entries sections
3735+
* for each function in the following loop.
3736+
*/
3737+
kelf->has_pfe = true;
3738+
else
3739+
/*
3740+
* Create a single __mcount_loc section pair for all
3741+
* functions.
3742+
*/
3743+
sec = create_section_pair(kelf, "__mcount_loc", sizeof(void*), nr);
37043744

37053745
/* populate sections */
37063746
index = 0;
@@ -3709,25 +3749,37 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
37093749
continue;
37103750

37113751
if (!sym->has_func_profiling) {
3712-
log_debug("function %s has no fentry/mcount call, no mcount record is needed\n",
3752+
log_debug("function %s has no ftrace callsite, no __patchable_function_entries/mcount record is needed\n",
37133753
sym->name);
37143754
continue;
37153755
}
37163756

37173757
switch(kelf->arch) {
37183758
case PPC64: {
3719-
bool found = false;
3759+
unsigned char *insn;
37203760

3721-
list_for_each_entry(rela, &sym->sec->rela->relas, list)
3722-
if (!strcmp(rela->sym->name, "_mcount")) {
3723-
found = true;
3724-
break;
3725-
}
3761+
if (kelf->has_pfe) {
3762+
insn_offset = sym->sym.st_value + PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other);
3763+
insn = sym->sec->data->d_buf + insn_offset;
3764+
3765+
/* verify nops */
3766+
if (insn[0] != 0x00 || insn[1] != 0x00 || insn[2] != 0x00 || insn[3] != 0x60 ||
3767+
insn[4] != 0x00 || insn[5] != 0x00 || insn[6] != 0x00 || insn[7] != 0x60)
3768+
ERROR("%s: unexpected instruction in patch section of function\n", sym->name);
3769+
} else {
3770+
bool found = false;
37263771

3727-
if (!found)
3728-
ERROR("%s: unexpected missing call to _mcount()", __func__);
3772+
list_for_each_entry(rela, &sym->sec->rela->relas, list)
3773+
if (!strcmp(rela->sym->name, "_mcount")) {
3774+
found = true;
3775+
break;
3776+
}
37293777

3730-
insn_offset = rela->offset;
3778+
if (!found)
3779+
ERROR("%s: unexpected missing call to _mcount()", __func__);
3780+
3781+
insn_offset = rela->offset;
3782+
}
37313783
break;
37323784
}
37333785
case X86_64: {
@@ -3783,16 +3835,31 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
37833835
ERROR("unsupported arch");
37843836
}
37853837

3786-
/*
3787-
* 'rela' points to the mcount/fentry call.
3788-
*
3789-
* Create a .rela__mcount_loc entry which also points to it.
3790-
*/
3791-
ALLOC_LINK(mcount_rela, &relasec->relas);
3792-
mcount_rela->sym = sym;
3793-
mcount_rela->type = absolute_rela_type(kelf);
3794-
mcount_rela->addend = insn_offset - sym->sym.st_value;
3795-
mcount_rela->offset = (unsigned int) (index * sizeof(*funcs));
3838+
if (kelf->has_pfe) {
3839+
/*
3840+
* Allocate a dedicated __patchable_function_entries for this function:
3841+
* - its .sh_link will be updated by kpatch_reindex_elements()
3842+
* - its lone rela is based on the section symbol
3843+
*/
3844+
sec = create_section_pair(kelf, "__patchable_function_entries", sizeof(void *), 1);
3845+
sec->sh.sh_flags |= SHF_WRITE | SHF_ALLOC | SHF_LINK_ORDER;
3846+
rela_sym = sym->sec->secsym;
3847+
rela_offset = 0;
3848+
rela_sym->pfe = sec;
3849+
} else {
3850+
/*
3851+
* mcount relas are based on the function symbol and saved in a
3852+
* single aggregate __mcount_loc section
3853+
*/
3854+
rela_sym = sym;
3855+
rela_offset = (unsigned int) (index * sizeof(*funcs));
3856+
}
3857+
3858+
ALLOC_LINK(rela, &sec->rela->relas);
3859+
rela->sym = rela_sym;
3860+
rela->type = absolute_rela_type(kelf);
3861+
rela->addend = insn_offset - rela->sym->sym.st_value;
3862+
rela->offset = rela_offset;
37963863

37973864
index++;
37983865
}
@@ -3945,36 +4012,66 @@ static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf)
39454012
sibling_call_errors);
39464013
}
39474014

4015+
static bool kpatch_symbol_has_pfe_entry(struct kpatch_elf *kelf, struct symbol *sym)
4016+
{
4017+
struct section *sec;
4018+
struct rela *rela;
4019+
4020+
if (!kelf->has_pfe)
4021+
return false;
4022+
4023+
list_for_each_entry(sec, &kelf->sections, list) {
4024+
if (strcmp(sec->name, "__patchable_function_entries"))
4025+
continue;
4026+
if (!sec->rela)
4027+
continue;
4028+
4029+
list_for_each_entry(rela, &sec->rela->relas, list) {
4030+
if (rela->sym->sec && sym->sec == rela->sym->sec &&
4031+
rela->sym->pfe == sec) {
4032+
return true;
4033+
}
4034+
}
4035+
}
4036+
4037+
return false;
4038+
}
4039+
39484040
/* Check which functions have fentry/mcount calls; save this info for later use. */
39494041
static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
39504042
{
39514043
struct symbol *sym;
39524044
struct rela *rela;
39534045
unsigned char *insn;
39544046
list_for_each_entry(sym, &kelf->symbols, list) {
3955-
if (sym->type != STT_FUNC || sym->is_pfx ||
3956-
!sym->sec || !sym->sec->rela)
4047+
if (sym->type != STT_FUNC || sym->is_pfx || !sym->sec)
39574048
continue;
39584049

39594050
switch(kelf->arch) {
39604051
case PPC64:
3961-
list_for_each_entry(rela, &sym->sec->rela->relas, list) {
3962-
if (!strcmp(rela->sym->name, "_mcount")) {
3963-
sym->has_func_profiling = 1;
3964-
break;
4052+
if (kpatch_symbol_has_pfe_entry(kelf, sym)) {
4053+
sym->has_func_profiling = 1;
4054+
} else if (sym->sec->rela) {
4055+
list_for_each_entry(rela, &sym->sec->rela->relas, list) {
4056+
if (!strcmp(rela->sym->name, "_mcount")) {
4057+
sym->has_func_profiling = 1;
4058+
break;
4059+
}
39654060
}
39664061
}
39674062
break;
39684063
case X86_64:
3969-
rela = list_first_entry(&sym->sec->rela->relas, struct rela,
3970-
list);
3971-
if ((rela->type != R_X86_64_NONE &&
3972-
rela->type != R_X86_64_PC32 &&
3973-
rela->type != R_X86_64_PLT32) ||
3974-
strcmp(rela->sym->name, "__fentry__"))
3975-
continue;
4064+
if (sym->sec->rela) {
4065+
rela = list_first_entry(&sym->sec->rela->relas, struct rela,
4066+
list);
4067+
if ((rela->type != R_X86_64_NONE &&
4068+
rela->type != R_X86_64_PC32 &&
4069+
rela->type != R_X86_64_PLT32) ||
4070+
strcmp(rela->sym->name, "__fentry__"))
4071+
continue;
39764072

3977-
sym->has_func_profiling = 1;
4073+
sym->has_func_profiling = 1;
4074+
}
39784075
break;
39794076
case S390:
39804077
/* Check for compiler generated fentry nop - jgnop 0 */
@@ -4045,6 +4142,7 @@ int main(int argc, char *argv[])
40454142
struct section *relasec, *symtab;
40464143
char *orig_obj, *patched_obj, *parent_name;
40474144
char *parent_symtab, *mod_symvers, *patch_name, *output_obj;
4145+
bool has_pfe = false;
40484146

40494147
memset(&arguments, 0, sizeof(arguments));
40504148
argp_parse (&argp, argc, argv, 0, NULL, &arguments);
@@ -4067,6 +4165,12 @@ int main(int argc, char *argv[])
40674165

40684166
kelf_orig = kpatch_elf_open(orig_obj);
40694167
kelf_patched = kpatch_elf_open(patched_obj);
4168+
4169+
kpatch_set_pfe_link(kelf_orig);
4170+
kpatch_set_pfe_link(kelf_patched);
4171+
if (kelf_patched->has_pfe)
4172+
has_pfe = true;
4173+
40704174
kpatch_find_func_profiling_calls(kelf_orig);
40714175
kpatch_find_func_profiling_calls(kelf_patched);
40724176

@@ -4146,7 +4250,7 @@ int main(int argc, char *argv[])
41464250
kpatch_create_callbacks_objname_rela(kelf_out, parent_name);
41474251
kpatch_build_strings_section_data(kelf_out);
41484252

4149-
kpatch_create_mcount_sections(kelf_out);
4253+
kpatch_create_ftrace_callsite_sections(kelf_out, has_pfe);
41504254

41514255
/*
41524256
* At this point, the set of output sections and symbols is

kpatch-build/kpatch-elf.c

100644100755
Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,16 @@ struct kpatch_elf *kpatch_elf_open(const char *name)
608608
kpatch_create_rela_list(kelf, relasec);
609609
}
610610

611+
/*
612+
* x86_64's pfe sections are only a side effect
613+
* CONFIG_CALL_PADDING building with * -fpatchable-function-entry=16,16,
614+
* These sections aren't used by ftrace on this arch, so do not
615+
* bother reading/writing them for x86_64.
616+
*/
617+
if (kelf->arch != X86_64)
618+
if (find_section_by_name(&kelf->sections, "__patchable_function_entries"))
619+
kelf->has_pfe = true;
620+
611621
return kelf;
612622
}
613623

@@ -643,6 +653,9 @@ void kpatch_dump_kelf(struct kpatch_elf *kelf)
643653
printf(", secsym-> %s", sec->secsym->name);
644654
if (sec->rela)
645655
printf(", rela-> %s", sec->rela->name);
656+
if (sec->secsym && sec->secsym->pfe)
657+
printf(", pfe-> [%d]",
658+
(sec->secsym->pfe) == NULL ? -1 : (int)sec->secsym->pfe->index);
646659
}
647660
next:
648661
printf("\n");
@@ -653,8 +666,10 @@ void kpatch_dump_kelf(struct kpatch_elf *kelf)
653666
printf("sym %02d, type %d, bind %d, ndx %02d, name %s (%s)",
654667
sym->index, sym->type, sym->bind, sym->sym.st_shndx,
655668
sym->name, status_str(sym->status));
656-
if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT))
669+
if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT)) {
657670
printf(" -> %s", sym->sec->name);
671+
printf(", profiling: %d", sym->has_func_profiling);
672+
}
658673
printf("\n");
659674
}
660675
}
@@ -923,6 +938,7 @@ struct section *create_section_pair(struct kpatch_elf *kelf, char *name,
923938
relasec->sh.sh_type = SHT_RELA;
924939
relasec->sh.sh_entsize = sizeof(GElf_Rela);
925940
relasec->sh.sh_addralign = 8;
941+
relasec->sh.sh_flags = SHF_INFO_LINK;
926942

927943
/* set text rela section pointer */
928944
sec->rela = relasec;
@@ -977,8 +993,11 @@ void kpatch_reindex_elements(struct kpatch_elf *kelf)
977993
index = 0;
978994
list_for_each_entry(sym, &kelf->symbols, list) {
979995
sym->index = index++;
980-
if (sym->sec)
996+
if (sym->sec) {
981997
sym->sym.st_shndx = (unsigned short)sym->sec->index;
998+
if (sym->pfe)
999+
sym->pfe->sh.sh_link = sym->sec->index;
1000+
}
9821001
else if (sym->sym.st_shndx != SHN_ABS &&
9831002
sym->sym.st_shndx != SHN_LIVEPATCH)
9841003
sym->sym.st_shndx = SHN_UNDEF;

kpatch-build/kpatch-elf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct symbol {
9393
};
9494
int has_func_profiling;
9595
bool is_pfx;
96+
struct section *pfe;
9697
};
9798

9899
struct rela {
@@ -125,6 +126,7 @@ struct kpatch_elf {
125126
struct list_head strings;
126127
Elf_Data *symtab_shndx;
127128
int fd;
129+
bool has_pfe;
128130
};
129131

130132
/*******************

0 commit comments

Comments
 (0)