diff --git a/test/integration-test/bpf/reloc.bpf.c b/test/integration-test/bpf/reloc.bpf.c index dbc464a4..ea67ee2e 100644 --- a/test/integration-test/bpf/reloc.bpf.c +++ b/test/integration-test/bpf/reloc.bpf.c @@ -4,7 +4,7 @@ #include // clang-format on -char _license[] __attribute__((section("license"), used)) = "GPL"; +char _license[] SEC("license") = "GPL"; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -19,12 +19,17 @@ long set_output(__u64 value) { } struct relocated_struct_with_scalars { +#ifndef TARGET __u8 a; +#endif __u8 b; __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}; 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(); } struct relocated_struct_with_pointer { +#ifndef TARGET struct relocated_struct_with_pointer *first; +#endif 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 *)42, (struct relocated_struct_with_pointer *)21, @@ -46,49 +56,86 @@ __attribute__((noinline)) int 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}; +#ifndef TARGET if (bpf_core_field_exists(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 { - 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(); } -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() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); +__noinline int enum_unsigned_32_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); } SEC("uprobe") int enum_unsigned_32(void *ctx) { 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() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); +__noinline int enum_signed_32_global() { + 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(); } -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() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); +__noinline int enum_unsigned_64_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); } SEC("uprobe") int enum_unsigned_64(void *ctx) { 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() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); +__noinline int enum_signed_64_global() { + 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(); } diff --git a/test/integration-test/bpf/reloc.btf.c b/test/integration-test/bpf/reloc.btf.c deleted file mode 100644 index 86801061..00000000 --- a/test/integration-test/bpf/reloc.btf.c +++ /dev/null @@ -1,77 +0,0 @@ -// clang-format off -#include -#include -#include -// clang-format on - -#include - -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(); -} diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index 2e3bef84..a17d64ad 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -64,20 +64,14 @@ fn main() { panic!("unsupported endian={:?}", endian) }; - const C_BPF: &[(&str, &str)] = &[ - ("ext.bpf.c", "ext.bpf.o"), - ("main.bpf.c", "main.bpf.o"), - ("multimap-btf.bpf.c", "multimap-btf.bpf.o"), - ("reloc.bpf.c", "reloc.bpf.o"), - ("text_64_64_reloc.c", "text_64_64_reloc.o"), + const C_BPF: &[(&str, bool)] = &[ + ("ext.bpf.c", false), + ("main.bpf.c", false), + ("multimap-btf.bpf.c", false), + ("reloc.bpf.c", true), + ("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 { let libbpf_dir = manifest_dir .parent() @@ -116,61 +110,56 @@ fn main() { target_arch.push(arch); }; - for (src, dst) in c_bpf { - let src = bpf_dir.join(src); - println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - - exec( - Command::new("clang") - .arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-O2", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .arg("-o") - .arg(dst), - ) - .unwrap(); - } + let clang = || { + let mut cmd = Command::new("clang"); + cmd.arg("-I") + .arg(&libbpf_headers_dir) + .args(["-g", "-O2", "-target", target, "-c"]) + .arg(&target_arch); + cmd + }; - 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); println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - let mut cmd = Command::new("clang"); - cmd.arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .args(["-o", "-"]); - - let mut child = cmd - .stdout(Stdio::piped()) - .spawn() - .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); - - let Child { stdout, .. } = &mut child; - let stdout = stdout.take().unwrap(); - - let mut output = OsString::new(); - output.push(".BTF="); - output.push(dst); - exec( - // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. - Command::new("llvm-objcopy") - .arg("--dump-section") - .arg(output) - .arg("-") - .stdin(stdout), - ) - .unwrap(); - - let output = child - .wait_with_output() - .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - let Output { status, .. } = &output; - assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); + exec(clang().arg(&src).arg("-o").arg(&dst)).unwrap(); + + if *build_btf { + let mut cmd = clang(); + let mut child = cmd + .arg("-DTARGET") + .arg(&src) + .args(["-o", "-"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); + + let Child { stdout, .. } = &mut child; + let stdout = stdout.take().unwrap(); + + let dst = dst.with_extension("target.o"); + + let mut output = OsString::new(); + output.push(".BTF="); + output.push(dst); + exec( + // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. + Command::new("llvm-objcopy") + .arg("--dump-section") + .arg(output) + .arg("-") + .stdin(stdout), + ) + .unwrap(); + + let output = child + .wait_with_output() + .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); + let Output { status, .. } = &output; + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); + } } let target = format!("{target}-unknown-none"); @@ -262,8 +251,13 @@ fn main() { .unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}")); } } 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}")); + 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; diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 80cd0b1d..08911a4e 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -5,7 +5,8 @@ pub const MAIN: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.b pub const MULTIMAP_BTF: &[u8] = 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_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] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o")); diff --git a/test/integration-test/src/tests/btf_relocations.rs b/test/integration-test/src/tests/btf_relocations.rs index 7e1020ba..79eb3e52 100644 --- a/test/integration-test/src/tests/btf_relocations.rs +++ b/test/integration-test/src/tests/btf_relocations.rs @@ -2,20 +2,20 @@ use test_case::test_case; use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness}; -#[test_case("field", false, None, 2)] -#[test_case("field", true, None, 1)] +#[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_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", 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", true, None, 21)] #[test_case("struct_flavors", false, None, 1)] -#[test_case("struct_flavors", true, None, 1)] -#[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)] +#[test_case("struct_flavors", true, None, 2)] fn relocation_tests( program: &str, with_relocations: bool,