diff options
author | Julia Kartseva <hex@fb.com> | 2020-11-14 02:02:50 +0100 |
---|---|---|
committer | Julia Kartseva <hex@fb.com> | 2021-04-27 01:07:41 +0200 |
commit | cf4f9a57f20f1b21d59574e1f0cb6504506f1728 (patch) | |
tree | 116a082bae3934858d3610f8e638c37fc1b41d52 /tools | |
parent | bpf: add socket-bind BPF program code sources (diff) | |
download | systemd-cf4f9a57f20f1b21d59574e1f0cb6504506f1728.tar.xz systemd-cf4f9a57f20f1b21d59574e1f0cb6504506f1728.zip |
bpf: add build script for bpf programs
Add a build script to compile bpf source code. A program in restricted
C is compiled into an object file. Object file is converted to BPF
skeleton [0] header file.
If build with custom meson build rule, the target header will reside in
build/ directory (not in source tree), e.g the path for socket_bind:
`build/src/core/bpf/socket_bind/socket-bind.skel.h`
Script runs the phases:
* clang to generate *.o from restricted C
* llvm-strip to remove useless DWARF info
* bpf skeleton generation with bpftool
These phases are logged to stderr for debug purposes.
To include BTF debug information, -g option is passed to clang.
[0] https://lwn.net/Articles/806911/
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/build-bpf-skel.py | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/tools/build-bpf-skel.py b/tools/build-bpf-skel.py new file mode 100755 index 0000000000..5506fdd875 --- /dev/null +++ b/tools/build-bpf-skel.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import argparse +import logging +import pathlib +import subprocess +import sys + +def clang_arch_flag(arch): + return '-D__{}__'.format(arch) + + +def target_triplet(): + gcc_exec = 'gcc' + + try: + return subprocess.check_output([gcc_exec, '-dumpmachine'], + universal_newlines=True).strip() + except subprocess.CalledProcessError as e: + logging.error('Failed to get target triplet: {}'.format(e)) + except FileNotFoundError: + logging.error('gcc not installed') + return None + + +def clang_compile(clang_exec, clang_flags, src_c, out_file, target_arch, + target_triplet): + clang_args = [clang_exec, *clang_flags, target_arch, '-I.'] + + if target_triplet: + clang_args += [ + '-isystem', + '/usr/include/{}'.format(target_triplet)] + + clang_args += [ + '-idirafter', + '/usr/local/include', + '-idirafter', + '/usr/include'] + + clang_args += [src_c, '-o', out_file] + + logging.debug('{}'.format(' '.join(clang_args))) + subprocess.check_call(clang_args) + + +def llvm_strip(llvm_strip_exec, in_file): + llvm_strip_args = [llvm_strip_exec, '-g', in_file] + + logging.debug('Stripping useless DWARF info:') + logging.debug('{}'.format(' '.join(llvm_strip_args))) + + subprocess.check_call(llvm_strip_args) + + +def gen_bpf_skeleton(bpftool_exec, in_file, out_fd): + bpftool_args = [bpftool_exec, 'g', 's', in_file] + + logging.debug('Generating BPF skeleton:') + logging.debug('{}'.format(' '.join(bpftool_args))) + subprocess.check_call(bpftool_args, stdout=out_fd) + + +def bpf_build(args): + clang_flags = [ + '-Wno-compare-distinct-pointer-types', + '-O2', + '-target', + 'bpf', + '-g', + '-c', + ] + + clang_out_path = pathlib.Path(args.bpf_src_c).with_suffix('.o') + with clang_out_path.open(mode='w') as clang_out, \ + open(args.bpf_skel_h, mode='w') as bpf_skel_h: + clang_compile(clang_exec=args.clang_exec, + clang_flags=clang_flags, + src_c=args.bpf_src_c, + out_file=clang_out.name, + target_arch=clang_arch_flag(args.arch), + target_triplet=target_triplet()) + + llvm_strip(llvm_strip_exec=args.llvm_strip_exec, in_file=clang_out.name) + + gen_bpf_skeleton(bpftool_exec=args.bpftool_exec, + in_file=clang_out.name, + out_fd=bpf_skel_h) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument( + 'bpf_src_c', + help='Path to *.c source of BPF program in systemd source tree \ + relative to the work directory') + + parser.add_argument( + 'bpf_skel_h', + help='Path to C header file') + + parser.add_argument( + '--clang_exec', + help='Path to clang exec') + + parser.add_argument( + '--llvm_strip_exec', + help='Path to llvm-strip exec') + + parser.add_argument( + '--bpftool_exec', + help='Path to bpftool exec') + + parser.add_argument( + '--arch', + help='Target CPU architecture', + default='x86_64') + + args = parser.parse_args(); + + logging.basicConfig(stream=sys.stderr, level=logging.WARNING) + bpf_build(args) |