@@ -382,7 +382,7 @@ static int decode_instructions(struct objtool_file *file)
382382 insn -> sec = sec ;
383383 insn -> offset = offset ;
384384
385- ret = arch_decode_instruction (file -> elf , sec , offset ,
385+ ret = arch_decode_instruction (file , sec , offset ,
386386 sec -> len - offset ,
387387 & insn -> len , & insn -> type ,
388388 & insn -> immediate ,
@@ -420,6 +420,82 @@ static int decode_instructions(struct objtool_file *file)
420420 return ret ;
421421}
422422
423+ /*
424+ * Read the pv_ops[] .data table to find the static initialized values.
425+ */
426+ static int add_pv_ops (struct objtool_file * file , const char * symname )
427+ {
428+ struct symbol * sym , * func ;
429+ unsigned long off , end ;
430+ struct reloc * rel ;
431+ int idx ;
432+
433+ sym = find_symbol_by_name (file -> elf , symname );
434+ if (!sym )
435+ return 0 ;
436+
437+ off = sym -> offset ;
438+ end = off + sym -> len ;
439+ for (;;) {
440+ rel = find_reloc_by_dest_range (file -> elf , sym -> sec , off , end - off );
441+ if (!rel )
442+ break ;
443+
444+ func = rel -> sym ;
445+ if (func -> type == STT_SECTION )
446+ func = find_symbol_by_offset (rel -> sym -> sec , rel -> addend );
447+
448+ idx = (rel -> offset - sym -> offset ) / sizeof (unsigned long );
449+
450+ objtool_pv_add (file , idx , func );
451+
452+ off = rel -> offset + 1 ;
453+ if (off > end )
454+ break ;
455+ }
456+
457+ return 0 ;
458+ }
459+
460+ /*
461+ * Allocate and initialize file->pv_ops[].
462+ */
463+ static int init_pv_ops (struct objtool_file * file )
464+ {
465+ static const char * pv_ops_tables [] = {
466+ "pv_ops" ,
467+ "xen_cpu_ops" ,
468+ "xen_irq_ops" ,
469+ "xen_mmu_ops" ,
470+ NULL ,
471+ };
472+ const char * pv_ops ;
473+ struct symbol * sym ;
474+ int idx , nr ;
475+
476+ if (!noinstr )
477+ return 0 ;
478+
479+ file -> pv_ops = NULL ;
480+
481+ sym = find_symbol_by_name (file -> elf , "pv_ops" );
482+ if (!sym )
483+ return 0 ;
484+
485+ nr = sym -> len / sizeof (unsigned long );
486+ file -> pv_ops = calloc (sizeof (struct pv_state ), nr );
487+ if (!file -> pv_ops )
488+ return -1 ;
489+
490+ for (idx = 0 ; idx < nr ; idx ++ )
491+ INIT_LIST_HEAD (& file -> pv_ops [idx ].targets );
492+
493+ for (idx = 0 ; (pv_ops = pv_ops_tables [idx ]); idx ++ )
494+ add_pv_ops (file , pv_ops );
495+
496+ return 0 ;
497+ }
498+
423499static struct instruction * find_last_insn (struct objtool_file * file ,
424500 struct section * sec )
425501{
@@ -893,6 +969,9 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
893969 return NULL ;
894970
895971 if (!insn -> reloc ) {
972+ if (!file )
973+ return NULL ;
974+
896975 insn -> reloc = find_reloc_by_dest_range (file -> elf , insn -> sec ,
897976 insn -> offset , insn -> len );
898977 if (!insn -> reloc ) {
@@ -1882,6 +1961,10 @@ static int decode_sections(struct objtool_file *file)
18821961
18831962 mark_rodata (file );
18841963
1964+ ret = init_pv_ops (file );
1965+ if (ret )
1966+ return ret ;
1967+
18851968 ret = decode_instructions (file );
18861969 if (ret )
18871970 return ret ;
@@ -2663,20 +2746,64 @@ static inline bool func_uaccess_safe(struct symbol *func)
26632746
26642747static inline const char * call_dest_name (struct instruction * insn )
26652748{
2749+ static char pvname [16 ];
2750+ struct reloc * rel ;
2751+ int idx ;
2752+
26662753 if (insn -> call_dest )
26672754 return insn -> call_dest -> name ;
26682755
2756+ rel = insn_reloc (NULL , insn );
2757+ if (rel && !strcmp (rel -> sym -> name , "pv_ops" )) {
2758+ idx = (rel -> addend / sizeof (void * ));
2759+ snprintf (pvname , sizeof (pvname ), "pv_ops[%d]" , idx );
2760+ return pvname ;
2761+ }
2762+
26692763 return "{dynamic}" ;
26702764}
26712765
2672- static inline bool noinstr_call_dest (struct symbol * func )
2766+ static bool pv_call_dest (struct objtool_file * file , struct instruction * insn )
2767+ {
2768+ struct symbol * target ;
2769+ struct reloc * rel ;
2770+ int idx ;
2771+
2772+ rel = insn_reloc (file , insn );
2773+ if (!rel || strcmp (rel -> sym -> name , "pv_ops" ))
2774+ return false;
2775+
2776+ idx = (arch_dest_reloc_offset (rel -> addend ) / sizeof (void * ));
2777+
2778+ if (file -> pv_ops [idx ].clean )
2779+ return true;
2780+
2781+ file -> pv_ops [idx ].clean = true;
2782+
2783+ list_for_each_entry (target , & file -> pv_ops [idx ].targets , pv_target ) {
2784+ if (!target -> sec -> noinstr ) {
2785+ WARN ("pv_ops[%d]: %s" , idx , target -> name );
2786+ file -> pv_ops [idx ].clean = false;
2787+ }
2788+ }
2789+
2790+ return file -> pv_ops [idx ].clean ;
2791+ }
2792+
2793+ static inline bool noinstr_call_dest (struct objtool_file * file ,
2794+ struct instruction * insn ,
2795+ struct symbol * func )
26732796{
26742797 /*
26752798 * We can't deal with indirect function calls at present;
26762799 * assume they're instrumented.
26772800 */
2678- if (!func )
2801+ if (!func ) {
2802+ if (file -> pv_ops )
2803+ return pv_call_dest (file , insn );
2804+
26792805 return false;
2806+ }
26802807
26812808 /*
26822809 * If the symbol is from a noinstr section; we good.
@@ -2695,10 +2822,12 @@ static inline bool noinstr_call_dest(struct symbol *func)
26952822 return false;
26962823}
26972824
2698- static int validate_call (struct instruction * insn , struct insn_state * state )
2825+ static int validate_call (struct objtool_file * file ,
2826+ struct instruction * insn ,
2827+ struct insn_state * state )
26992828{
27002829 if (state -> noinstr && state -> instr <= 0 &&
2701- !noinstr_call_dest (insn -> call_dest )) {
2830+ !noinstr_call_dest (file , insn , insn -> call_dest )) {
27022831 WARN_FUNC ("call to %s() leaves .noinstr.text section" ,
27032832 insn -> sec , insn -> offset , call_dest_name (insn ));
27042833 return 1 ;
@@ -2719,15 +2848,17 @@ static int validate_call(struct instruction *insn, struct insn_state *state)
27192848 return 0 ;
27202849}
27212850
2722- static int validate_sibling_call (struct instruction * insn , struct insn_state * state )
2851+ static int validate_sibling_call (struct objtool_file * file ,
2852+ struct instruction * insn ,
2853+ struct insn_state * state )
27232854{
27242855 if (has_modified_stack_frame (insn , state )) {
27252856 WARN_FUNC ("sibling call from callable instruction with modified stack frame" ,
27262857 insn -> sec , insn -> offset );
27272858 return 1 ;
27282859 }
27292860
2730- return validate_call (insn , state );
2861+ return validate_call (file , insn , state );
27312862}
27322863
27332864static int validate_return (struct symbol * func , struct instruction * insn , struct insn_state * state )
@@ -2880,7 +3011,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
28803011
28813012 case INSN_CALL :
28823013 case INSN_CALL_DYNAMIC :
2883- ret = validate_call (insn , & state );
3014+ ret = validate_call (file , insn , & state );
28843015 if (ret )
28853016 return ret ;
28863017
@@ -2899,7 +3030,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
28993030 case INSN_JUMP_CONDITIONAL :
29003031 case INSN_JUMP_UNCONDITIONAL :
29013032 if (is_sibling_call (insn )) {
2902- ret = validate_sibling_call (insn , & state );
3033+ ret = validate_sibling_call (file , insn , & state );
29033034 if (ret )
29043035 return ret ;
29053036
@@ -2921,7 +3052,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
29213052 case INSN_JUMP_DYNAMIC :
29223053 case INSN_JUMP_DYNAMIC_CONDITIONAL :
29233054 if (is_sibling_call (insn )) {
2924- ret = validate_sibling_call (insn , & state );
3055+ ret = validate_sibling_call (file , insn , & state );
29253056 if (ret )
29263057 return ret ;
29273058 }
0 commit comments