|
|
|
@ -6,6 +6,9 @@ use aya::{maps::Array, programs::TracePoint, BpfLoader, Btf, Endianness};
|
|
|
|
|
|
|
|
|
|
use super::{integration_test, IntegrationTest};
|
|
|
|
|
|
|
|
|
|
// In the tests below we often use values like 0xAAAAAAAA or -0x7AAAAAAA. Those values have no
|
|
|
|
|
// special meaning, they just have "nice" bit patterns that can be helpful while debugging.
|
|
|
|
|
|
|
|
|
|
#[integration_test]
|
|
|
|
|
fn relocate_field() {
|
|
|
|
|
let test = RelocationTest {
|
|
|
|
@ -28,9 +31,7 @@ fn relocate_field() {
|
|
|
|
|
relocation_code: r#"
|
|
|
|
|
__u8 memory[] = {1, 2, 3, 4};
|
|
|
|
|
struct foo *ptr = (struct foo *) &memory;
|
|
|
|
|
bpf_probe_read_kernel(&value,
|
|
|
|
|
sizeof(__u8),
|
|
|
|
|
__builtin_preserve_access_index(&ptr->c));
|
|
|
|
|
value = __builtin_preserve_access_index(ptr->c);
|
|
|
|
|
"#,
|
|
|
|
|
}
|
|
|
|
|
.build()
|
|
|
|
@ -43,10 +44,10 @@ fn relocate_field() {
|
|
|
|
|
fn relocate_enum() {
|
|
|
|
|
let test = RelocationTest {
|
|
|
|
|
local_definition: r#"
|
|
|
|
|
enum foo { D = 1 };
|
|
|
|
|
enum foo { D = 0xAAAAAAAA };
|
|
|
|
|
"#,
|
|
|
|
|
target_btf: r#"
|
|
|
|
|
enum foo { D = 4 } e1;
|
|
|
|
|
enum foo { D = 0xBBBBBBBB } e1;
|
|
|
|
|
"#,
|
|
|
|
|
relocation_code: r#"
|
|
|
|
|
#define BPF_ENUMVAL_VALUE 1
|
|
|
|
@ -55,8 +56,28 @@ fn relocate_enum() {
|
|
|
|
|
}
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(test.run().unwrap(), 4);
|
|
|
|
|
assert_eq!(test.run_no_btf().unwrap(), 1);
|
|
|
|
|
assert_eq!(test.run().unwrap(), 0xBBBBBBBB);
|
|
|
|
|
assert_eq!(test.run_no_btf().unwrap(), 0xAAAAAAAA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[integration_test]
|
|
|
|
|
fn relocate_enum_signed() {
|
|
|
|
|
let test = RelocationTest {
|
|
|
|
|
local_definition: r#"
|
|
|
|
|
enum foo { D = -0x7AAAAAAA };
|
|
|
|
|
"#,
|
|
|
|
|
target_btf: r#"
|
|
|
|
|
enum foo { D = -0x7BBBBBBB } e1;
|
|
|
|
|
"#,
|
|
|
|
|
relocation_code: r#"
|
|
|
|
|
#define BPF_ENUMVAL_VALUE 1
|
|
|
|
|
value = __builtin_preserve_enum_value(*(typeof(enum foo) *)D, BPF_ENUMVAL_VALUE);
|
|
|
|
|
"#,
|
|
|
|
|
}
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(test.run().unwrap() as i64, -0x7BBBBBBBi64);
|
|
|
|
|
assert_eq!(test.run_no_btf().unwrap() as i64, -0x7AAAAAAAi64);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[integration_test]
|
|
|
|
@ -73,9 +94,7 @@ fn relocate_pointer() {
|
|
|
|
|
relocation_code: r#"
|
|
|
|
|
__u8 memory[] = {42, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
struct bar* ptr = (struct bar *) &memory;
|
|
|
|
|
bpf_probe_read_kernel(&value,
|
|
|
|
|
sizeof(void *),
|
|
|
|
|
__builtin_preserve_access_index(&ptr->f));
|
|
|
|
|
value = (__u64) __builtin_preserve_access_index(ptr->f);
|
|
|
|
|
"#,
|
|
|
|
|
}
|
|
|
|
|
.build()
|
|
|
|
@ -121,14 +140,13 @@ impl RelocationTest {
|
|
|
|
|
#include <linux/bpf.h>
|
|
|
|
|
|
|
|
|
|
static long (*bpf_map_update_elem)(void *map, const void *key, const void *value, __u64 flags) = (void *) 2;
|
|
|
|
|
static long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 113;
|
|
|
|
|
|
|
|
|
|
{local_definition}
|
|
|
|
|
|
|
|
|
|
struct {{
|
|
|
|
|
int (*type)[BPF_MAP_TYPE_ARRAY];
|
|
|
|
|
__u32 *key;
|
|
|
|
|
__u32 *value;
|
|
|
|
|
__u64 *value;
|
|
|
|
|
int (*max_entries)[1];
|
|
|
|
|
}} output_map
|
|
|
|
|
__attribute__((section(".maps"), used));
|
|
|
|
@ -136,7 +154,7 @@ impl RelocationTest {
|
|
|
|
|
__attribute__((section("tracepoint/bpf_prog"), used))
|
|
|
|
|
int bpf_prog(void *ctx) {{
|
|
|
|
|
__u32 key = 0;
|
|
|
|
|
__u32 value = 0;
|
|
|
|
|
__u64 value = 0;
|
|
|
|
|
{relocation_code}
|
|
|
|
|
bpf_map_update_elem(&output_map, &key, &value, BPF_ANY);
|
|
|
|
|
return 0;
|
|
|
|
@ -165,11 +183,9 @@ impl RelocationTest {
|
|
|
|
|
r#"
|
|
|
|
|
#include <linux/bpf.h>
|
|
|
|
|
|
|
|
|
|
static long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 113;
|
|
|
|
|
|
|
|
|
|
{target_btf}
|
|
|
|
|
int main() {{
|
|
|
|
|
__u32 value = 0;
|
|
|
|
|
__u64 value = 0;
|
|
|
|
|
// This is needed to make sure to emit BTF for the defined types,
|
|
|
|
|
// it could be dead code eliminated if we don't.
|
|
|
|
|
{relocation_code};
|
|
|
|
@ -218,17 +234,17 @@ struct RelocationTestRunner {
|
|
|
|
|
|
|
|
|
|
impl RelocationTestRunner {
|
|
|
|
|
/// Run test and return the output value
|
|
|
|
|
fn run(&self) -> Result<u32> {
|
|
|
|
|
fn run(&self) -> Result<u64> {
|
|
|
|
|
self.run_internal(true).context("Error running with BTF")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run without loading btf
|
|
|
|
|
fn run_no_btf(&self) -> Result<u32> {
|
|
|
|
|
fn run_no_btf(&self) -> Result<u64> {
|
|
|
|
|
self.run_internal(false)
|
|
|
|
|
.context("Error running without BTF")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn run_internal(&self, with_relocations: bool) -> Result<u32> {
|
|
|
|
|
fn run_internal(&self, with_relocations: bool) -> Result<u64> {
|
|
|
|
|
let mut loader = BpfLoader::new();
|
|
|
|
|
if with_relocations {
|
|
|
|
|
loader.btf(Some(&self.btf));
|
|
|
|
@ -250,7 +266,7 @@ impl RelocationTestRunner {
|
|
|
|
|
// To inspect the loaded eBPF bytecode, increse the timeout and run:
|
|
|
|
|
// $ sudo bpftool prog dump xlated name bpf_prog
|
|
|
|
|
|
|
|
|
|
let output_map: Array<_, u32> = bpf.take_map("output_map").unwrap().try_into().unwrap();
|
|
|
|
|
let output_map: Array<_, u64> = bpf.take_map("output_map").unwrap().try_into().unwrap();
|
|
|
|
|
let key = 0;
|
|
|
|
|
output_map.get(&key, 0).context("Getting key 0 failed")
|
|
|
|
|
}
|
|
|
|
|