De-duplicate BTF relocation test

reviewable/pr638/r31
Tamir Duberstein 2 years ago
parent 35e81afbcb
commit 53da8f3c1a
No known key found for this signature in database

@ -4,7 +4,7 @@
#include <bpf/bpf_core_read.h> #include <bpf/bpf_core_read.h>
// clang-format on // clang-format on
char _license[] __attribute__((section("license"), used)) = "GPL"; char _license[] SEC("license") = "GPL";
struct { struct {
__uint(type, BPF_MAP_TYPE_ARRAY); __uint(type, BPF_MAP_TYPE_ARRAY);
@ -19,12 +19,17 @@ long set_output(__u64 value) {
} }
struct relocated_struct_with_scalars { struct relocated_struct_with_scalars {
#ifndef TARGET
__u8 a; __u8 a;
#endif
__u8 b; __u8 b;
__u8 c; __u8 c;
#ifdef TARGET
__u8 d;
#endif
}; };
__attribute__((noinline)) int field_global() { __noinline int field_global() {
struct relocated_struct_with_scalars s = {1, 2, 3}; struct relocated_struct_with_scalars s = {1, 2, 3};
return set_output(__builtin_preserve_access_index(s.b)); return set_output(__builtin_preserve_access_index(s.b));
} }
@ -32,11 +37,16 @@ __attribute__((noinline)) int field_global() {
SEC("uprobe") int field(void *ctx) { return field_global(); } SEC("uprobe") int field(void *ctx) { return field_global(); }
struct relocated_struct_with_pointer { struct relocated_struct_with_pointer {
#ifndef TARGET
struct relocated_struct_with_pointer *first; struct relocated_struct_with_pointer *first;
#endif
struct relocated_struct_with_pointer *second; struct relocated_struct_with_pointer *second;
#ifdef TARGET
struct relocated_struct_with_pointer *first;
#endif
}; };
__attribute__((noinline)) int pointer_global() { __noinline int pointer_global() {
struct relocated_struct_with_pointer s = { struct relocated_struct_with_pointer s = {
(struct relocated_struct_with_pointer *)42, (struct relocated_struct_with_pointer *)42,
(struct relocated_struct_with_pointer *)21, (struct relocated_struct_with_pointer *)21,
@ -46,49 +56,86 @@ __attribute__((noinline)) int pointer_global() {
SEC("uprobe") int pointer(void *ctx) { return pointer_global(); } SEC("uprobe") int pointer(void *ctx) { return pointer_global(); }
__attribute__((noinline)) int struct_flavors_global() { __noinline int struct_flavors_global() {
struct relocated_struct_with_scalars s = {1, 2, 3}; struct relocated_struct_with_scalars s = {1, 2, 3};
#ifndef TARGET
if (bpf_core_field_exists(s.a)) { if (bpf_core_field_exists(s.a)) {
return set_output(__builtin_preserve_access_index(s.a)); return set_output(__builtin_preserve_access_index(s.a));
#else
if (bpf_core_field_exists(s.d)) {
return set_output(__builtin_preserve_access_index(s.d));
#endif
} else { } else {
return set_output(__builtin_preserve_access_index(s.b)); return set_output(__builtin_preserve_access_index(s.c));
} }
} }
SEC("uprobe") int struct_flavors(void *ctx) { return struct_flavors_global(); } SEC("uprobe") int struct_flavors(void *ctx) { return struct_flavors_global(); }
enum relocated_enum_unsigned_32 { U32 = 0xAAAAAAAA }; enum relocated_enum_unsigned_32 {
U32_VAL =
#ifndef TARGET
0xAAAAAAAA
#else
0xBBBBBBBB
#endif
};
__attribute__((noinline)) int enum_unsigned_32_global() { __noinline int enum_unsigned_32_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); return set_output(
bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL));
} }
SEC("uprobe") int enum_unsigned_32(void *ctx) { SEC("uprobe") int enum_unsigned_32(void *ctx) {
return enum_unsigned_32_global(); return enum_unsigned_32_global();
} }
enum relocated_enum_signed_32 { S32 = -0x7AAAAAAA }; enum relocated_enum_signed_32 {
S32_VAL =
#ifndef TARGET
-0x7AAAAAAA
#else
-0x7BBBBBBB
#endif
};
__attribute__((noinline)) int enum_signed_32_global() { __noinline int enum_signed_32_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); return set_output(
bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL));
} }
SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); } SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); }
enum relocated_enum_unsigned_64 { U64 = 0xAAAAAAAABBBBBBBB }; enum relocated_enum_unsigned_64 {
U64_VAL =
#ifndef TARGET
0xAAAAAAAABBBBBBBB
#else
0xCCCCCCCCDDDDDDDD
#endif
};
__attribute__((noinline)) int enum_unsigned_64_global() { __noinline int enum_unsigned_64_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); return set_output(
bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL));
} }
SEC("uprobe") int enum_unsigned_64(void *ctx) { SEC("uprobe") int enum_unsigned_64(void *ctx) {
return enum_unsigned_64_global(); return enum_unsigned_64_global();
} }
enum relocated_enum_signed_64 { u64 = -0xAAAAAAABBBBBBBB }; enum relocated_enum_signed_64 {
S64_VAL =
#ifndef TARGET
-0xAAAAAAABBBBBBBB
#else
-0xCCCCCCCDDDDDDDD
#endif
};
__attribute__((noinline)) int enum_signed_64_global() { __noinline int enum_signed_64_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); return set_output(
bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL));
} }
SEC("uprobe") int enum_signed_64(void *ctx) { return enum_signed_64_global(); } SEC("uprobe") int enum_signed_64(void *ctx) { return enum_signed_64_global(); }

@ -1,77 +0,0 @@
// clang-format off
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
// clang-format on
#include <stdlib.h>
long set_output(__u64 value) { exit((int)value); }
struct relocated_struct_with_scalars {
__u8 b;
__u8 c;
__u8 d;
};
__attribute__((noinline)) int field_global() {
struct relocated_struct_with_scalars s = {1, 2, 3};
return set_output(__builtin_preserve_access_index(s.b));
}
struct relocated_struct_with_pointer {
struct relocated_struct_with_pointer *second;
struct relocated_struct_with_pointer *first;
};
__attribute__((noinline)) int pointer_global() {
struct relocated_struct_with_pointer s = {
(struct relocated_struct_with_pointer *)42,
(struct relocated_struct_with_pointer *)21,
};
return set_output((__u64)__builtin_preserve_access_index(s.first));
}
__attribute__((noinline)) int struct_flavors_global() {
struct relocated_struct_with_scalars s = {1, 2, 3};
if (bpf_core_field_exists(s.b)) {
return set_output(__builtin_preserve_access_index(s.b));
} else {
return set_output(__builtin_preserve_access_index(s.c));
}
}
enum relocated_enum_unsigned_32 { U32 = 0xBBBBBBBB };
__attribute__((noinline)) int enum_unsigned_32_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32));
}
enum relocated_enum_signed_32 { S32 = -0x7BBBBBBB };
__attribute__((noinline)) int enum_signed_32_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32));
}
enum relocated_enum_unsigned_64 { U64 = 0xCCCCCCCCDDDDDDDD };
__attribute__((noinline)) int enum_unsigned_64_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64));
}
enum relocated_enum_signed_64 { u64 = -0xCCCCCCCDDDDDDDD };
__attribute__((noinline)) int enum_signed_64_global() {
return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64));
}
// Avoids dead code elimination by the compiler.
int main() {
field_global();
pointer_global();
struct_flavors_global();
enum_unsigned_32_global();
enum_signed_32_global();
enum_unsigned_64_global();
enum_signed_64_global();
}

@ -64,20 +64,14 @@ fn main() {
panic!("unsupported endian={:?}", endian) panic!("unsupported endian={:?}", endian)
}; };
const C_BPF: &[(&str, &str)] = &[ const C_BPF: &[(&str, bool)] = &[
("ext.bpf.c", "ext.bpf.o"), ("ext.bpf.c", false),
("main.bpf.c", "main.bpf.o"), ("main.bpf.c", false),
("multimap-btf.bpf.c", "multimap-btf.bpf.o"), ("multimap-btf.bpf.c", false),
("reloc.bpf.c", "reloc.bpf.o"), ("reloc.bpf.c", true),
("text_64_64_reloc.c", "text_64_64_reloc.o"), ("text_64_64_reloc.c", false),
]; ];
let c_bpf = C_BPF.iter().map(|(src, dst)| (src, out_dir.join(dst)));
const C_BTF: &[(&str, &str)] = &[("reloc.btf.c", "reloc.btf.o")];
let c_btf = C_BTF.iter().map(|(src, dst)| (src, out_dir.join(dst)));
if build_integration_bpf { if build_integration_bpf {
let libbpf_dir = manifest_dir let libbpf_dir = manifest_dir
.parent() .parent()
@ -116,61 +110,56 @@ fn main() {
target_arch.push(arch); target_arch.push(arch);
}; };
for (src, dst) in c_bpf { let clang = || {
let src = bpf_dir.join(src); let mut cmd = Command::new("clang");
println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); cmd.arg("-I")
.arg(&libbpf_headers_dir)
exec( .args(["-g", "-O2", "-target", target, "-c"])
Command::new("clang") .arg(&target_arch);
.arg("-I") cmd
.arg(&libbpf_headers_dir) };
.args(["-g", "-O2", "-target", target, "-c"])
.arg(&target_arch)
.arg(src)
.arg("-o")
.arg(dst),
)
.unwrap();
}
for (src, dst) in c_btf { for (src, build_btf) in C_BPF {
let dst = out_dir.join(src).with_extension("o");
let src = bpf_dir.join(src); let src = bpf_dir.join(src);
println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); println!("cargo:rerun-if-changed={}", src.to_str().unwrap());
let mut cmd = Command::new("clang"); exec(clang().arg(&src).arg("-o").arg(&dst)).unwrap();
cmd.arg("-I")
.arg(&libbpf_headers_dir) if *build_btf {
.args(["-g", "-target", target, "-c"]) let mut cmd = clang();
.arg(&target_arch) let mut child = cmd
.arg(src) .arg("-DTARGET")
.args(["-o", "-"]); .arg(&src)
.args(["-o", "-"])
let mut child = cmd .stdout(Stdio::piped())
.stdout(Stdio::piped()) .spawn()
.spawn() .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}"));
.unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}"));
let Child { stdout, .. } = &mut child;
let Child { stdout, .. } = &mut child; let stdout = stdout.take().unwrap();
let stdout = stdout.take().unwrap();
let dst = dst.with_extension("target.o");
let mut output = OsString::new();
output.push(".BTF="); let mut output = OsString::new();
output.push(dst); output.push(".BTF=");
exec( output.push(dst);
// NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. exec(
Command::new("llvm-objcopy") // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy.
.arg("--dump-section") Command::new("llvm-objcopy")
.arg(output) .arg("--dump-section")
.arg("-") .arg(output)
.stdin(stdout), .arg("-")
) .stdin(stdout),
.unwrap(); )
.unwrap();
let output = child
.wait_with_output() let output = child
.unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); .wait_with_output()
let Output { status, .. } = &output; .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}"));
assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); let Output { status, .. } = &output;
assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}");
}
} }
let target = format!("{target}-unknown-none"); let target = format!("{target}-unknown-none");
@ -262,8 +251,13 @@ fn main() {
.unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}")); .unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}"));
} }
} else { } else {
for (_src, dst) in c_bpf.chain(c_btf) { for (src, build_btf) in C_BPF {
let dst = out_dir.join(src).with_extension("o");
fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}"));
if *build_btf {
let dst = dst.with_extension("target.o");
fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}"));
}
} }
let Package { targets, .. } = integration_ebpf_package; let Package { targets, .. } = integration_ebpf_package;

@ -5,7 +5,8 @@ pub const MAIN: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.b
pub const MULTIMAP_BTF: &[u8] = pub const MULTIMAP_BTF: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/multimap-btf.bpf.o")); include_bytes_aligned!(concat!(env!("OUT_DIR"), "/multimap-btf.bpf.o"));
pub const RELOC_BPF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.o")); pub const RELOC_BPF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.o"));
pub const RELOC_BTF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.btf.o")); pub const RELOC_BTF: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.target.o"));
pub const TEXT_64_64_RELOC: &[u8] = pub const TEXT_64_64_RELOC: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o")); include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o"));

@ -2,20 +2,20 @@ use test_case::test_case;
use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness}; use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness};
#[test_case("field", false, None, 2)] #[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)]
#[test_case("field", true, None, 1)] #[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)]
#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)]
#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)]
#[test_case("enum_unsigned_32", false, None, 0xAAAAAAAA)] #[test_case("enum_unsigned_32", false, None, 0xAAAAAAAA)]
#[test_case("enum_unsigned_32", true, None, 0xBBBBBBBB)] #[test_case("enum_unsigned_32", true, None, 0xBBBBBBBB)]
#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)]
#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)]
#[test_case("field", false, None, 2)]
#[test_case("field", true, None, 1)]
#[test_case("pointer", false, None, 42)] #[test_case("pointer", false, None, 42)]
#[test_case("pointer", true, None, 21)] #[test_case("pointer", true, None, 21)]
#[test_case("struct_flavors", false, None, 1)] #[test_case("struct_flavors", false, None, 1)]
#[test_case("struct_flavors", true, None, 1)] #[test_case("struct_flavors", true, None, 2)]
#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)]
#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)]
#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)]
#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)]
#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)]
#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)]
fn relocation_tests( fn relocation_tests(
program: &str, program: &str,
with_relocations: bool, with_relocations: bool,

Loading…
Cancel
Save