<s> static inline long long load_byte ( void * skb __attribute__ ( ( unused ) ) , unsigned long long off ) { return __builtin_bpf_load_byte ( off ) ; } </s>

Functions to emit BPF_LD_ABS and BPF_LD_IND instructions . We provide the `` standard '' names as synonyms of the corresponding GCC builtins . Note how the SKB argument is ignored .


"unsupported variable size field access"

"invalid second argument to built-in function"

Expand a call to __builtin_preserve_field_info by evaluating the requested information about SRC according to KIND , and return a tree holding the result .


<s> static bool bpf_core_is_maybe_aggregate_access ( tree expr ) { switch ( TREE_CODE ( expr ) ) { case COMPONENT_REF : case BIT_FIELD_REF : case ARRAY_REF : case ARRAY_RANGE_REF : return true ; case ADDR_EXPR : case NOP_EXPR : return bpf_core_is_maybe_aggregate_access ( TREE_OPERAND ( expr , 0 ) ) ; default : return false ; } } </s>

Return whether EXPR could access some aggregate data structure that BPF CO-RE support needs to know about .


<s> static tree bpf_core_newdecl ( tree type , enum bpf_builtins which ) { tree rettype ; char name [ 80 ] ; static unsigned long pai_count = 0 ; static unsigned long pfi_count = 0 ; switch ( which ) { case BPF_BUILTIN_PRESERVE_ACCESS_INDEX : { rettype = build_function_type_list ( type , type , NULL ) ; int len = snprintf ( name , sizeof ( name ) , "%s" , "__builtin_pai_" ) ; len = snprintf ( name + len , sizeof ( name ) - len , "%lu" , pai_count ++ ) ; } break ; case BPF_BUILTIN_PRESERVE_FIELD_INFO : { rettype = build_function_type_list ( unsigned_type_node , type , unsigned_type_node , NULL ) ; int len = snprintf ( name , sizeof ( name ) , "%s" , "__builtin_pfi_" ) ; len = snprintf ( name + len , sizeof ( name ) - len , "%lu" , pfi_count ++ ) ; } break ; default : gcc_unreachable ( ) ; } return add_builtin_function_ext_scope ( name , rettype , - which , BUILT_IN_MD , NULL , NULL_TREE ) ; } </s>

Synthesize a new builtin function declaration with signature TYPE . Used by bpf_resolve_overloaded_builtin to resolve calls to __builtin_preserve_access_index .


<s> static tree bpf_core_walk ( tree * tp , int * walk_subtrees , void * data ) { struct core_walk_data * dat = ( struct core_walk_data * ) data ; if ( TYPE_P ( * tp ) ) { * walk_subtrees = 0 ; return NULL_TREE ; } tree newdecl = bpf_core_newdecl ( TREE_TYPE ( * tp ) , dat -> which ) ; if ( dat -> which == BPF_BUILTIN_PRESERVE_ACCESS_INDEX ) { if ( bpf_core_is_maybe_aggregate_access ( * tp ) ) { * tp = build_call_expr_loc ( dat -> loc , newdecl , 1 , * tp ) ; * walk_subtrees = 0 ; } } else { * tp = build_call_expr_loc ( dat -> loc , newdecl , 2 , * tp , dat -> arg ) ; * walk_subtrees = 0 ; } return NULL_TREE ; } </s>

Callback function used with walk_tree from bpf_resolve_overloaded_builtin .


<s>
static
rtx
bpf_expand_builtin
(
tree
exp
,
rtx
target
ATTRIBUTE_UNUSED
,
rtx
subtarget
ATTRIBUTE_UNUSED
,
machine_mode
mode
ATTRIBUTE_UNUSED
,
int
ignore
ATTRIBUTE_UNUSED
)
{
tree
fndecl
=
TREE_OPERAND
(
CALL_EXPR_FN
(
exp
)
,
0
)
;
int
code
=
DECL_MD_FUNCTION_CODE
(
fndecl
)
;
if
(
code
==
BPF_BUILTIN_LOAD_BYTE
||
code
==
BPF_BUILTIN_LOAD_HALF
||
code
==
BPF_BUILTIN_LOAD_WORD
)
{
enum
insn_code
abs_icode
=
(
code
==
BPF_BUILTIN_LOAD_BYTE
CODE_FOR_ldabsb
:
code
==
BPF_BUILTIN_LOAD_HALF
CODE_FOR_ldabsh
:
CODE_FOR_ldabsw
)
;
enum
insn_code
ind_icode
=
(
code
==
BPF_BUILTIN_LOAD_BYTE
CODE_FOR_ldindb
:
code
==
BPF_BUILTIN_LOAD_HALF
CODE_FOR_ldindh
:
CODE_FOR_ldindw
)
;
tree
offset_arg
=
CALL_EXPR_ARG
(
exp
,
0
)
;
struct
expand_operand
ops
[
2
]
;
create_input_operand
(
&
ops
[
0
]
,
expand_normal
(
offset_arg
)
,
TYPE_MODE
(
TREE_TYPE
(
offset_arg
)
)
)
;
create_input_operand
(
&
ops
[
1
]
,
const0_rtx
,
SImode
)
;
if
(
!
maybe_expand_insn
(
abs_icode
,
2
,
ops
)
&&
!
maybe_expand_insn
(
ind_icode
,
2
,
ops
)
)
{
error
(
"invalid argument to built-in function"
)
;
return
gen_rtx_REG
(
ops
[
0
]
.
mode
,
BPF_R0
)
;
}
return
gen_rtx_REG
(
ops
[
0
]
.
mode
,
BPF_R0
)
;
}
else
if
(
code
==
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
)
{
tree
arg
=
CALL_EXPR_ARG
(
exp
,
0
)
;
if
(
arg
==
NULL_TREE
)
return
NULL_RTX
;
if
(
TREE_CODE
(
arg
)
==
SSA_NAME
)
{
gimple
*
def_stmt
=
SSA_NAME_DEF_STMT
(
arg
)
;
if
(
is_gimple_assign
(
def_stmt
)
)
arg
=
gimple_assign_rhs1
(
def_stmt
)
;
else
return
expand_normal
(
arg
)
;
}
if
(
!
is_attr_preserve_access
(
arg
)
)
maybe_make_core_relo
(
arg
,
BPF_RELO_FIELD_BYTE_OFFSET
)
;
return
expand_normal
(
arg
)
;
}
else
if
(
code
==
BPF_BUILTIN_PRESERVE_FIELD_INFO
)
{
tree
src
=
CALL_EXPR_ARG
(
exp
,
0
)
;
tree
kind_tree
=
CALL_EXPR_ARG
(
exp
,
1
)
;
unsigned
HOST_WIDE_INT
kind_val
=
0
;
if
(
tree_fits_uhwi_p
(
kind_tree
)
)
kind_val
=
tree_to_uhwi
(
kind_tree
)
;
else
{
error
(
"invalid argument to built-in function"
)
;
return
expand_normal
(
error_mark_node
)
;
}
enum
btf_core_reloc_kind
kind
=
(
enum
btf_core_reloc_kind
)
kind_val
;
if
(
TREE_CODE
(
src
)
==
SSA_NAME
)
{
gimple
*
def_stmt
=
SSA_NAME_DEF_STMT
(
src
)
;
if
(
is_gimple_assign
(
def_stmt
)
)
src
=
gimple_assign_rhs1
(
def_stmt
)
;
}
if
(
TREE_CODE
(
src
)
==
ADDR_EXPR
)
src
=
TREE_OPERAND
(
src
,
0
)
;
tree
result
=
bpf_core_field_info
(
src
,
kind
)
;
if
(
result
!=
error_mark_node
)
maybe_make_core_relo
(
src
,
kind
)
;
return
expand_normal
(
result
)
;
}
gcc_unreachable
(
)
;
}
</s>

Expand a call to a BPF-specific built-in function that was set up with bpf_init_builtins .


<s> void bpf_expand_epilogue ( void ) { if ( TARGET_XBPF ) { int regno ; int fp_offset = - cfun -> machine -> local_vars_size ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) { if ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( cfun -> calls_alloca && regno == STACK_POINTER_REGNUM ) ) { rtx mem ; if ( ! IN_RANGE ( fp_offset , - 1 - 0x7fff , 0x7fff ) ) break ; else { mem = gen_frame_mem ( DImode , plus_constant ( DImode , hard_frame_pointer_rtx , fp_offset - 8 ) ) ; emit_move_insn ( gen_rtx_REG ( DImode , regno ) , mem ) ; fp_offset -= 8 ; } } } } emit_jump_insn ( gen_exit ( ) ) ; } </s>

Expand to the instructions in a function epilogue . This function is called when expanding the 'epilogue ' pattern in bpf.md .


<s> void bpf_expand_prologue ( void ) { HOST_WIDE_INT size ; size = ( cfun -> machine -> local_vars_size + cfun -> machine -> callee_saved_reg_size ) ; if ( TARGET_XBPF ) { int regno ; int fp_offset = - cfun -> machine -> local_vars_size ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) { if ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( cfun -> calls_alloca && regno == STACK_POINTER_REGNUM ) ) { rtx mem ; if ( ! IN_RANGE ( fp_offset , - 1 - 0x7fff , 0x7fff ) ) break ; else { mem = gen_frame_mem ( DImode , plus_constant ( DImode , hard_frame_pointer_rtx , fp_offset - 8 ) ) ; emit_move_insn ( mem , gen_rtx_REG ( DImode , regno ) ) ; fp_offset -= 8 ; } } } } if ( cfun -> calls_alloca ) { emit_move_insn ( stack_pointer_rtx , hard_frame_pointer_rtx ) ; if ( size > 0 ) { emit_insn ( gen_rtx_SET ( stack_pointer_rtx , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , GEN_INT ( - size ) ) ) ) ; } } } </s>

Expand to the instructions in a function prologue . This function is called when expanding the 'prologue ' pattern in bpf.md .


<s> static void bpf_init_builtins ( void ) { tree ullt = long_long_unsigned_type_node ; def_builtin ( "__builtin_bpf_load_byte" , BPF_BUILTIN_LOAD_BYTE , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_bpf_load_half" , BPF_BUILTIN_LOAD_HALF , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_bpf_load_word" , BPF_BUILTIN_LOAD_WORD , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_preserve_access_index" , BPF_BUILTIN_PRESERVE_ACCESS_INDEX , build_function_type_list ( ptr_type_node , ptr_type_node , 0 ) ) ; def_builtin ( "__builtin_preserve_field_info" , BPF_BUILTIN_PRESERVE_FIELD_INFO , build_function_type_list ( unsigned_type_node , ptr_type_node , unsigned_type_node , 0 ) ) ; } </s>

Define machine-specific built-in functions .


<s> bpf_small_register_classes_for_mode_p static bool bpf_is_valid_preserve_field_info_arg ( tree expr ) { switch ( TREE_CODE ( expr ) ) { case COMPONENT_REF : case BIT_FIELD_REF : case ARRAY_REF : case ARRAY_RANGE_REF : return true ; case NOP_EXPR : return bpf_is_valid_preserve_field_info_arg ( TREE_OPERAND ( expr , 0 ) ) ; case ADDR_EXPR : return ( TREE_CODE ( TREE_TYPE ( TREE_OPERAND ( expr , 0 ) ) ) == ARRAY_TYPE ) ; default : return false ; } } </s>

Return whether EXPR is a valid first argument for a call to __builtin_preserve_field_info .


<s> static bool bpf_legitimate_address_p ( machine_mode mode , rtx x , bool strict ) { switch ( GET_CODE ( x ) ) { case CONST_INT : return ( mode == FUNCTION_MODE ) ; case REG : return bpf_address_base_p ( x , strict ) ; case PLUS : { rtx x0 = XEXP ( x , 0 ) ; rtx x1 = XEXP ( x , 1 ) ; if ( bpf_address_base_p ( x0 , strict ) && GET_CODE ( x1 ) == CONST_INT ) return IN_RANGE ( INTVAL ( x1 ) , - 1 - 0x7fff , 0x7fff ) ; break ; } default : break ; } return false ; } </s>

Return true if X ( a RTX ) is a legitimate memory address on the target machine for a memory operand of mode MODE .


"BPF CO-RE requires BTF debugging information, use %<-gbtf%>"

Override options and do some other initialization .


<s> void bpf_print_operand ( FILE * file , rtx op , int code ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case REG : fprintf ( file , "%s" , reg_names [ REGNO ( op ) ] ) ; break ; case MEM : output_address ( GET_MODE ( op ) , XEXP ( op , 0 ) ) ; break ; case CONST_DOUBLE : if ( GET_MODE ( op ) == VOIDmode ) { if ( CONST_DOUBLE_HIGH ( op ) ) fprintf ( file , HOST_WIDE_INT_PRINT_DOUBLE_HEX , CONST_DOUBLE_HIGH ( op ) , CONST_DOUBLE_LOW ( op ) ) ; else if ( CONST_DOUBLE_LOW ( op ) < 0 ) fprintf ( file , HOST_WIDE_INT_PRINT_HEX , CONST_DOUBLE_LOW ( op ) ) ; else fprintf ( file , HOST_WIDE_INT_PRINT_DEC , CONST_DOUBLE_LOW ( op ) ) ; } else { long vals [ 2 ] ; real_to_target ( vals , CONST_DOUBLE_REAL_VALUE ( op ) , GET_MODE ( op ) ) ; vals [ 0 ] &= 0xffffffff ; vals [ 1 ] &= 0xffffffff ; if ( GET_MODE ( op ) == SFmode ) fprintf ( file , "0x%08lx" , vals [ 0 ] ) ; else if ( GET_MODE ( op ) == DFmode ) { if ( WORDS_BIG_ENDIAN ) fprintf ( file , "0x%08lx%08lx" , vals [ 0 ] , vals [ 1 ] ) ; else fprintf ( file , "0x%08lx%08lx" , vals [ 1 ] , vals [ 0 ] ) ; } else gcc_unreachable ( ) ; } break ; default : output_addr_const ( file , op ) ; } } </s>

Print an instruction operand . This function is called in the macro PRINT_OPERAND defined in bpf.h


<s>
static
tree
bpf_resolve_overloaded_builtin
(
location_t
loc
,
tree
fndecl
,
void
*
arglist
)
{
enum
bpf_builtins
which
=
(
enum
bpf_builtins
)
DECL_MD_FUNCTION_CODE
(
fndecl
)
;
if
(
which
<
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
||
which
>=
BPF_BUILTIN_MAX
)
return
NULL_TREE
;
vec
<
tree
,
va_gc
>
*
params
=
static_cast
<
vec
<
tree
,
va_gc
>
*
>
(
arglist
)
;
unsigned
n_params
=
params
params
->
length
(
)
:
0
;
if
(
!
(
which
==
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
&&
n_params
==
1
)
&&
n_params
!=
2
)
{
error_at
(
loc
,
"wrong number of arguments"
)
;
return
error_mark_node
;
}
tree
param
=
(
*
params
)
[
0
]
;
if
(
which
==
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
&&
!
TARGET_BPF_CORE
)
return
param
;
else
if
(
which
==
BPF_BUILTIN_PRESERVE_FIELD_INFO
&&
!
bpf_is_valid_preserve_field_info_arg
(
param
)
)
{
error_at
(
EXPR_LOC_OR_LOC
(
param
,
loc
)
,
"argument is not a field access"
)
;
return
error_mark_node
;
}
if
(
TREE_CODE
(
param
)
==
C_MAYBE_CONST_EXPR
)
param
=
C_MAYBE_CONST_EXPR_EXPR
(
param
)
;
struct
core_walk_data
data
;
data
.
loc
=
loc
;
data
.
which
=
which
;
if
(
which
==
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
)
data
.
arg
=
NULL_TREE
;
else
data
.
arg
=
(
*
params
)
[
1
]
;
walk_tree
(
&
param
,
bpf_core_walk
,
(
void
*
)
&
data
,
)
;
return
param
;
}
</s>

Implement TARGET_RESOLVE_OVERLOADED_BUILTIN ( see gccint manual section Target Macros : :Misc. ) . Used for CO-RE support builtins such as __builtin_preserve_access_index and __builtin_preserve_field_info . FNDECL is the declaration of the builtin , and ARGLIST is the list of arguments passed to it , and is really a vec < tree , _ > * .


<s> static bool bpf_small_register_classes_for_mode_p ( machine_mode mode ) { if ( TARGET_XBPF ) return 1 ; else return ( mode != FUNCTION_MODE ) ; } </s>

Implement target hook small_register_classes_for_mode_p .


<s> static void handle_attr_preserve ( function * fn ) { basic_block bb ; rtx_insn * insn ; FOR_EACH_BB_FN ( bb , fn ) { FOR_BB_INSNS ( bb , insn ) { if ( ! NONJUMP_INSN_P ( insn ) ) continue ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) != SET ) continue ; start_sequence ( ) ; for ( int i = 0 ; i < 2 ; i ++ ) { rtx mem = XEXP ( pat , i ) ; if ( MEM_P ( mem ) ) { tree expr = MEM_EXPR ( mem ) ; if ( ! expr ) continue ; if ( TREE_CODE ( expr ) == MEM_REF && TREE_CODE ( TREE_OPERAND ( expr , 0 ) ) == SSA_NAME ) { gimple * def_stmt = SSA_NAME_DEF_STMT ( TREE_OPERAND ( expr , 0 ) ) ; if ( def_stmt && is_gimple_assign ( def_stmt ) ) expr = gimple_assign_rhs1 ( def_stmt ) ; } if ( is_attr_preserve_access ( expr ) ) maybe_make_core_relo ( expr , BPF_RELO_FIELD_BYTE_OFFSET ) ; } } rtx_insn * seq = get_insns ( ) ; end_sequence ( ) ; emit_insn_before ( seq , insn ) ; } } } </s>

The body of pass_bpf_core_attr . Scan RTL for accesses to structs/unions marked with __attribute__ ( ( preserve_access_index ) ) and generate a CO-RE relocation for any such access .


<s> static void maybe_make_core_relo ( tree expr , enum btf_core_reloc_kind kind ) { if ( ! TARGET_BPF_CORE ) return ; auto_vec < unsigned int , 16 > accessors ; tree container = bpf_core_compute ( expr , & accessors ) ; if ( accessors . length ( ) < 1 ) return ; accessors . reverse ( ) ; rtx_code_label * label = gen_label_rtx ( ) ; LABEL_PRESERVE_P ( label ) = 1 ; emit_label ( label ) ; const char * section_name ; if ( current_function_decl && DECL_SECTION_NAME ( current_function_decl ) ) section_name = DECL_SECTION_NAME ( current_function_decl ) ; else section_name = ".text" ; bpf_core_reloc_add ( TREE_TYPE ( container ) , section_name , & accessors , label , kind ) ; } </s>

BPF Compile Once - Run Everywhere ( CO-RE ) support . Construct a CO-RE relocation record for EXPR of kind KIND to be emitted in the .BTF.ext section . Does nothing if we are not targetting BPF CO-RE , or if the constructed relocation would be a no-op .


<s> static inline bool bpf_address_base_p ( rtx x , bool strict ) { return ( GET_CODE ( x ) == REG && ( REGNO ( x ) < 11 || ( ! strict && REGNO ( x ) >= FIRST_PSEUDO_REGISTER ) ) ) ; } </s>

Return ` true ' if the given RTX X is a valid base for an indirect memory access . STRICT has the same meaning than in bpf_legitimate_address_p .


<s> static void bpf_asm_init_sections ( void ) { if ( TARGET_BPF_CORE ) btf_ext_init ( ) ; } </s>


<s> static void bpf_asm_named_section ( const char * name , unsigned int flags ATTRIBUTE_UNUSED , tree decl ATTRIBUTE_UNUSED ) { fprintf ( asm_out_file , "\t.section\t%s\n" , name ) ; } </s>

Output assembly directives to switch to section NAME . The section should have attributes as specified by FLAGS , which is a bit mask of the 'SECTION_ * ' flags defined in 'output.h ' . If DECL is non-NULL , it is the 'VAR_DECL ' or 'FUNCTION_DECL ' with which this section is associated .


<s>
static
void
bpf_compute_frame_layout
(
void
)
{
int
stack_alignment
=
STACK_BOUNDARY
/
BITS_PER_UNIT
;
int
padding_locals
,
regno
;
cfun
->
machine
->
local_vars_size
=
get_frame_size
(
)
;
padding_locals
=
cfun
->
machine
->
local_vars_size
%
stack_alignment
;
if
(
padding_locals
)
padding_locals
=
stack_alignment
padding_locals
;
cfun
->
machine
->
local_vars_size
+=
padding_locals
;
if
(
TARGET_XBPF
)
{
for
(
regno
=
0
;
regno
<
FIRST_PSEUDO_REGISTER
;
regno
++
)
if
(
(
df_regs_ever_live_p
(
regno
)
&&
!
call_used_or_fixed_reg_p
(
regno
)
)
||
(
cfun
->
calls_alloca
&&
regno
==
STACK_POINTER_REGNUM
)
)
cfun
->
machine
->
callee_saved_reg_size
+=
8
;
}
if
(
(
cfun
->
machine
->
local_vars_size
+
cfun
->
machine
->
callee_saved_reg_size
)
>
bpf_frame_limit
)
{
static
int
stack_limit_exceeded
=
0
;
if
(
!
stack_limit_exceeded
)
error
(
"eBPF stack limit exceeded"
)
;
stack_limit_exceeded
=
1
;
}
}
</s>

Compute the size of the function 's stack frame , including the local area and the register-save area .


<s> static tree bpf_core_compute ( tree node , vec < unsigned int > * accessors ) { if ( TREE_CODE ( node ) == ADDR_EXPR ) node = TREE_OPERAND ( node , 0 ) ; else if ( TREE_CODE ( node ) == INDIRECT_REF || TREE_CODE ( node ) == POINTER_PLUS_EXPR ) { accessors -> safe_push ( 0 ) ; return TREE_OPERAND ( node , 0 ) ; } while ( 1 ) { switch ( TREE_CODE ( node ) ) { case COMPONENT_REF : accessors -> safe_push ( bpf_core_get_index ( TREE_OPERAND ( node , 1 ) ) ) ; break ; case ARRAY_REF : case ARRAY_RANGE_REF : accessors -> safe_push ( bpf_core_get_index ( node ) ) ; break ; case MEM_REF : accessors -> safe_push ( bpf_core_get_index ( node ) ) ; if ( TREE_CODE ( TREE_OPERAND ( node , 0 ) ) == ADDR_EXPR ) node = TREE_OPERAND ( TREE_OPERAND ( node , 0 ) , 0 ) ; goto done ; default : goto done ; } node = TREE_OPERAND ( node , 0 ) ; } done : return node ; } </s>

Traverse the subtree under NODE , which is expected to be some form of aggregate access the CO-RE machinery cares about ( like a read of a member of a struct or union ) , collecting access indices for the components and storing them in the vector referenced by ACCESSORS . Return the ultimate ( top-level ) container of the aggregate access . In general , this will be a VAR_DECL or some kind of REF . Note that the accessors are computed * in reverse order * of how the BPF CO-RE machinery defines them . The vector needs to be reversed ( or simply output in reverse order ) for the .BTF.ext relocation information .


<s> static int bpf_core_get_index ( const tree node ) { enum tree_code code = TREE_CODE ( node ) ; if ( code == FIELD_DECL ) { int idx = bpf_core_get_sou_member_index ( ctf_get_tu_ctfc ( ) , node ) ; if ( idx >= 0 ) return idx ; } else if ( code == ARRAY_REF || code == ARRAY_RANGE_REF || code == MEM_REF ) { tree index = TREE_OPERAND ( node , 1 ) ; if ( TREE_CODE ( index ) == INTEGER_CST && tree_fits_shwi_p ( index ) ) return tree_to_shwi ( index ) ; } return - 1 ; } </s>

Compute the index of the NODE in its immediate container . NODE should be a FIELD_DECL ( i.e . of struct or union ) , or an ARRAY_REF .


<s> static int bpf_core_is_maybe_aggregate_access ( tree expr ) { enum tree_code code = TREE_CODE ( expr ) ; if ( code == COMPONENT_REF || code == ARRAY_REF ) return 1 ; if ( code == ADDR_EXPR ) return bpf_core_is_maybe_aggregate_access ( TREE_OPERAND ( expr , 0 ) ) ; return 0 ; } </s>

Return whether EXPR could access some aggregate data structure that BPF CO-RE support needs to know about .


<s> static tree bpf_core_newdecl ( tree type ) { tree rettype = build_function_type_list ( type , type , NULL ) ; char name [ 80 ] ; int len = snprintf ( name , sizeof ( name ) , "%s" , "__builtin_pai_" ) ; static unsigned long cnt = 0 ; len = snprintf ( name + len , sizeof ( name ) - len , "%lu" , cnt ++ ) ; return add_builtin_function_ext_scope ( name , rettype , - 1 , BUILT_IN_MD , NULL , NULL_TREE ) ; } </s>

Synthesize a new builtin function declaration with signature TYPE . Used by bpf_resolve_overloaded_builtin to resolve calls to __builtin_preserve_access_index .


<s> static tree bpf_core_walk ( tree * tp , int * walk_subtrees , void * data ) { location_t loc = * ( ( location_t * ) data ) ; if ( TYPE_P ( * tp ) ) { * walk_subtrees = 0 ; return NULL_TREE ; } if ( bpf_core_is_maybe_aggregate_access ( * tp ) ) { tree newdecl = bpf_core_newdecl ( TREE_TYPE ( * tp ) ) ; tree newcall = build_call_expr_loc ( loc , newdecl , 1 , * tp ) ; * tp = newcall ; * walk_subtrees = 0 ; } return NULL_TREE ; } </s>

Callback function used with walk_tree from bpf_resolve_overloaded_builtin .


<s> static enum unwind_info_type bpf_debug_unwind_info ( ) { return UI_NONE ; } </s>

Define the mechanism that will be used for describing frame unwind information to the debugger . In eBPF it is not possible to unwind frames .


<s>
static
rtx
bpf_expand_builtin
(
tree
exp
,
rtx
target
ATTRIBUTE_UNUSED
,
rtx
subtarget
ATTRIBUTE_UNUSED
,
machine_mode
mode
ATTRIBUTE_UNUSED
,
int
ignore
ATTRIBUTE_UNUSED
)
{
tree
fndecl
=
TREE_OPERAND
(
CALL_EXPR_FN
(
exp
)
,
0
)
;
int
code
=
DECL_MD_FUNCTION_CODE
(
fndecl
)
;
if
(
code
==
BPF_BUILTIN_LOAD_BYTE
||
code
==
BPF_BUILTIN_LOAD_HALF
||
code
==
BPF_BUILTIN_LOAD_WORD
)
{
enum
insn_code
abs_icode
=
(
code
==
BPF_BUILTIN_LOAD_BYTE
CODE_FOR_ldabsb
:
code
==
BPF_BUILTIN_LOAD_HALF
CODE_FOR_ldabsh
:
CODE_FOR_ldabsw
)
;
enum
insn_code
ind_icode
=
(
code
==
BPF_BUILTIN_LOAD_BYTE
CODE_FOR_ldindb
:
code
==
BPF_BUILTIN_LOAD_HALF
CODE_FOR_ldindh
:
CODE_FOR_ldindw
)
;
tree
offset_arg
=
CALL_EXPR_ARG
(
exp
,
0
)
;
struct
expand_operand
ops
[
2
]
;
create_input_operand
(
&
ops
[
0
]
,
expand_normal
(
offset_arg
)
,
TYPE_MODE
(
TREE_TYPE
(
offset_arg
)
)
)
;
create_input_operand
(
&
ops
[
1
]
,
const0_rtx
,
SImode
)
;
if
(
!
maybe_expand_insn
(
abs_icode
,
2
,
ops
)
&&
!
maybe_expand_insn
(
ind_icode
,
2
,
ops
)
)
{
error
(
"invalid argument to built-in function"
)
;
return
gen_rtx_REG
(
ops
[
0
]
.
mode
,
BPF_R0
)
;
}
return
gen_rtx_REG
(
ops
[
0
]
.
mode
,
BPF_R0
)
;
}
else
if
(
code
==
1
)
{
tree
arg
=
CALL_EXPR_ARG
(
exp
,
0
)
;
if
(
arg
==
NULL_TREE
)
return
NULL_RTX
;
auto_vec
<
unsigned
int
,
16
>
accessors
;
tree
container
;
if
(
TREE_CODE
(
arg
)
==
SSA_NAME
)
{
gimple
*
def_stmt
=
SSA_NAME_DEF_STMT
(
arg
)
;
if
(
is_gimple_assign
(
def_stmt
)
)
arg
=
gimple_assign_rhs1
(
def_stmt
)
;
else
return
expand_normal
(
arg
)
;
}
if
(
is_attr_preserve_access
(
arg
)
)
return
expand_normal
(
arg
)
;
container
=
bpf_core_compute
(
arg
,
&
accessors
)
;
if
(
accessors
.
length
(
)
<
1
)
return
expand_normal
(
arg
)
;
accessors
.
reverse
(
)
;
container
=
TREE_TYPE
(
container
)
;
rtx_code_label
*
label
=
gen_label_rtx
(
)
;
LABEL_PRESERVE_P
(
label
)
=
1
;
emit_label
(
label
)
;
const
char
*
section_name
;
if
(
current_function_decl
&&
DECL_SECTION_NAME
(
current_function_decl
)
)
section_name
=
DECL_SECTION_NAME
(
current_function_decl
)
;
else
section_name
=
".text"
;
bpf_core_reloc_add
(
container
,
section_name
,
&
accessors
,
label
)
;
return
expand_normal
(
arg
)
;
}
gcc_unreachable
(
)
;
}
</s>

Expand a call to a BPF-specific built-in function that was set up with bpf_init_builtins .


<s> void bpf_expand_cbranch ( machine_mode mode , rtx * operands ) { if ( bpf_has_jmpext ) return ; enum rtx_code code = GET_CODE ( operands [ 0 ] ) ; if ( ( code == LT || code == LE || code == LTU || code == LEU ) ) { PUT_CODE ( operands [ 0 ] , reverse_condition ( code ) ) ; if ( ! register_operand ( operands [ 2 ] , mode ) ) operands [ 2 ] = force_reg ( mode , operands [ 2 ] ) ; rtx tmp = operands [ 1 ] ; operands [ 1 ] = operands [ 2 ] ; operands [ 2 ] = tmp ; } } </s>

Expand to the instructions for a conditional branch . This function is called when expanding the 'cbranch < mode > 4 ' pattern in bpf.md .


<s> void bpf_expand_epilogue ( void ) { if ( TARGET_XBPF ) { rtx insn ; int regno ; int fp_offset = - cfun -> machine -> local_vars_size ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) { if ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( cfun -> calls_alloca && regno == STACK_POINTER_REGNUM ) ) { rtx mem ; if ( ! IN_RANGE ( fp_offset , - 1 - 0x7fff , 0x7fff ) ) break ; else { mem = gen_frame_mem ( DImode , plus_constant ( DImode , hard_frame_pointer_rtx , fp_offset - 8 ) ) ; insn = emit_move_insn ( gen_rtx_REG ( DImode , regno ) , mem ) ; fp_offset -= 8 ; } } } } emit_jump_insn ( gen_exit ( ) ) ; } </s>

Expand to the instructions in a function epilogue . This function is called when expanding the 'epilogue ' pattern in bpf.md .


<s> void bpf_expand_prologue ( void ) { rtx insn ; HOST_WIDE_INT size ; size = ( cfun -> machine -> local_vars_size + cfun -> machine -> callee_saved_reg_size ) ; if ( TARGET_XBPF ) { int regno ; int fp_offset = - cfun -> machine -> local_vars_size ; for ( regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno ++ ) { if ( ( df_regs_ever_live_p ( regno ) && ! call_used_or_fixed_reg_p ( regno ) ) || ( cfun -> calls_alloca && regno == STACK_POINTER_REGNUM ) ) { rtx mem ; if ( ! IN_RANGE ( fp_offset , - 1 - 0x7fff , 0x7fff ) ) break ; else { mem = gen_frame_mem ( DImode , plus_constant ( DImode , hard_frame_pointer_rtx , fp_offset - 8 ) ) ; insn = emit_move_insn ( mem , gen_rtx_REG ( DImode , regno ) ) ; fp_offset -= 8 ; } } } } if ( cfun -> calls_alloca ) { insn = emit_move_insn ( stack_pointer_rtx , hard_frame_pointer_rtx ) ; if ( size > 0 ) { insn = emit_insn ( gen_rtx_SET ( stack_pointer_rtx , gen_rtx_PLUS ( Pmode , stack_pointer_rtx , GEN_INT ( - size ) ) ) ) ; } } } </s>

Expand to the instructions in a function prologue . This function is called when expanding the 'prologue ' pattern in bpf.md .


<s> static void bpf_file_end ( void ) { if ( TARGET_BPF_CORE ) btf_ext_output ( ) ; } </s>


<s> static bool bpf_frame_pointer_required ( void ) { return true ; } </s>

Return true if a function must have and use a frame pointer .


<s> static rtx bpf_function_arg ( cumulative_args_t ca , const function_arg_info & arg ) { CUMULATIVE_ARGS * cum = get_cumulative_args ( ca ) ; if ( * cum < 5 ) return gen_rtx_REG ( arg . mode , * cum + 1 ) ; else return NULL_RTX ; } </s>

Return a RTX indicating whether a function argument is passed in a register and if so , which register .


<s>
static
void
bpf_function_arg_advance
(
cumulative_args_t
ca
,
const
function_arg_info
&
arg
)
{
CUMULATIVE_ARGS
*
cum
=
get_cumulative_args
(
ca
)
;
unsigned
num_bytes
=
arg
.
type_size_in_bytes
(
)
;
unsigned
num_words
=
CEIL
(
num_bytes
,
UNITS_PER_WORD
)
;
if
(
*
cum
<=
5
&&
*
cum
+
num_words
>
5
)
error
(
"too many function arguments for eBPF"
)
;
*
cum
+=
num_words
;
}
</s>

Update the summarizer variable pointed by CA to advance past an argument in the argument list .


<s> static rtx bpf_function_value ( const_tree ret_type , const_tree fntype_or_decl , bool outgoing ATTRIBUTE_UNUSED ) { enum machine_mode mode ; int unsignedp ; mode = TYPE_MODE ( ret_type ) ; if ( INTEGRAL_TYPE_P ( ret_type ) ) mode = promote_function_mode ( ret_type , mode , & unsignedp , fntype_or_decl , 1 ) ; return gen_rtx_REG ( mode , BPF_R0 ) ; } </s>

Return an RTX representing the place where a function returns or receives a value of data type RET_TYPE , a tree node representing a data type .


<s> static bool bpf_function_value_regno_p ( const unsigned int regno ) { return ( regno == BPF_R0 ) ; } </s>

Return true if REGNO is the number of a hard register in which the values of called function may come back .


"%qE attribute only applies to functions"

"%qE attribute requires an integer argument"

Handle an attribute requiring a FUNCTION_DECL ; arguments as in struct attribute_spec.handler .


"%qE attribute only applies to structure, union and class types"

Handle preserve_access_index attribute , which can be applied to structs , unions and classes . Actually adding the attribute to the TYPE_DECL is taken care of for us , so just warn for types that are n't supported .


<s> static bool bpf_hard_regno_mode_ok ( unsigned int regno ATTRIBUTE_UNUSED , enum machine_mode mode ) { switch ( mode ) { case E_SImode : case E_DImode : case E_HImode : case E_QImode : case E_TImode : case E_SFmode : case E_DFmode : return true ; default : return false ; } } </s>

Return true if it is permissible to store a value of mode MODE in hard register number REGNO , or in several registers starting with that one .


<s> static unsigned int bpf_hard_regno_nregs ( unsigned int regno ATTRIBUTE_UNUSED , enum machine_mode mode ) { return CEIL ( GET_MODE_SIZE ( mode ) , UNITS_PER_WORD ) ; } </s>

Return the number of consecutive hard registers , starting at register number REGNO , required to hold a value of mode MODE .


<s> static inline int bpf_helper_code ( const char * name ) { int i ; for ( i = 1 ; i < BPF_BUILTIN_HELPER_MAX ; ++ i ) if ( strcmp ( name , bpf_helper_names [ i ] ) == 0 ) return i ; return 0 ; } </s>

Return the builtin code corresponding to the kernel helper builtin __builtin_NAME , or 0 if the name does n't correspond to a kernel helper builtin .


<s> HOST_WIDE_INT bpf_initial_elimination_offset ( int from , int to ) { HOST_WIDE_INT ret ; if ( from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM ) ret = ( cfun -> machine -> local_vars_size + cfun -> machine -> callee_saved_reg_size ) ; else if ( from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM ) ret = 0 ; else gcc_unreachable ( ) ; return ret ; } </s>

Return the initial difference between the specified pair of registers . The registers that can figure in FROM , and TO , are specified by ELIMINABLE_REGS in bpf.h . This function is used in the definition of INITIAL_ELIMINATION_OFFSET in bpf.h


<s> static void bpf_init_builtins ( void ) { tree ullt = long_long_unsigned_type_node ; def_builtin ( "__builtin_bpf_load_byte" , BPF_BUILTIN_LOAD_BYTE , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_bpf_load_half" , BPF_BUILTIN_LOAD_HALF , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_bpf_load_word" , BPF_BUILTIN_LOAD_WORD , build_function_type_list ( ullt , ullt , 0 ) ) ; def_builtin ( "__builtin_preserve_access_index" , BPF_BUILTIN_PRESERVE_ACCESS_INDEX , build_function_type_list ( ptr_type_node , ptr_type_node , 0 ) ) ; } </s>

Define machine-specific built-in functions .


<s> static void bpf_init_libfuncs ( void ) { set_conv_libfunc ( sext_optab , DFmode , SFmode , "__bpf_extendsfdf2" ) ; set_conv_libfunc ( trunc_optab , SFmode , DFmode , "__bpf_truncdfsf2" ) ; set_conv_libfunc ( sfix_optab , SImode , DFmode , "__bpf_fix_truncdfsi" ) ; set_conv_libfunc ( sfloat_optab , DFmode , SImode , "__bpf_floatsidf" ) ; set_conv_libfunc ( ufloat_optab , DFmode , SImode , "__bpf_floatunsidf" ) ; } </s>

Initialize target-specific function library calls . This is mainly used to call library-provided soft-fp operations , since eBPF does n't support floating-point in `` hardware '' .


<s> static struct machine_function * bpf_init_machine_status ( void ) { return ggc_cleared_alloc < machine_function > ( ) ; } </s>

Initialize the per-function machine status .


<s> static bool bpf_legitimate_address_p ( machine_mode mode ATTRIBUTE_UNUSED , rtx x , bool strict ) { switch ( GET_CODE ( x ) ) { case REG : return bpf_address_base_p ( x , strict ) ; case PLUS : { rtx x0 = XEXP ( x , 0 ) ; rtx x1 = XEXP ( x , 1 ) ; if ( bpf_address_base_p ( x0 , strict ) && GET_CODE ( x1 ) == CONST_INT ) return IN_RANGE ( INTVAL ( x1 ) , - 1 - 0x7fff , 0x7fff ) ; break ; } default : break ; } return false ; } </s>

Return true if X ( a RTX ) is a legitimate memory address on the target machine for a memory operand of mode MODE .


"BPF CO-RE requires BTF debugging information, use %<-gbtf%>"

Override options and do some other initialization .


"indirect call in function, which are not supported by eBPF"

Return the appropriate instruction to CALL to a function . TARGET is an RTX denoting the address of the called function . The main purposes of this function are : - To reject indirect CALL instructions , which are not supported by eBPF . - To recognize calls to kernel helper functions and emit the corresponding CALL N instruction . This function is called from the expansion of the 'call ' pattern in bpf.md .


<s>
static
void
bpf_output_constructor
(
rtx
symbol
,
int
priority
ATTRIBUTE_UNUSED
)
{
tree
decl
=
SYMBOL_REF_DECL
(
symbol
)
;
if
(
decl
)
sorry_at
(
DECL_SOURCE_LOCATION
(
decl
)
,
"no constructors"
)
;
else
sorry
(
"no constructors"
)
;
}
</s>

Output the assembly code for a constructor . Since eBPF does n't support indirect calls , constructors are not supported .


<s>
static
void
bpf_output_destructor
(
rtx
symbol
,
int
priority
ATTRIBUTE_UNUSED
)
{
tree
decl
=
SYMBOL_REF_DECL
(
symbol
)
;
if
(
decl
)
sorry_at
(
DECL_SOURCE_LOCATION
(
decl
)
,
"no destructors"
)
;
else
sorry
(
"no destructors"
)
;
}
</s>

Output the assembly code for a destructor . Since eBPF does n't support indirect calls , destructors are not supported .


<s> static bool bpf_pass_by_reference ( cumulative_args_t cum ATTRIBUTE_UNUSED , const function_arg_info & arg ) { unsigned num_bytes = arg . type_size_in_bytes ( ) ; return ( arg . aggregate_type_p ( ) || ( num_bytes > 8 * 5 ) ) ; } </s>

Return true if an argument at the position indicated by CUM should be passed by reference . If the hook returns true , a copy of that argument is made in memory and a pointer to the argument is passed instead of the argument itself .


<s> void bpf_print_operand ( FILE * file , rtx op , int code ATTRIBUTE_UNUSED ) { switch ( GET_CODE ( op ) ) { case REG : fprintf ( file , "%s" , reg_names [ REGNO ( op ) ] ) ; break ; case MEM : output_address ( GET_MODE ( op ) , XEXP ( op , 0 ) ) ; break ; case CONST_DOUBLE : if ( CONST_DOUBLE_HIGH ( op ) ) fprintf ( file , HOST_WIDE_INT_PRINT_DOUBLE_HEX , CONST_DOUBLE_HIGH ( op ) , CONST_DOUBLE_LOW ( op ) ) ; else if ( CONST_DOUBLE_LOW ( op ) < 0 ) fprintf ( file , HOST_WIDE_INT_PRINT_HEX , CONST_DOUBLE_LOW ( op ) ) ; else fprintf ( file , HOST_WIDE_INT_PRINT_DEC , CONST_DOUBLE_LOW ( op ) ) ; break ; default : output_addr_const ( file , op ) ; } } </s>

Print an instruction operand . This function is called in the macro PRINT_OPERAND defined in bpf.h


<s>
void
bpf_print_operand_address
(
FILE
*
file
,
rtx
addr
)
{
switch
(
GET_CODE
(
addr
)
)
{
case
REG
:
fprintf
(
file
,
"[%s+0]"
,
reg_names
[
REGNO
(
addr
)
]
)
;
break
;
case
PLUS
:
{
rtx
op0
=
XEXP
(
addr
,
0
)
;
rtx
op1
=
XEXP
(
addr
,
1
)
;
if
(
GET_CODE
(
op0
)
==
REG
&&
GET_CODE
(
op1
)
==
CONST_INT
)
{
fprintf
(
file
,
"[%s+"
,
reg_names
[
REGNO
(
op0
)
]
)
;
output_addr_const
(
file
,
op1
)
;
fputs
(
"]"
,
file
)
;
}
else
fatal_insn
(
"invalid address in operand"
,
addr
)
;
break
;
}
case
MEM
:
case
LABEL_REF
:
fatal_insn
(
"unsupported operand"
,
addr
)
;
break
;
default
:
output_addr_const
(
file
,
addr
)
;
break
;
}
}
</s>

Print an operand which is an address . This function should handle any legit address , as accepted by bpf_legitimate_address_p , and also addresses that are valid in CALL instructions . This function is called in the PRINT_OPERAND_ADDRESS macro defined in bpf.h


<s>
static
tree
bpf_resolve_overloaded_builtin
(
location_t
loc
,
tree
fndecl
,
void
*
arglist
)
{
if
(
DECL_MD_FUNCTION_CODE
(
fndecl
)
!=
BPF_BUILTIN_PRESERVE_ACCESS_INDEX
)
return
NULL_TREE
;
vec
<
tree
,
va_gc
>
*
params
=
static_cast
<
vec
<
tree
,
va_gc
>
*
>
(
arglist
)
;
unsigned
n_params
=
params
params
->
length
(
)
:
0
;
if
(
n_params
!=
1
)
{
error_at
(
loc
,
"expected exactly 1 argument"
)
;
return
NULL_TREE
;
}
tree
param
=
(
*
params
)
[
0
]
;
if
(
!
TARGET_BPF_CORE
)
return
param
;
if
(
TREE_CODE
(
param
)
==
C_MAYBE_CONST_EXPR
)
param
=
C_MAYBE_CONST_EXPR_EXPR
(
param
)
;
walk_tree
(
&
param
,
bpf_core_walk
,
(
void
*
)
&
loc
,
)
;
return
param
;
}
</s>

Implement TARGET_RESOLVE_OVERLOADED_BUILTIN ( see gccint manual section Target Macros : :Misc. ) . Used for CO-RE support builtins such as __builtin_preserve_access_index and __builtin_preserve_field_info . FNDECL is the declaration of the builtin , and ARGLIST is the list of arguments passed to it , and is really a vec < tree , _ > * .


<s> static bool bpf_rtx_costs ( rtx x ATTRIBUTE_UNUSED , enum machine_mode mode ATTRIBUTE_UNUSED , int outer_code ATTRIBUTE_UNUSED , int opno ATTRIBUTE_UNUSED , int * total ATTRIBUTE_UNUSED , bool speed ATTRIBUTE_UNUSED ) { return false ; } </s>

Describe the relative costs of RTL expressions . Return true when all subexpressions of X have been processed , and false when ` rtx_cost ' should recurse .


<s> static tree def_builtin ( const char * name , enum bpf_builtins code , tree type ) { tree t = add_builtin_function ( name , type , code , BUILT_IN_MD , NULL , NULL_TREE ) ; bpf_builtins [ code ] = t ; return t ; } </s>

Add a SPARC builtin function with NAME , ICODE , CODE and TYPE . Return the function decl or NULL_TREE if the builtin was not added .


<s> unsigned int pass_bpf_core_attr :: execute ( function * fn ) { handle_attr_preserve ( fn ) ; return 0 ; } </s>


<s> static void handle_attr_preserve ( function * fn ) { basic_block bb ; rtx_insn * insn ; rtx_code_label * label ; FOR_EACH_BB_FN ( bb , fn ) { FOR_BB_INSNS ( bb , insn ) { if ( ! NONJUMP_INSN_P ( insn ) ) continue ; rtx pat = PATTERN ( insn ) ; if ( GET_CODE ( pat ) != SET ) continue ; start_sequence ( ) ; for ( int i = 0 ; i < 2 ; i ++ ) { rtx mem = XEXP ( pat , i ) ; if ( MEM_P ( mem ) ) { tree expr = MEM_EXPR ( mem ) ; if ( ! expr ) continue ; if ( TREE_CODE ( expr ) == MEM_REF && TREE_CODE ( TREE_OPERAND ( expr , 0 ) ) == SSA_NAME ) { gimple * def_stmt = SSA_NAME_DEF_STMT ( TREE_OPERAND ( expr , 0 ) ) ; if ( def_stmt && is_gimple_assign ( def_stmt ) ) expr = gimple_assign_rhs1 ( def_stmt ) ; } if ( is_attr_preserve_access ( expr ) ) { auto_vec < unsigned int , 16 > accessors ; tree container = bpf_core_compute ( expr , & accessors ) ; if ( accessors . length ( ) < 1 ) continue ; accessors . reverse ( ) ; container = TREE_TYPE ( container ) ; const char * section_name ; if ( DECL_SECTION_NAME ( fn -> decl ) ) section_name = DECL_SECTION_NAME ( fn -> decl ) ; else section_name = ".text" ; label = gen_label_rtx ( ) ; LABEL_PRESERVE_P ( label ) = 1 ; emit_label ( label ) ; bpf_core_reloc_add ( container , section_name , & accessors , label ) ; } } } rtx_insn * seq = get_insns ( ) ; end_sequence ( ) ; emit_insn_before ( seq , insn ) ; } } } </s>

The body of pass_bpf_core_attr . Scan RTL for accesses to structs/unions marked with __attribute__ ( ( preserve_access_index ) ) and generate a CO-RE relocation for any such access .


<s> static bool is_attr_preserve_access ( tree t ) { if ( t == NULL_TREE ) return false ; poly_int64 bitsize , bitpos ; tree var_off ; machine_mode mode ; int sign , reverse , vol ; tree base = get_inner_reference ( t , & bitsize , & bitpos , & var_off , & mode , & sign , & reverse , & vol ) ; if ( TREE_CODE ( base ) == MEM_REF ) { return lookup_attribute ( "preserve_access_index" , TYPE_ATTRIBUTES ( TREE_TYPE ( base ) ) ) ; } if ( TREE_CODE ( t ) == COMPONENT_REF ) { const tree op = TREE_OPERAND ( t , 0 ) ; if ( TREE_CODE ( op ) == COMPONENT_REF ) return is_attr_preserve_access ( op ) ; const tree container = DECL_CONTEXT ( TREE_OPERAND ( t , 1 ) ) ; return lookup_attribute ( "preserve_access_index" , TYPE_ATTRIBUTES ( container ) ) ; } else if ( TREE_CODE ( t ) == ADDR_EXPR ) return is_attr_preserve_access ( TREE_OPERAND ( t , 0 ) ) ; return false ; } </s>

True iff tree T accesses any member of a struct/union/class which is marked with the PRESERVE_ACCESS_INDEX attribute .


<s> int bpf_core_get_sou_member_index ( ctf_container_ref ctfc , const tree node ) { if ( TREE_CODE ( node ) == FIELD_DECL ) { const tree container = DECL_CONTEXT ( node ) ; dw_die_ref die = lookup_type_die ( container ) ; if ( die == NULL ) return - 1 ; ctf_dtdef_ref dtd = ctf_dtd_lookup ( ctfc , die ) ; if ( dtd == NULL ) return - 1 ; unsigned int kind = CTF_V2_INFO_KIND ( dtd -> dtd_data . ctti_info ) ; if ( kind != CTF_K_STRUCT && kind != CTF_K_UNION ) return - 1 ; tree field = TYPE_FIELDS ( container ) ; int i = 0 ; ctf_dmdef_t * dmd ; for ( dmd = dtd -> dtd_u . dtu_members ; dmd != NULL ; dmd = ( ctf_dmdef_t * ) ctf_dmd_list_next ( dmd ) ) { bool field_has_btf = get_btf_id ( dmd -> dmd_type ) <= BTF_MAX_TYPE ; if ( field == node ) return field_has_btf ? i : - 1 ; if ( field_has_btf ) i ++ ; field = DECL_CHAIN ( field ) ; } } return - 1 ; } </s>

Return the 0-based index of the field NODE in its containing struct or union type .


<s> void bpf_core_reloc_add ( const tree type , const char * section_name , vec < unsigned int > * accessors , rtx_code_label * label , enum btf_core_reloc_kind kind ) { char buf [ 40 ] ; unsigned int i , n = 0 ; if ( accessors -> length ( ) < 1 ) return ; for ( i = 0 ; i < accessors -> length ( ) - 1 ; i ++ ) n += snprintf ( buf + n , sizeof ( buf ) - n , "%u:" , ( * accessors ) [ i ] ) ; snprintf ( buf + n , sizeof ( buf ) - n , "%u" , ( * accessors ) [ i ] ) ; bpf_core_reloc_ref bpfcr = ggc_cleared_alloc < bpf_core_reloc_t > ( ) ; ctf_container_ref ctfc = ctf_get_tu_ctfc ( ) ; ctf_add_string ( ctfc , buf , & ( bpfcr -> bpfcr_astr_off ) , CTF_AUX_STRTAB ) ; bpfcr -> bpfcr_type = get_btf_id ( ctf_lookup_tree_type ( ctfc , type ) ) ; bpfcr -> bpfcr_insn_label = label ; bpfcr -> bpfcr_kind = kind ; bpf_core_section_ref sec ; FOR_EACH_VEC_ELT ( * bpf_core_sections , i , sec ) if ( strcmp ( sec -> name , section_name ) == 0 ) { vec_safe_push ( sec -> relocs , bpfcr ) ; return ; } sec = ggc_cleared_alloc < bpf_core_section_t > ( ) ; ctf_add_string ( ctfc , section_name , & sec -> name_offset , CTF_AUX_STRTAB ) ; if ( strcmp ( section_name , "" ) ) ctfc -> ctfc_aux_strlen += strlen ( section_name ) + 1 ; sec -> name = section_name ; vec_alloc ( sec -> relocs , 1 ) ; vec_safe_push ( sec -> relocs , bpfcr ) ; vec_safe_push ( bpf_core_sections , sec ) ; } </s>

Create a new BPF CO-RE relocation record , and add it to the appropriate CO-RE section .


<s> int bpf_core_get_sou_member_index ( ctf_container_ref ctfc , const tree node ) { if ( TREE_CODE ( node ) == FIELD_DECL ) { const tree container = DECL_CONTEXT ( node ) ; const char * name = IDENTIFIER_POINTER ( DECL_NAME ( node ) ) ; dw_die_ref die = lookup_type_die ( container ) ; if ( die == NULL ) return - 1 ; ctf_dtdef_ref dtd = ctf_dtd_lookup ( ctfc , die ) ; if ( dtd == NULL ) return - 1 ; unsigned int kind = CTF_V2_INFO_KIND ( dtd -> dtd_data . ctti_info ) ; if ( kind != CTF_K_STRUCT && kind != CTF_K_UNION ) return - 1 ; int i = 0 ; ctf_dmdef_t * dmd ; for ( dmd = dtd -> dtd_u . dtu_members ; dmd != NULL ; dmd = ( ctf_dmdef_t * ) ctf_dmd_list_next ( dmd ) ) { if ( get_btf_id ( dmd -> dmd_type ) > BTF_MAX_TYPE ) continue ; if ( strcmp ( dmd -> dmd_name , name ) == 0 ) return i ; i ++ ; } } return - 1 ; } </s>


<s> void bpf_core_reloc_add ( const tree type , const char * section_name , vec < unsigned int > * accessors , rtx_code_label * label ) { char buf [ 40 ] ; unsigned int i , n = 0 ; if ( accessors -> length ( ) < 1 ) return ; for ( i = 0 ; i < accessors -> length ( ) - 1 ; i ++ ) n += snprintf ( buf + n , sizeof ( buf ) - n , "%u:" , ( * accessors ) [ i ] ) ; snprintf ( buf + n , sizeof ( buf ) - n , "%u" , ( * accessors ) [ i ] ) ; bpf_core_reloc_ref bpfcr = ggc_cleared_alloc < bpf_core_reloc_t > ( ) ; ctf_container_ref ctfc = ctf_get_tu_ctfc ( ) ; ctf_add_string ( ctfc , buf , & ( bpfcr -> bpfcr_astr_off ) , CTF_AUX_STRTAB ) ; bpfcr -> bpfcr_type = get_btf_id ( ctf_lookup_tree_type ( ctfc , type ) ) ; bpfcr -> bpfcr_insn_label = label ; bpfcr -> bpfcr_kind = BPF_RELO_FIELD_BYTE_OFFSET ; bpf_core_section_ref sec ; FOR_EACH_VEC_ELT ( * bpf_core_sections , i , sec ) if ( strcmp ( sec -> name , section_name ) == 0 ) { vec_safe_push ( sec -> relocs , bpfcr ) ; return ; } sec = ggc_cleared_alloc < bpf_core_section_t > ( ) ; ctf_add_string ( ctfc , section_name , & sec -> name_offset , CTF_AUX_STRTAB ) ; if ( strcmp ( section_name , "" ) ) ctfc -> ctfc_aux_strlen += strlen ( section_name ) + 1 ; sec -> name = section_name ; vec_alloc ( sec -> relocs , 1 ) ; vec_safe_push ( sec -> relocs , bpfcr ) ; vec_safe_push ( bpf_core_sections , sec ) ; } </s>


<s> void btf_ext_init ( void ) { btf_ext_info_section = get_section ( BTF_EXT_INFO_SECTION_NAME , BTF_EXT_INFO_SECTION_FLAGS , NULL ) ; ASM_GENERATE_INTERNAL_LABEL ( btf_ext_info_section_label , BTF_EXT_INFO_SECTION_LABEL , btf_ext_label_num ++ ) ; vec_alloc ( bpf_core_sections , 1 ) ; } </s>

Initialize sections , labels , and data structures for BTF.ext output .


<s> void btf_ext_output ( void ) { output_btfext_header ( ) ; output_btfext_core_sections ( ) ; bpf_core_sections = NULL ; } </s>


<s>
static
void
output_asm_btfext_core_reloc
(
bpf_core_reloc_ref
bpfcr
)
{
bpfcr
->
bpfcr_astr_off
+=
ctfc_get_strtab_len
(
ctf_get_tu_ctfc
(
)
,
CTF_STRTAB
)
;
dw2_assemble_integer
(
4
,
gen_rtx_LABEL_REF
(
Pmode
,
bpfcr
->
bpfcr_insn_label
)
)
;
fprintf
(
asm_out_file
,
"\t%s bpfcr_insn\n"
,
ASM_COMMENT_START
)
;
dw2_asm_output_data
(
4
,
bpfcr
->
bpfcr_type
,
"bpfcr_type"
)
;
dw2_asm_output_data
(
4
,
bpfcr
->
bpfcr_astr_off
,
"bpfcr_astr_off"
)
;
dw2_asm_output_data
(
4
,
bpfcr
->
bpfcr_kind
,
"bpfcr_kind"
)
;
}
</s>

Output a single CO-RE relocation record .


<s> static void output_btfext_core_relocs ( bpf_core_section_ref sec ) { size_t i ; bpf_core_reloc_ref bpfcr ; FOR_EACH_VEC_ELT ( * ( sec -> relocs ) , i , bpfcr ) output_asm_btfext_core_reloc ( bpfcr ) ; } </s>

Output all CO-RE relocation records for a section .


<s> static void output_btfext_core_sections ( void ) { size_t i ; bpf_core_section_ref sec ; dw2_asm_output_data ( 4 , sizeof ( struct btf_ext_reloc ) , "btfext_core_info_rec_size" ) ; FOR_EACH_VEC_ELT ( * bpf_core_sections , i , sec ) { sec -> name_offset += ctfc_get_strtab_len ( ctf_get_tu_ctfc ( ) , CTF_STRTAB ) ; dw2_asm_output_data ( 4 , sec -> name_offset , "btfext_secinfo_sec_name_off" ) ; dw2_asm_output_data ( 4 , vec_safe_length ( sec -> relocs ) , "btfext_secinfo_num_recs" ) ; output_btfext_core_relocs ( sec ) ; } } </s>


Compute and output the header of a .BTF.ext debug info section .