Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support casting int <-> int array #2686

Merged
merged 6 commits into from
Aug 25, 2023
Merged

Conversation

viktormalik
Copy link
Contributor

This PR adds support for conversions between integers and integer arrays. The main purpose is to allow conversion from/to byte arrays.

A good use-case for this are scripts working with IPv4 addresses which the kernel sometimes stores as 32-bit integers (e.g. in struct sock_common) and sometimes as 4-byte arrays (e.g. in TCP tracepoints). This feature, in combination with array comparison added in #2387, allows to compare such representations:

kfunc:tcp_connect
{
    @ = args->sk->__sk_common.skc_daddr;
}
tracepoint:tcp:tcp_rcv_space_adjust
{
    // map values are always 64-bit so first cast to uint32
    // and then to the target array
    if ((uint8[4])(uint32)@ == args->daddr)
    {
        ...
    }
}

Similarly, it is now possible to compare the int IPv4 addresses with absolute addresses obtained from the pton builtin:

kfunc:tcp_connect
{
    if (args->sk->__sk_common.skc_daddr == (uint32)pton("127.0.0.1"))
        ...
}

Both the cast and the destination type must have the same size. When casting to an array, it is possible to omit the size which will be determined automatically from the size of the cast value.

This also does some refactoring of type parsing. See individual commit messages for more implementation details.

Resolves #2634.

Checklist
  • Language changes are updated in man/adoc/bpftrace.adoc and if needed in docs/reference_guide.md
  • User-visible and non-trivial changes updated in CHANGELOG.md
  • The new behaviour is covered by tests

Comment on lines +2370 to +2402
if ((cast.type.IsIntTy() && !rhs.IsIntTy() && !rhs.IsPtrTy() &&
!rhs.IsCtxAccess() && !(rhs.IsArrayTy())) ||
// casting from/to int arrays must respect the size
(cast.type.IsArrayTy() &&
(!rhs.IsIntTy() || cast.type.GetSize() != rhs.GetSize())) ||
(rhs.IsArrayTy() &&
(!cast.type.IsIntTy() || cast.type.GetSize() != rhs.GetSize())))

Check notice

Code scanning / CodeQL

Complex condition Note

Complex condition: too many logical operations in this expression.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that this is a mess and wanted to refactor it but then found out that the cast checks will require some improvement, so I'd rather post it as a separate PR.

src/lexer.l Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

src/ast/passes/semantic_analyser.cpp Show resolved Hide resolved
src/ast/passes/semantic_analyser.cpp Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neat use of FLA semantics.

tests/semantic_analyser.cpp Show resolved Hide resolved
src/ast/passes/codegen_llvm.cpp Outdated Show resolved Hide resolved
docs/reference_guide.md Show resolved Hide resolved
@viktormalik
Copy link
Contributor Author

Thanks for the review @danobi! I addressed all the comments and added them as new commits to simplify reviewing. Will fixup the commits afterwards.

@viktormalik
Copy link
Contributor Author

This is quite a big feature and could use another review.

@fbs, @ajor

Copy link
Member

@ajor ajor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice - the code's a lot simpler than I'd expected!

tests/runtime/array Outdated Show resolved Hide resolved
Split simple types into integer types and builtin types. This is useful
as it will allow special treatment of integer types and their usage in
constructions where builtin types don't make sense (e.g. arrays).
The syntax is the same as for other casts:

    $array = (int8[8])42;

For now, it is only possible to cast integers to integer arrays. Both
the cast value and the target array must have the same size.

The integer being cast is copied to the BPF stack and the pointer to it
is then reinterpreted as the target array pointer.

This, in combination with recently added array comparison, allows to
compare values which are stored under different types in kernel.
E.g., IP addresses are represented with 32-bit int in "struct sock" [1]
but with byte array in TCP tracepoints [2]. This feature allows to
compare them:

    kfunc:tcp_connect
    {
        @ = args->sk->__sk_common.skc_daddr;
    }
    tracepoint:tcp:tcp_rcv_space_adjust
    {
        // map values are always 64-bit so first cast to uint32
        // and then to the target array
        if ((uint8[4])(uint32)@ == args->daddr)
        {
            ...
        }
    }

[1] https://elixir.bootlin.com/linux/v6.4/source/include/net/sock.h#L167
[2] https://elixir.bootlin.com/linux/v6.4/source/include/trace/events/tcp.h#L64
Support omitting the array size when casting to arrays as it can be
computed automatically in semantic analyser.

E.g. for `(int8[])42`, the array will have 8 elements (since ints are by
default 64-bit).
It is only possible to cast the entire array to an integer of the same
size. The main purpose is to allow conversion of byte arrays such as
those returned by the 'pton' builtin:

    kfunc:tcp_connect
    {
        if (args->sk->__sk_common.skc_daddr == (uint32)pton("127.0.0.1"))
            ...
    }

Since arrays are internally stored as pointers, the codegen for this
just reinterprets the pointer to the expected integer size and loads the
data as an integer (by a direct load or by an additional proberead).
Add examples of casts to both the Reference guide and manpage.
@ajor ajor merged commit f676cc8 into bpftrace:master Aug 25, 2023
21 checks passed
@viktormalik viktormalik deleted the bytearray-cast branch August 31, 2023 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

IP address comparison is incomplete
3 participants