Skip to content

Commit

Permalink
Merge branch 'master' into patch-12
Browse files Browse the repository at this point in the history
  • Loading branch information
Rtoax committed Apr 2, 2022
2 parents afa7801 + 9382ad1 commit fcb70ad
Show file tree
Hide file tree
Showing 31 changed files with 266 additions and 160 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to
- [#2147](https://github.com/iovisor/bpftrace/pull/2147)
- Improve include paths resolution
- [#2149](https://github.com/iovisor/bpftrace/pull/2149)
- Add builtin function: `bswap`
- [#2166](https://github.com/iovisor/bpftrace/pull/2166)

#### Changed
#### Deprecated
Expand Down
19 changes: 18 additions & 1 deletion docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,7 @@ Tracing block I/O sizes > 0 bytes
- `uptr(void *p)` - Annotate as userspace pointer
- `kptr(void *p)` - Annotate as kernelspace pointer
- `macaddr(char[6] addr)` - Convert MAC address data
- `bswap(uint[8|16|32|64] n)` - Reverse byte order

Some of these are asynchronous: the kernel queues the event, but some time later (milliseconds) it is
processed in user-space. The asynchronous actions are: `printf()`, `time()`, and `join()`. Both `ksym()`
Expand Down Expand Up @@ -3122,6 +3123,21 @@ Attaching 1 probe...
unified:/user.slice/user-1000.slice/session-3.scope
```

## 30. `bswap`: Reverse byte order

Syntax: `bswap(uint[8|16|32|64] n)`

Reverses the order of the bytes in integer `n`. In case of 8 bit integers, `n` is returned without being modified.
The return type is an unsigned integer of the same width as `n`.

Example:

```
# bpftrace -e 'BEGIN { $i = (uint32)0x12345678; printf("Reversing byte order of 0x%x ==> 0x%x\n", $i, bswap($i)); }'
Attaching 1 probe...
Reversing byte order of 0x12345678 ==> 0x78563412
```

# Map Functions

Maps are special BPF data types that can be used to store counts, statistics, and histograms. They are
Expand Down Expand Up @@ -3632,4 +3648,5 @@ bpftrace requires kernel headers for certain features, which are searched for by
/lib/modules/$(uname -r)
```

The default search directory can be overridden using the environment variable `BPFTRACE_KERNEL_SOURCE`.
The default search directory can be overridden using the environment variable `BPFTRACE_KERNEL_SOURCE`, and
also `BPFTRACE_KERNEL_BUILD` if it is out-of-tree Linux kernel build.
11 changes: 11 additions & 0 deletions man/adoc/bpftrace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,17 @@ Functions that are marked *async* are asynchronous which can lead to unexpected

*unsafe* functions can have dangerous side effects and should be used with care, the `--unsafe` flag is required for use.

=== bswap

.variants
* `uint8 bswap(uint8 n)`
* `uint16 bswap(uint16 n)`
* `uint32 bswap(uint32 n)`
* `uint64 bswap(uint64 n)`

`bswap` reverses the order of the bytes in integer `n`. In case of 8 bit integers, `n` is returned without being modified.
The return type is an unsigned integer of the same width as `n`.

=== buf

.variants
Expand Down
20 changes: 17 additions & 3 deletions src/ast/passes/codegen_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,22 @@ void CodegenLLVM::visit(Call &call)
b_.CreateLifetimeEnd(buf);
expr_ = nullptr;
}
else if (call.func == "bswap")
{
bpftrace::ast::Expression *arg = call.vargs->at(0);
auto scoped_del_arg = accept(arg);

assert(arg->type.IsIntegerTy());
if (arg->type.GetSize() > 1)
{
llvm::Type *arg_type = b_.GetType(arg->type);
Function *swap_fun = Intrinsic::getDeclaration(module_.get(),
Intrinsic::bswap,
{ arg_type });

expr_ = b_.CreateCall(swap_fun, { expr_ });
}
}
else
{
LOG(FATAL) << "missing codegen for function \"" << call.func << "\"";
Expand Down Expand Up @@ -3286,9 +3302,7 @@ void CodegenLLVM::probereadDatastructElem(Value *src_data,
AllocaInst *dst = b_.CreateAllocaBPF(elem_type, temp_name);
b_.CreateProbeRead(
ctx_, dst, elem_type.GetSize(), src, data_type.GetAS(), loc);
expr_ = b_.CreateIntCast(b_.CreateLoad(b_.GetType(elem_type), dst),
b_.getInt64Ty(),
elem_type.IsSigned());
expr_ = b_.CreateLoad(b_.GetType(elem_type), dst);
b_.CreateLifetimeEnd(dst);
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/ast/passes/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,22 @@ void SemanticAnalyser::visit(Call &call)
// Return type cannot be used
call.type = SizedType(Type::none, 0);
}
else if (call.func == "bswap")
{
if (!check_nargs(call, 1))
return;

Expression *arg = call.vargs->at(0);
if (arg->type.type != Type::integer)
{
LOG(ERROR, call.loc, err_)
<< call.func << "() only supports integer arguments ("
<< arg->type.type << " provided)";
return;
}

call.type = CreateUInt(arg->type.GetIntBitWidth());
}
else
{
LOG(ERROR, call.loc, err_) << "Unknown function: '" << call.func << "'";
Expand Down
25 changes: 10 additions & 15 deletions src/attached_probe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,9 +676,8 @@ void AttachedProbe::load_prog()

uint64_t log_buf_size = probe_.log_size;
auto log_buf = std::make_unique<char[]>(log_buf_size);
char name[STRING_SIZE];
const char *namep;
std::string tracing_type, tracing_name;
std::string name;
std::string tracing_type;

{
// Redirect stderr, so we don't get error messages from BCC
Expand All @@ -694,16 +693,13 @@ void AttachedProbe::load_prog()

// Use orig_name for program name so we get proper name for
// wildcard probes, replace wildcards with '.'
std::string orig_name = probe_.orig_name;
std::replace(orig_name.begin(), orig_name.end(), '*', '.');

strncpy(name, orig_name.c_str(), STRING_SIZE - 1);
namep = name;
name = probe_.orig_name;
std::replace(name.begin(), name.end(), '*', '.');

// bpf_prog_load rejects colons in the probe name,
// so start the name after the probe type, after ':'
if (strrchr(name, ':') != NULL)
namep = strrchr(name, ':') + 1;
if (auto last_colon = name.rfind(':'); last_colon != std::string::npos)
name = name.substr(last_colon + 1);

// The bcc_prog_load function now recognizes 'kfunc__/kretfunc__'
// prefixes and detects and fills in all the necessary BTF related
Expand All @@ -715,8 +711,7 @@ void AttachedProbe::load_prog()
if (tracing_type == "iter")
tracing_type = "bpf_iter";

tracing_name = tracing_type + "__" + namep;
namep = tracing_name.c_str();
name = tracing_type + "__" + name;
}

for (int attempt = 0; attempt < 3; attempt++)
Expand All @@ -735,7 +730,7 @@ void AttachedProbe::load_prog()
struct bpf_load_program_attr attr = {};

attr.prog_type = progtype(probe_.type);
attr.name = namep;
attr.name = name.c_str();
attr.insns = reinterpret_cast<struct bpf_insn *>(insns);
attr.license = license;

Expand All @@ -754,10 +749,10 @@ void AttachedProbe::load_prog()
#else // HAVE_BCC_PROG_LOAD_XATTR
#ifdef HAVE_BCC_PROG_LOAD
progfd_ = bcc_prog_load(progtype(probe_.type),
namep,
name.c_str(),
#else
progfd_ = bpf_prog_load(progtype(probe_.type),
namep,
name.c_str(),
#endif
reinterpret_cast<struct bpf_insn *>(insns),
prog_len,
Expand Down
2 changes: 1 addition & 1 deletion src/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ vspace [\n\r]
space {hspace}|{vspace}
path :(\\.|[_\-\./a-zA-Z0-9#\*])+
builtin arg[0-9]|args|cgroup|comm|cpid|numaid|cpu|ctx|curtask|elapsed|func|gid|nsecs|pid|probe|rand|retval|sarg[0-9]|tid|uid|username
call avg|buf|cat|cgroupid|clear|count|delete|exit|hist|join|kaddr|kptr|ksym|lhist|macaddr|max|min|ntop|override|print|printf|cgroup_path|reg|signal|sizeof|stats|str|strftime|strncmp|sum|system|time|uaddr|uptr|usym|zero|path|unwatch
call avg|buf|cat|cgroupid|clear|count|delete|exit|hist|join|kaddr|kptr|ksym|lhist|macaddr|max|min|ntop|override|print|printf|cgroup_path|reg|signal|sizeof|stats|str|strftime|strncmp|sum|system|time|uaddr|uptr|usym|zero|path|unwatch|bswap

/* Don't add to this! Use builtin OR call not both */
call_and_builtin kstack|ustack
Expand Down
9 changes: 8 additions & 1 deletion src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,14 @@ std::tuple<std::string, std::string> get_kernel_dirs(

const char *kpath_env = ::getenv("BPFTRACE_KERNEL_SOURCE");
if (kpath_env)
return std::make_tuple(kpath_env, kpath_env);
{
const char *kpath_build_env = ::getenv("BPFTRACE_KERNEL_BUILD");
if (!kpath_build_env)
{
kpath_build_env = kpath_env;
}
return std::make_tuple(kpath_env, kpath_build_env);
}

std::string kdir = std::string("/lib/modules/") + utsname.release;
auto ksrc = kdir + "/source";
Expand Down
8 changes: 4 additions & 4 deletions tests/codegen/llvm/builtin_ctx_field.ll
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ entry:
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %"struct c.c")
%probe_read_kernel = call i64 inttoptr (i64 113 to i64 (i8*, i32, i64)*)(i8* %"struct c.c", i32 1, i64 %35)
%36 = load i8, i8* %"struct c.c", align 1
%37 = sext i8 %36 to i64
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %"struct c.c")
%38 = bitcast i64* %"@d_key" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %38)
%37 = bitcast i64* %"@d_key" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %37)
store i64 0, i64* %"@d_key", align 8
%38 = sext i8 %36 to i64
%39 = bitcast i64* %"@d_val" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %39)
store i64 %37, i64* %"@d_val", align 8
store i64 %38, i64* %"@d_val", align 8
%pseudo5 = call i64 @llvm.bpf.pseudo(i64 1, i64 3)
%update_elem6 = call i64 inttoptr (i64 2 to i64 (i64, i64*, i64*, i64)*)(i64 %pseudo5, i64* %"@d_key", i64* %"@d_val", i64 0)
%40 = bitcast i64* %"@d_val" to i8*
Expand Down
6 changes: 3 additions & 3 deletions tests/codegen/llvm/call_printf.ll
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ entry:
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %"struct Foo.c")
%probe_read_kernel = call i64 inttoptr (i64 113 to i64 (i8*, i32, i64)*)(i8* %"struct Foo.c", i32 1, i64 %8)
%9 = load i8, i8* %"struct Foo.c", align 1
%10 = sext i8 %9 to i64
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %"struct Foo.c")
%11 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 1
store i64 %10, i64* %11, align 8
%10 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 1
%11 = sext i8 %9 to i64
store i64 %11, i64* %10, align 8
%12 = load i64, i64* %"$foo", align 8
%13 = add i64 %12, 8
%14 = bitcast i64* %"struct Foo.l" to i8*
Expand Down
102 changes: 49 additions & 53 deletions tests/codegen/llvm/logical_and_or_different_type.ll
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ entry:
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %10)
%probe_read_user = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m", i32 4, i64 %9)
%11 = load i32, i32* %"struct Foo.m", align 4
%12 = sext i32 %11 to i64
%13 = bitcast i32* %"struct Foo.m" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %13)
%lhs_true_cond = icmp ne i64 %12, 0
%12 = bitcast i32* %"struct Foo.m" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
%lhs_true_cond = icmp ne i32 %11, 0
br i1 %lhs_true_cond, label %"&&_lhs_true", label %"&&_false"

"&&_lhs_true": ; preds = %entry
Expand All @@ -59,24 +58,23 @@ entry:
br label %"&&_merge"

"&&_merge": ; preds = %"&&_false", %"&&_true"
%14 = load i64, i64* %"&&_result", align 8
%15 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 1
store i64 %14, i64* %15, align 8
%16 = bitcast i64* %"&&_result5" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %16)
%13 = load i64, i64* %"&&_result", align 8
%14 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 1
store i64 %13, i64* %14, align 8
%15 = bitcast i64* %"&&_result5" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %15)
br i1 true, label %"&&_lhs_true1", label %"&&_false3"

"&&_lhs_true1": ; preds = %"&&_merge"
%17 = load i64, i64* %"$foo", align 8
%18 = add i64 %17, 0
%19 = bitcast i32* %"struct Foo.m6" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %19)
%probe_read_user7 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m6", i32 4, i64 %18)
%20 = load i32, i32* %"struct Foo.m6", align 4
%21 = sext i32 %20 to i64
%22 = bitcast i32* %"struct Foo.m6" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %22)
%rhs_true_cond = icmp ne i64 %21, 0
%16 = load i64, i64* %"$foo", align 8
%17 = add i64 %16, 0
%18 = bitcast i32* %"struct Foo.m6" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %18)
%probe_read_user7 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m6", i32 4, i64 %17)
%19 = load i32, i32* %"struct Foo.m6", align 4
%20 = bitcast i32* %"struct Foo.m6" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %20)
%rhs_true_cond = icmp ne i32 %19, 0
br i1 %rhs_true_cond, label %"&&_true2", label %"&&_false3"

"&&_true2": ; preds = %"&&_lhs_true1"
Expand All @@ -88,21 +86,20 @@ entry:
br label %"&&_merge4"

"&&_merge4": ; preds = %"&&_false3", %"&&_true2"
%23 = load i64, i64* %"&&_result5", align 8
%24 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 2
store i64 %23, i64* %24, align 8
%25 = bitcast i64* %"||_result" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %25)
%26 = load i64, i64* %"$foo", align 8
%27 = add i64 %26, 0
%21 = load i64, i64* %"&&_result5", align 8
%22 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 2
store i64 %21, i64* %22, align 8
%23 = bitcast i64* %"||_result" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %23)
%24 = load i64, i64* %"$foo", align 8
%25 = add i64 %24, 0
%26 = bitcast i32* %"struct Foo.m8" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %26)
%probe_read_user9 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m8", i32 4, i64 %25)
%27 = load i32, i32* %"struct Foo.m8", align 4
%28 = bitcast i32* %"struct Foo.m8" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %28)
%probe_read_user9 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m8", i32 4, i64 %27)
%29 = load i32, i32* %"struct Foo.m8", align 4
%30 = sext i32 %29 to i64
%31 = bitcast i32* %"struct Foo.m8" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %31)
%lhs_true_cond10 = icmp ne i64 %30, 0
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %28)
%lhs_true_cond10 = icmp ne i32 %27, 0
br i1 %lhs_true_cond10, label %"||_true", label %"||_lhs_false"

"||_lhs_false": ; preds = %"&&_merge4"
Expand All @@ -117,24 +114,23 @@ entry:
br label %"||_merge"

"||_merge": ; preds = %"||_true", %"||_false"
%32 = load i64, i64* %"||_result", align 8
%33 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 3
store i64 %32, i64* %33, align 8
%34 = bitcast i64* %"||_result15" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %34)
%29 = load i64, i64* %"||_result", align 8
%30 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 3
store i64 %29, i64* %30, align 8
%31 = bitcast i64* %"||_result15" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %31)
br i1 false, label %"||_true13", label %"||_lhs_false11"

"||_lhs_false11": ; preds = %"||_merge"
%35 = load i64, i64* %"$foo", align 8
%36 = add i64 %35, 0
%37 = bitcast i32* %"struct Foo.m16" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %37)
%probe_read_user17 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m16", i32 4, i64 %36)
%38 = load i32, i32* %"struct Foo.m16", align 4
%39 = sext i32 %38 to i64
%40 = bitcast i32* %"struct Foo.m16" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %40)
%rhs_true_cond18 = icmp ne i64 %39, 0
%32 = load i64, i64* %"$foo", align 8
%33 = add i64 %32, 0
%34 = bitcast i32* %"struct Foo.m16" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %34)
%probe_read_user17 = call i64 inttoptr (i64 112 to i64 (i32*, i32, i64)*)(i32* %"struct Foo.m16", i32 4, i64 %33)
%35 = load i32, i32* %"struct Foo.m16", align 4
%36 = bitcast i32* %"struct Foo.m16" to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %36)
%rhs_true_cond18 = icmp ne i32 %35, 0
br i1 %rhs_true_cond18, label %"||_true13", label %"||_false12"

"||_false12": ; preds = %"||_lhs_false11"
Expand All @@ -146,13 +142,13 @@ entry:
br label %"||_merge14"

"||_merge14": ; preds = %"||_true13", %"||_false12"
%41 = load i64, i64* %"||_result15", align 8
%42 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 4
store i64 %41, i64* %42, align 8
%37 = load i64, i64* %"||_result15", align 8
%38 = getelementptr %printf_t, %printf_t* %printf_args, i32 0, i32 4
store i64 %37, i64* %38, align 8
%pseudo = call i64 @llvm.bpf.pseudo(i64 1, i64 0)
%perf_event_output = call i64 inttoptr (i64 25 to i64 (i8*, i64, i64, %printf_t*, i64)*)(i8* %0, i64 %pseudo, i64 4294967295, %printf_t* %printf_args, i64 40)
%43 = bitcast %printf_t* %printf_args to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %43)
%39 = bitcast %printf_t* %printf_args to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %39)
ret i64 0
}

Expand Down
Loading

0 comments on commit fcb70ad

Please sign in to comment.