@@ -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. */
39494041static 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
0 commit comments