Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ version = "0.4.1"

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

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

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
Expand Down Expand Up @@ -83,9 +83,9 @@ version = "1.2.0"

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

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
Expand Down Expand Up @@ -142,7 +142,7 @@ uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.0"

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

[[Preferences]]
Expand Down Expand Up @@ -250,3 +250,7 @@ deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c417cbbce3efb49a309b2d478fea9df7cfe024c0"
uuid = "c88a4935-d25e-5644-aacc-5db6f1b8ef79"
version = "1.1.0+0"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "BPFnative"
uuid = "b6338580-32ea-11e9-1791-33a79977d8c4"
authors = ["Julian P Samaroo <[email protected]>"]
version = "0.1.1"
version = "0.1.2"

[deps]
CBinding = "d43a6710-96b8-4a2d-833c-c424785e5374"
Expand All @@ -15,7 +15,7 @@ Preferences = "21216c6a-2e73-6563-6e65-726566657250"
[compat]
CBinding = "1"
GPUCompiler = "0.9.1"
LLVM = "= 3.4"
LLVM = "3.6"
Libbpf_jll = "0.3"
Preferences = "1"
julia = "1.6"
Expand Down
10 changes: 6 additions & 4 deletions src/BPFnative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ end
# Runtime API
module RT
import ..API
include("runtime_maps.jl")
include("misc.jl")
include("runtime/bpfcall.jl")
include("runtime/maps.jl")
include("runtime/buffers.jl")
include("runtime/helpers.jl")
end

# Host API
module Host
import ..API
include("syscall.jl")
include("host_maps.jl")
include("host/syscall.jl")
include("host/maps.jl")
end

# Compiler
Expand Down
95 changes: 94 additions & 1 deletion src/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const bpffunction_cache = Dict{UInt,Any}()

# actual compilation
function bpffunction_compile(source::FunctionSpec; format=:obj, license="",
prog_section="prog", btf=true, kwargs...)
prog_section="prog", btf=false, kwargs...)
# compile to BPF
target = BPFCompilerTarget(; license, prog_section)
params = BPFCompilerParams()
Expand All @@ -49,3 +49,96 @@ function bpffunction_compile(source::FunctionSpec; format=:obj, license="",
return collect(codeunits(args[1]))
end
bpffunction_link(@nospecialize(source::FunctionSpec), exe; kwargs...) = exe

function GPUCompiler.finish_module!(job::BPFCompilerJob, mod::LLVM.Module)
#= TODO: Fix upstream and re-enable if needed
invoke(GPUCompiler.finish_module!,
Tuple{CompilerJob{BPFCompilerTarget}, LLVM.Module},
job, mod)
=#

for func in LLVM.functions(mod)
if LLVM.name(func) == "gpu_signal_exception"
throw(GPUCompiler.KernelError(job, "eBPF does not support exceptions"))
end
# Set entry section for loaders like libbpf
LLVM.section!(func, job.target.prog_section)
end

# Set license
license = job.target.license
if license != ""
ctx = LLVM.context(mod)
i8 = LLVM.Int8Type(ctx)
glob = GlobalVariable(mod, LLVM.ArrayType(i8, length(license)+1), "_license")
linkage!(glob, LLVM.API.LLVMExternalLinkage)
constant!(glob, true)
section!(glob, "license")
str = ConstantArray(Vector{UInt8}(license*'\0'), ctx)
@assert context(glob) == context(str) == ctx
initializer!(glob, str)
end

# Set all map definitions as external linkage
for gv in filter(x->(section(x)=="maps")||(section(x)==".maps"), collect(LLVM.globals(mod)))
linkage!(gv, LLVM.API.LLVMExternalLinkage)
end

ModulePassManager() do pm
if Base.JLOptions().debug_level > 1
# Validate contexts, for my sanity
add!(pm, ModulePass("BPFValidateContexts", validate_contexts!))
end
# Promote `@malloc` intrinsics
add!(pm, FunctionPass("BPFHeapToStack", heap_to_stack!))
run!(pm, mod)
end
end

"Validates LLVM contexts of all the things."
function validate_contexts!(mod::LLVM.Module)
ctx = LLVM.context(mod)
for fn in LLVM.functions(mod)
@assert context(fn) == ctx "Failed validation: $fn"
for bb in LLVM.blocks(fn)
for insn in LLVM.instructions(bb)
@assert context(insn) == ctx "Failed validation: $insn"
for op in LLVM.operands(insn)
@assert context(op) == ctx "Failed validation: $op"
end
end
end
end
for gv in LLVM.globals(mod)
@assert context(gv) == ctx "Failed validation: $gv"
end
false
end

"Promotes `@malloc` intrinsics to allocas."
function heap_to_stack!(fn::LLVM.Function)
changed = false
ctx = LLVM.context(fn)
for bb in LLVM.blocks(fn)
for insn in LLVM.instructions(bb)
if insn isa LLVM.CallInst && LLVM.name(LLVM.called_value(insn)) == "malloc"
sz = convert(Int64, LLVM.operands(insn)[1])
T_i8 = LLVM.Int8Type(ctx)
T_pi8 = LLVM.PointerType(T_i8)
T_buf = LLVM.ArrayType(T_i8, sz)
Builder(ctx) do builder
# Place alloca at beginning of entry
position!(builder, first(LLVM.instructions(first(LLVM.blocks(fn)))))
buf = alloca!(builder, T_buf)
# Replace malloc with bitcast'd alloca
position!(builder, insn)
new_insn = bitcast!(builder, buf, T_pi8)
replace_uses!(insn, new_insn)
unsafe_delete!(LLVM.parent(insn), insn)
end
changed = true
end
end
end
changed
end
2 changes: 1 addition & 1 deletion src/host_maps.jl → src/host/maps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function Base.delete!(map::AbstractHashMap{K,V}, idx) where {K,V}
map
end

function Base.haskey(map::AbstractHashMap{K,V}, idx) where {K,V}
function Base.haskey(map::HostMap{K,V}, idx) where {K,V}
key = Ref{K}(idx)
value = Ref{V}()
key_ptr = Base.unsafe_convert(Ptr{K}, key)
Expand Down
File renamed without changes.
22 changes: 0 additions & 22 deletions src/misc.jl

This file was deleted.

16 changes: 8 additions & 8 deletions src/probes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ struct KProbe <: AbstractProbe
kfunc::String
retprobe::Bool
end
function KProbe(f::Function, kfunc; retprobe=false)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
function KProbe(f::Function, kfunc; retprobe=false, kwargs...)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
foreach(prog->API.set_kprobe!(prog), API.programs(obj))
KProbe(obj, kfunc, retprobe)
end
Expand All @@ -20,8 +20,8 @@ struct UProbe{F<:Function,T} <: AbstractProbe
sig::T
retprobe::Bool
end
function UProbe(f::Function, method, sig; retprobe=false)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
function UProbe(f::Function, method, sig; retprobe=false, kwargs...)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
#foreach(prog->API.set_uprobe!(prog), API.programs(obj))
foreach(prog->API.set_kprobe!(prog), API.programs(obj))
UProbe(obj, method, sig, retprobe)
Expand All @@ -31,18 +31,18 @@ struct Tracepoint <: AbstractProbe
category::String
name::String
end
function Tracepoint(f::Function, category, name)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false))
function Tracepoint(f::Function, category, name; kwargs...)
obj = API.Object(bpffunction(f, Tuple{API.pointertype(API.pt_regs)}; btf=false, kwargs...))
foreach(prog->API.set_tracepoint!(prog), API.programs(obj))
Tracepoint(obj, category, name)
end

Base.show(io::IO, p::KProbe) =
print(io, "KProbe ($(p.kfunc)")
print(io, "KProbe ($(p.kfunc))")
Base.show(io::IO, p::UProbe) =
print(io, "UProbe ($(p.func)($(p.sig)))")
Base.show(io::IO, p::Tracepoint) =
print(io, "Tracepoint ($(p.category)/$(p.name)")
print(io, "Tracepoint ($(p.category)/$(p.name))")

function API.load(p::KProbe)
API.load(p.obj)
Expand Down
2 changes: 1 addition & 1 deletion src/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ for method in (:code_typed, :code_warntype, :code_llvm, :code_native)
function $method(io::IO, @nospecialize(func), @nospecialize(types);
kernel::Bool=false, kwargs...)
source = FunctionSpec(func, Base.to_tuple_type(types), kernel)
target = BPFCompilerTarget(; dev_isa=default_isa(default_device()))
target = BPFCompilerTarget()
params = BPFCompilerParams()
job = CompilerJob(target, source, params)
GPUCompiler.$method($(args...); kwargs...)
Expand Down
26 changes: 26 additions & 0 deletions src/runtime/bpfcall.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export bpfcall

@generated function _bpfcall(::Val{cmd}, ::Type{rettype}, ::Type{argtypes}, args::Vararg{Any}) where {cmd,rettype,argtypes}
JuliaContext() do ctx
T_ret = convert(LLVMType, rettype, ctx)
T_args = map(x->convert(LLVMType, x, ctx), argtypes.parameters)

llvm_f, _ = create_function(T_ret, LLVMType[T_args...])
mod = LLVM.parent(llvm_f)

Builder(ctx) do builder
entry = BasicBlock(llvm_f, "entry", ctx)
position!(builder, entry)
ft = LLVM.FunctionType(T_ret, LLVMType[T_args...])
ftp = LLVM.PointerType(ft)
f = inttoptr!(builder, ConstantInt(cmd, ctx), ftp)
value = call!(builder, f, LLVM.Value[parameters(llvm_f)...])
ret!(builder, value)
end
call_function(llvm_f, rettype, Base.to_tuple_type(args), :((args...,)))
end
end
@inline bpfcall(cmd::API.BPFHelper, RT, AT, args...) =
_bpfcall(Val(Int(cmd)), RT, AT, args...)
@inline bpfcall(cmd::API.BPFHelper, RT) = _bpfcall(Val(Int(cmd)), RT, Tuple{})
@inline bpfcall(cmd::API.BPFHelper) = _bpfcall(Val(Int(cmd)), Cvoid, Tuple{})
Loading