>> Jose E. Marchesi writes: >> >>>> This patch corrects bugs within the CO-RE builtin field expression >>>> related builtins. >>>> The following bugs were identified and corrected based on the expected >>>> results of bpf-next selftests testsuite. >>>> It addresses the following problems: >>>> - Expressions with pointer dereferencing now point to the BTF structure >>>> type, instead of the structure pointer type. >>>> - Pointer addition to structure root is now identified and constructed >>>> in CO-RE relocations as if it is an array access. For example, >>>> "&(s+2)->b" generates "2:1" as an access string where "2" is >>>> refering to the access for "s+2". >>>> >>>> gcc/ChangeLog: >>>> * config/bpf/core-builtins.cc (core_field_info): Add >>>> support for POINTER_PLUS_EXPR in the root of the field expression. >>>> (bpf_core_get_index): Likewise. >>>> (pack_field_expr): Make the BTF type to point to the structure >>>> related node, instead of its pointer type. >>>> (make_core_safe_access_index): Correct to new code. >>>> >>>> gcc/testsuite/ChangeLog: >>>> * gcc.target/bpf/core-attr-5.c: Correct. >>>> * gcc.target/bpf/core-attr-6.c: Likewise. >>>> * gcc.target/bpf/core-attr-struct-as-array.c: Add test case for >>>> pointer arithmetics as array access use case. >>>> --- >>>> gcc/config/bpf/core-builtins.cc | 54 +++++++++++++++---- >>>> gcc/testsuite/gcc.target/bpf/core-attr-5.c | 4 +- >>>> gcc/testsuite/gcc.target/bpf/core-attr-6.c | 4 +- >>>> .../bpf/core-attr-struct-as-array.c | 35 ++++++++++++ >>>> 4 files changed, 82 insertions(+), 15 deletions(-) >>>> create mode 100644 >>>> gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c >>>> >>>> diff --git a/gcc/config/bpf/core-builtins.cc >>>> b/gcc/config/bpf/core-builtins.cc >>>> index 8d8c54c1fb3d..4256fea15e49 100644 >>>> --- a/gcc/config/bpf/core-builtins.cc >>>> +++ b/gcc/config/bpf/core-builtins.cc >>>> @@ -388,8 +388,8 @@ core_field_info (tree src, enum btf_core_reloc_kind >>>> kind) >>>> >>>> src = root_for_core_field_info (src); >>>> >>>> - get_inner_reference (src, &bitsize, &bitpos, &var_off, &mode, >>>> &unsignedp, >>>> - &reversep, &volatilep); >>>> + tree root = get_inner_reference (src, &bitsize, &bitpos, &var_off, >>>> &mode, >>>> + &unsignedp, &reversep, &volatilep); >>>> >>>> /* Note: Use DECL_BIT_FIELD_TYPE rather than DECL_BIT_FIELD here, >>>> because it >>>> remembers whether the field in question was originally declared as a >>>> @@ -414,6 +414,23 @@ core_field_info (tree src, enum btf_core_reloc_kind >>>> kind) >>>> { >>>> case BPF_RELO_FIELD_BYTE_OFFSET: >>>> { >>>> + result = 0; >>>> + if (var_off == NULL_TREE >>>> + && TREE_CODE (root) == INDIRECT_REF >>>> + && TREE_CODE (TREE_OPERAND (root, 0)) == POINTER_PLUS_EXPR) >>>> + { >>>> + tree node = TREE_OPERAND (root, 0); >>>> + tree offset = TREE_OPERAND (node, 1); >>>> + tree type = TREE_TYPE (TREE_OPERAND (node, 0)); >>>> + type = TREE_TYPE (type); >>>> + >>>> + gcc_assert (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p >>>> (offset) >>>> + && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE >>>> (type))); >>> >>> What if an expression with a non-constant offset (something like s+foo) >>> is passed to the builtin? Wouldn't it be better to error there instead >>> of ICEing? >>> >> In that case, var_off == NULL_TREE, and it did not reach the assert. >> In any case, please notice that this code was copied from some different >> code in the same file which in that case would actually produce the >> error earlier. The assert is there as a safe guard just in case the >> other function stops detecting this case. >> >> In core-builtins.cc:572 >> >> else if (code == POINTER_PLUS_EXPR) >> { >> tree offset = TREE_OPERAND (node, 1); >> tree type = TREE_TYPE (TREE_OPERAND (node, 0)); >> type = TREE_TYPE (type); >> >> if (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p (offset) >> && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE (type))) >> { >> HOST_WIDE_INT offset_i = tree_to_shwi (offset); >> HOST_WIDE_INT type_size_i = tree_to_shwi (TYPE_SIZE_UNIT (type)); >> if ((offset_i % type_size_i) == 0) >> return offset_i / type_size_i; >> } >> } >> >> if (valid != NULL) >> *valid = false; >> return -1; >> } >> >> Because the code, although similar, is actually having different >> purposes, I decided not to abstract this in an independent function. My >> perception was that it would be more confusing. >> >> Without wanting to paste too much code, please notice that the function >> with the assert is only called if the above function, does not return >> with error (i.e. valid != false). > > Ok understood. > Please submit upstream. > Thanks!
Heh this is already upstream, sorry. The patch is OK. Thanks! > >> >>> >>>> + >>>> + HOST_WIDE_INT offset_i = tree_to_shwi (offset); >>>> + result += offset_i; >>>> + } >>>> + >>>> type = unsigned_type_node; >>>> if (var_off != NULL_TREE) >>>> { >>>> @@ -422,9 +439,9 @@ core_field_info (tree src, enum btf_core_reloc_kind >>>> kind) >>>> } >>>> >>>> if (bitfieldp) >>>> - result = start_bitpos / 8; >>>> + result += start_bitpos / 8; >>>> else >>>> - result = bitpos / 8; >>>> + result += bitpos / 8; >>>> } >>>> break; >>>> >>>> @@ -552,6 +569,7 @@ bpf_core_get_index (const tree node, bool *valid) >>>> { >>>> tree offset = TREE_OPERAND (node, 1); >>>> tree type = TREE_TYPE (TREE_OPERAND (node, 0)); >>>> + type = TREE_TYPE (type); >>>> >>>> if (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p (offset) >>>> && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE (type))) >>>> @@ -627,14 +645,18 @@ compute_field_expr (tree node, unsigned int >>>> *accessors, >>>> >>>> switch (TREE_CODE (node)) >>>> { >>>> - case ADDR_EXPR: >>>> - return 0; >>>> case INDIRECT_REF: >>>> - accessors[0] = 0; >>>> - return 1; >>>> - case POINTER_PLUS_EXPR: >>>> - accessors[0] = bpf_core_get_index (node, valid); >>>> - return 1; >>>> + if (TREE_CODE (node = TREE_OPERAND (node, 0)) == POINTER_PLUS_EXPR) >>>> + { >>>> + accessors[0] = bpf_core_get_index (node, valid); >>>> + *access_node = TREE_OPERAND (node, 0); >>>> + return 1; >>>> + } >>>> + else >>>> + { >>>> + accessors[0] = 0; >>>> + return 1; >>>> + } >>>> case COMPONENT_REF: >>>> n = compute_field_expr (TREE_OPERAND (node, 0), accessors, >>>> valid, >>>> @@ -660,6 +682,7 @@ compute_field_expr (tree node, unsigned int *accessors, >>>> access_node, false); >>>> return n; >>>> >>>> + case ADDR_EXPR: >>>> case CALL_EXPR: >>>> case SSA_NAME: >>>> case VAR_DECL: >>>> @@ -688,6 +711,9 @@ pack_field_expr (tree *args, >>>> tree access_node = NULL_TREE; >>>> tree type = NULL_TREE; >>>> >>>> + if (TREE_CODE (root) == ADDR_EXPR) >>>> + root = TREE_OPERAND (root, 0); >>>> + >>>> ret.reloc_decision = REPLACE_CREATE_RELOCATION; >>>> >>>> unsigned int accessors[100]; >>>> @@ -695,6 +721,8 @@ pack_field_expr (tree *args, >>>> compute_field_expr (root, accessors, &valid, &access_node, false); >>>> >>>> type = TREE_TYPE (access_node); >>>> + if (POINTER_TYPE_P (type)) >>>> + type = TREE_TYPE (type); >>>> >>>> if (valid == true) >>>> { >>>> @@ -1351,6 +1379,8 @@ make_core_safe_access_index (tree expr, bool >>>> *changed, bool entry = true) >>>> if (base == NULL_TREE || base == expr) >>>> return expr; >>>> >>>> + base = expr; >>>> + >>>> tree ret = NULL_TREE; >>>> int n; >>>> bool valid = true; >>>> @@ -1365,6 +1395,8 @@ make_core_safe_access_index (tree expr, bool >>>> *changed, bool entry = true) >>>> { >>>> if (TREE_CODE (access_node) == INDIRECT_REF) >>>> base = TREE_OPERAND (access_node, 0); >>>> + else >>>> + base = access_node; >>>> >>>> bool local_changed = false; >>>> ret = make_core_safe_access_index (base, &local_changed, false); >>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-5.c >>>> b/gcc/testsuite/gcc.target/bpf/core-attr-5.c >>>> index e71901d0d4d1..90734dab3a29 100644 >>>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-5.c >>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-5.c >>>> @@ -63,5 +63,5 @@ func (struct T *t, int i) >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } >>>> } */ >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:1\"\\)" 1 >>>> } } */ >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } >>>> */ >>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 4 } >>>> } */ >>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 4 { >>>> xfail *-*-* } } } */ >>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 4 } } */ >>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 4 { >>>> xfail *-*-* } } } */ >>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-6.c >>>> b/gcc/testsuite/gcc.target/bpf/core-attr-6.c >>>> index 34a4c367e528..d0c5371b86e0 100644 >>>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-6.c >>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-6.c >>>> @@ -45,6 +45,6 @@ func (struct T *t, int i) >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } >>>> */ >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } >>>> } */ >>>> /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } >>>> */ >>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 3 } >>>> } */ >>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 2 } >>>> } */ >>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 3 } } */ >>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 2 } } */ >>>> >>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c >>>> b/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c >>>> new file mode 100644 >>>> index 000000000000..3f6eb9cb97f8 >>>> --- /dev/null >>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c >>>> @@ -0,0 +1,35 @@ >>>> +/* Basic test for struct __attribute__((preserve_access_index)) >>>> + for BPF CO-RE support. */ >>>> + >>>> +/* { dg-do compile } */ >>>> +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ >>>> + >>>> +struct S { >>>> + int a; >>>> + int b; >>>> + int c; >>>> +} __attribute__((preserve_access_index)); >>>> + >>>> +void >>>> +func (struct S * s) >>>> +{ >>>> + /* This test is marked as XFAIL since for the time being the CO-RE >>>> + implementation is not able to disambiguate between a point >>>> manipulation >>>> + and a CO-RE access when using preserve_access_index attribute. The >>>> + current implemetantion is incorrect if we consider that STRUCT S >>>> might >>>> + have different size within the kernel. >>>> + This example demonstrates how the implementation of >>>> preserve_access_index >>>> + as an attribute of the type is flagile. */ >>>> + >>>> + /* 2:2 */ >>>> + int *x = &((s+2)->c); >>>> + *x = 4; >>>> + >>>> + /* 2:1 */ >>>> + int *y = __builtin_preserve_access_index (&((s+2)->b)); >>>> + *y = 2; >>>> +} >>>> + >>>> +/* { dg-final { scan-assembler-times "ascii \"2:2.0\"\[\t >>>> \]+\[^\n\]*btf_aux_string" 1 { xfail *-*-* } } } */ >>>> +/* { dg-final { scan-assembler-times "ascii \"2:1.0\"\[\t >>>> \]+\[^\n\]*btf_aux_string" 1 } } */ >>>> +/* { dg-final { scan-assembler-times "bpfcr_type" 2 } } */