Skip to content

Commit e4d5d1c

Browse files
authored
Merge pull request #20 from jpsamaroo/jps/bpfcall
Add bpfcall and runtime buffers
2 parents 8ddd527 + a76a1a8 commit e4d5d1c

File tree

14 files changed

+374
-51
lines changed

14 files changed

+374
-51
lines changed

Manifest.toml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ version = "0.4.1"
2828

2929
[[Clang_jll]]
3030
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "libLLVM_jll"]
31-
git-tree-sha1 = "b0db0edbfd3388b23f9578ec2ee7ff814f646649"
31+
git-tree-sha1 = "a5923c06de3178dd755f4b9411ea8922a7ae6fb8"
3232
uuid = "0ee61d77-7f21-5576-8119-9fcc46b10100"
33-
version = "11.0.0+7"
33+
version = "11.0.1+3"
3434

3535
[[Compat]]
3636
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
37-
git-tree-sha1 = "919c7f3151e79ff196add81d7f4e45d91bbf420b"
37+
git-tree-sha1 = "ac4132ad78082518ec2037ae5770b6e796f7f956"
3838
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
39-
version = "3.25.0"
39+
version = "3.27.0"
4040

4141
[[DataStructures]]
4242
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
@@ -83,9 +83,9 @@ version = "1.2.0"
8383

8484
[[LLVM]]
8585
deps = ["CEnum", "Libdl", "Printf", "Unicode"]
86-
git-tree-sha1 = "000a737732aa4eb996414c4685368f6a74b41d14"
86+
git-tree-sha1 = "b616937c31337576360cb9fb872ec7633af7b194"
8787
uuid = "929cbde3-209d-540e-8aea-75f648917ca0"
88-
version = "3.4.0"
88+
version = "3.6.0"
8989

9090
[[LibCURL]]
9191
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
@@ -142,7 +142,7 @@ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
142142
version = "1.4.0"
143143

144144
[[Pkg]]
145-
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs"]
145+
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
146146
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
147147

148148
[[Preferences]]
@@ -250,3 +250,7 @@ deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
250250
git-tree-sha1 = "c417cbbce3efb49a309b2d478fea9df7cfe024c0"
251251
uuid = "c88a4935-d25e-5644-aacc-5db6f1b8ef79"
252252
version = "1.1.0+0"
253+
254+
[[p7zip_jll]]
255+
deps = ["Artifacts", "Libdl"]
256+
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "BPFnative"
22
uuid = "b6338580-32ea-11e9-1791-33a79977d8c4"
33
authors = ["Julian P Samaroo <[email protected]>"]
4-
version = "0.1.1"
4+
version = "0.1.2"
55

66
[deps]
77
CBinding = "d43a6710-96b8-4a2d-833c-c424785e5374"
@@ -15,7 +15,7 @@ Preferences = "21216c6a-2e73-6563-6e65-726566657250"
1515
[compat]
1616
CBinding = "1"
1717
GPUCompiler = "0.9.1"
18-
LLVM = "= 3.4"
18+
LLVM = "3.6"
1919
Libbpf_jll = "0.3"
2020
Preferences = "1"
2121
julia = "1.6"

src/BPFnative.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,17 @@ end
5353
# Runtime API
5454
module RT
5555
import ..API
56-
include("runtime_maps.jl")
57-
include("misc.jl")
56+
include("runtime/bpfcall.jl")
57+
include("runtime/maps.jl")
58+
include("runtime/buffers.jl")
59+
include("runtime/helpers.jl")
5860
end
5961

6062
# Host API
6163
module Host
6264
import ..API
63-
include("syscall.jl")
64-
include("host_maps.jl")
65+
include("host/syscall.jl")
66+
include("host/maps.jl")
6567
end
6668

6769
# Compiler

src/compiler.jl

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const bpffunction_cache = Dict{UInt,Any}()
3939

4040
# actual compilation
4141
function bpffunction_compile(source::FunctionSpec; format=:obj, license="",
42-
prog_section="prog", btf=true, kwargs...)
42+
prog_section="prog", btf=false, kwargs...)
4343
# compile to BPF
4444
target = BPFCompilerTarget(; license, prog_section)
4545
params = BPFCompilerParams()
@@ -49,3 +49,96 @@ function bpffunction_compile(source::FunctionSpec; format=:obj, license="",
4949
return collect(codeunits(args[1]))
5050
end
5151
bpffunction_link(@nospecialize(source::FunctionSpec), exe; kwargs...) = exe
52+
53+
function GPUCompiler.finish_module!(job::BPFCompilerJob, mod::LLVM.Module)
54+
#= TODO: Fix upstream and re-enable if needed
55+
invoke(GPUCompiler.finish_module!,
56+
Tuple{CompilerJob{BPFCompilerTarget}, LLVM.Module},
57+
job, mod)
58+
=#
59+
60+
for func in LLVM.functions(mod)
61+
if LLVM.name(func) == "gpu_signal_exception"
62+
throw(GPUCompiler.KernelError(job, "eBPF does not support exceptions"))
63+
end
64+
# Set entry section for loaders like libbpf
65+
LLVM.section!(func, job.target.prog_section)
66+
end
67+
68+
# Set license
69+
license = job.target.license
70+
if license != ""
71+
ctx = LLVM.context(mod)
72+
i8 = LLVM.Int8Type(ctx)
73+
glob = GlobalVariable(mod, LLVM.ArrayType(i8, length(license)+1), "_license")
74+
linkage!(glob, LLVM.API.LLVMExternalLinkage)
75+
constant!(glob, true)
76+
section!(glob, "license")
77+
str = ConstantArray(Vector{UInt8}(license*'\0'), ctx)
78+
@assert context(glob) == context(str) == ctx
79+
initializer!(glob, str)
80+
end
81+
82+
# Set all map definitions as external linkage
83+
for gv in filter(x->(section(x)=="maps")||(section(x)==".maps"), collect(LLVM.globals(mod)))
84+
linkage!(gv, LLVM.API.LLVMExternalLinkage)
85+
end
86+
87+
ModulePassManager() do pm
88+
if Base.JLOptions().debug_level > 1
89+
# Validate contexts, for my sanity
90+
add!(pm, ModulePass("BPFValidateContexts", validate_contexts!))
91+
end
92+
# Promote `@malloc` intrinsics
93+
add!(pm, FunctionPass("BPFHeapToStack", heap_to_stack!))
94+
run!(pm, mod)
95+
end
96+
end
97+
98+
"Validates LLVM contexts of all the things."
99+
function validate_contexts!(mod::LLVM.Module)
100+
ctx = LLVM.context(mod)
101+
for fn in LLVM.functions(mod)
102+
@assert context(fn) == ctx "Failed validation: $fn"
103+
for bb in LLVM.blocks(fn)
104+
for insn in LLVM.instructions(bb)
105+
@assert context(insn) == ctx "Failed validation: $insn"
106+
for op in LLVM.operands(insn)
107+
@assert context(op) == ctx "Failed validation: $op"
108+
end
109+
end
110+
end
111+
end
112+
for gv in LLVM.globals(mod)
113+
@assert context(gv) == ctx "Failed validation: $gv"
114+
end
115+
false
116+
end
117+
118+
"Promotes `@malloc` intrinsics to allocas."
119+
function heap_to_stack!(fn::LLVM.Function)
120+
changed = false
121+
ctx = LLVM.context(fn)
122+
for bb in LLVM.blocks(fn)
123+
for insn in LLVM.instructions(bb)
124+
if insn isa LLVM.CallInst && LLVM.name(LLVM.called_value(insn)) == "malloc"
125+
sz = convert(Int64, LLVM.operands(insn)[1])
126+
T_i8 = LLVM.Int8Type(ctx)
127+
T_pi8 = LLVM.PointerType(T_i8)
128+
T_buf = LLVM.ArrayType(T_i8, sz)
129+
Builder(ctx) do builder
130+
# Place alloca at beginning of entry
131+
position!(builder, first(LLVM.instructions(first(LLVM.blocks(fn)))))
132+
buf = alloca!(builder, T_buf)
133+
# Replace malloc with bitcast'd alloca
134+
position!(builder, insn)
135+
new_insn = bitcast!(builder, buf, T_pi8)
136+
replace_uses!(insn, new_insn)
137+
unsafe_delete!(LLVM.parent(insn), insn)
138+
end
139+
changed = true
140+
end
141+
end
142+
end
143+
changed
144+
end

src/host_maps.jl renamed to src/host/maps.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function Base.delete!(map::AbstractHashMap{K,V}, idx) where {K,V}
116116
map
117117
end
118118

119-
function Base.haskey(map::AbstractHashMap{K,V}, idx) where {K,V}
119+
function Base.haskey(map::HostMap{K,V}, idx) where {K,V}
120120
key = Ref{K}(idx)
121121
value = Ref{V}()
122122
key_ptr = Base.unsafe_convert(Ptr{K}, key)
File renamed without changes.

src/misc.jl

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/probes.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ struct KProbe <: AbstractProbe
99
kfunc::String
1010
retprobe::Bool
1111
end
12-
function KProbe(f::Function, kfunc; retprobe=false)
13-
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
12+
function KProbe(f::Function, kfunc; retprobe=false, kwargs...)
13+
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
1414
foreach(prog->API.set_kprobe!(prog), API.programs(obj))
1515
KProbe(obj, kfunc, retprobe)
1616
end
@@ -20,8 +20,8 @@ struct UProbe{F<:Function,T} <: AbstractProbe
2020
sig::T
2121
retprobe::Bool
2222
end
23-
function UProbe(f::Function, method, sig; retprobe=false)
24-
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
23+
function UProbe(f::Function, method, sig; retprobe=false, kwargs...)
24+
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
2525
#foreach(prog->API.set_uprobe!(prog), API.programs(obj))
2626
foreach(prog->API.set_kprobe!(prog), API.programs(obj))
2727
UProbe(obj, method, sig, retprobe)
@@ -31,18 +31,18 @@ struct Tracepoint <: AbstractProbe
3131
category::String
3232
name::String
3333
end
34-
function Tracepoint(f::Function, category, name)
35-
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
34+
function Tracepoint(f::Function, category, name; kwargs...)
35+
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
3636
foreach(prog->API.set_tracepoint!(prog), API.programs(obj))
3737
Tracepoint(obj, category, name)
3838
end
3939

4040
Base.show(io::IO, p::KProbe) =
41-
print(io, "KProbe ($(p.kfunc)")
41+
print(io, "KProbe ($(p.kfunc))")
4242
Base.show(io::IO, p::UProbe) =
4343
print(io, "UProbe ($(p.func)($(p.sig)))")
4444
Base.show(io::IO, p::Tracepoint) =
45-
print(io, "Tracepoint ($(p.category)/$(p.name)")
45+
print(io, "Tracepoint ($(p.category)/$(p.name))")
4646

4747
function API.load(p::KProbe)
4848
API.load(p.obj)

src/reflection.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ for method in (:code_typed, :code_warntype, :code_llvm, :code_native)
1414
function $method(io::IO, @nospecialize(func), @nospecialize(types);
1515
kernel::Bool=false, kwargs...)
1616
source = FunctionSpec(func, Base.to_tuple_type(types), kernel)
17-
target = BPFCompilerTarget(; dev_isa=default_isa(default_device()))
17+
target = BPFCompilerTarget()
1818
params = BPFCompilerParams()
1919
job = CompilerJob(target, source, params)
2020
GPUCompiler.$method($(args...); kwargs...)

src/runtime/bpfcall.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export bpfcall
2+
3+
@generated function _bpfcall(::Val{cmd}, ::Type{rettype}, ::Type{argtypes}, args::Vararg{Any}) where {cmd,rettype,argtypes}
4+
JuliaContext() do ctx
5+
T_ret = convert(LLVMType, rettype, ctx)
6+
T_args = map(x->convert(LLVMType, x, ctx), argtypes.parameters)
7+
8+
llvm_f, _ = create_function(T_ret, LLVMType[T_args...])
9+
mod = LLVM.parent(llvm_f)
10+
11+
Builder(ctx) do builder
12+
entry = BasicBlock(llvm_f, "entry", ctx)
13+
position!(builder, entry)
14+
ft = LLVM.FunctionType(T_ret, LLVMType[T_args...])
15+
ftp = LLVM.PointerType(ft)
16+
f = inttoptr!(builder, ConstantInt(cmd, ctx), ftp)
17+
value = call!(builder, f, LLVM.Value[parameters(llvm_f)...])
18+
ret!(builder, value)
19+
end
20+
call_function(llvm_f, rettype, Base.to_tuple_type(args), :((args...,)))
21+
end
22+
end
23+
@inline bpfcall(cmd::API.BPFHelper, RT, AT, args...) =
24+
_bpfcall(Val(Int(cmd)), RT, AT, args...)
25+
@inline bpfcall(cmd::API.BPFHelper, RT) = _bpfcall(Val(Int(cmd)), RT, Tuple{})
26+
@inline bpfcall(cmd::API.BPFHelper) = _bpfcall(Val(Int(cmd)), Cvoid, Tuple{})

0 commit comments

Comments
 (0)