@@ -382,7 +382,7 @@ static int decode_instructions(struct objtool_file *file)
382
382
insn -> sec = sec ;
383
383
insn -> offset = offset ;
384
384
385
- ret = arch_decode_instruction (file -> elf , sec , offset ,
385
+ ret = arch_decode_instruction (file , sec , offset ,
386
386
sec -> len - offset ,
387
387
& insn -> len , & insn -> type ,
388
388
& insn -> immediate ,
@@ -420,6 +420,82 @@ static int decode_instructions(struct objtool_file *file)
420
420
return ret ;
421
421
}
422
422
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
+
423
499
static struct instruction * find_last_insn (struct objtool_file * file ,
424
500
struct section * sec )
425
501
{
@@ -893,6 +969,9 @@ static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *i
893
969
return NULL ;
894
970
895
971
if (!insn -> reloc ) {
972
+ if (!file )
973
+ return NULL ;
974
+
896
975
insn -> reloc = find_reloc_by_dest_range (file -> elf , insn -> sec ,
897
976
insn -> offset , insn -> len );
898
977
if (!insn -> reloc ) {
@@ -1882,6 +1961,10 @@ static int decode_sections(struct objtool_file *file)
1882
1961
1883
1962
mark_rodata (file );
1884
1963
1964
+ ret = init_pv_ops (file );
1965
+ if (ret )
1966
+ return ret ;
1967
+
1885
1968
ret = decode_instructions (file );
1886
1969
if (ret )
1887
1970
return ret ;
@@ -2663,20 +2746,64 @@ static inline bool func_uaccess_safe(struct symbol *func)
2663
2746
2664
2747
static inline const char * call_dest_name (struct instruction * insn )
2665
2748
{
2749
+ static char pvname [16 ];
2750
+ struct reloc * rel ;
2751
+ int idx ;
2752
+
2666
2753
if (insn -> call_dest )
2667
2754
return insn -> call_dest -> name ;
2668
2755
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
+
2669
2763
return "{dynamic}" ;
2670
2764
}
2671
2765
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 )
2673
2796
{
2674
2797
/*
2675
2798
* We can't deal with indirect function calls at present;
2676
2799
* assume they're instrumented.
2677
2800
*/
2678
- if (!func )
2801
+ if (!func ) {
2802
+ if (file -> pv_ops )
2803
+ return pv_call_dest (file , insn );
2804
+
2679
2805
return false;
2806
+ }
2680
2807
2681
2808
/*
2682
2809
* If the symbol is from a noinstr section; we good.
@@ -2695,10 +2822,12 @@ static inline bool noinstr_call_dest(struct symbol *func)
2695
2822
return false;
2696
2823
}
2697
2824
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 )
2699
2828
{
2700
2829
if (state -> noinstr && state -> instr <= 0 &&
2701
- !noinstr_call_dest (insn -> call_dest )) {
2830
+ !noinstr_call_dest (file , insn , insn -> call_dest )) {
2702
2831
WARN_FUNC ("call to %s() leaves .noinstr.text section" ,
2703
2832
insn -> sec , insn -> offset , call_dest_name (insn ));
2704
2833
return 1 ;
@@ -2719,15 +2848,17 @@ static int validate_call(struct instruction *insn, struct insn_state *state)
2719
2848
return 0 ;
2720
2849
}
2721
2850
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 )
2723
2854
{
2724
2855
if (has_modified_stack_frame (insn , state )) {
2725
2856
WARN_FUNC ("sibling call from callable instruction with modified stack frame" ,
2726
2857
insn -> sec , insn -> offset );
2727
2858
return 1 ;
2728
2859
}
2729
2860
2730
- return validate_call (insn , state );
2861
+ return validate_call (file , insn , state );
2731
2862
}
2732
2863
2733
2864
static 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,
2880
3011
2881
3012
case INSN_CALL :
2882
3013
case INSN_CALL_DYNAMIC :
2883
- ret = validate_call (insn , & state );
3014
+ ret = validate_call (file , insn , & state );
2884
3015
if (ret )
2885
3016
return ret ;
2886
3017
@@ -2899,7 +3030,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
2899
3030
case INSN_JUMP_CONDITIONAL :
2900
3031
case INSN_JUMP_UNCONDITIONAL :
2901
3032
if (is_sibling_call (insn )) {
2902
- ret = validate_sibling_call (insn , & state );
3033
+ ret = validate_sibling_call (file , insn , & state );
2903
3034
if (ret )
2904
3035
return ret ;
2905
3036
@@ -2921,7 +3052,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
2921
3052
case INSN_JUMP_DYNAMIC :
2922
3053
case INSN_JUMP_DYNAMIC_CONDITIONAL :
2923
3054
if (is_sibling_call (insn )) {
2924
- ret = validate_sibling_call (insn , & state );
3055
+ ret = validate_sibling_call (file , insn , & state );
2925
3056
if (ret )
2926
3057
return ret ;
2927
3058
}
0 commit comments