forked from OSchip/llvm-project
[bpf] error when unknown bpf helper is called
Emit error when BPF backend sees a call to a global function or to an external symbol. The kernel verifier only allows calls to predefined helpers from bpf.h which are defined in 'enum bpf_func_id'. Such calls in assembler must look like 'call [1-9]+' where number matches bpf_func_id. Signed-off-by: Alexei Starovoitov <ast@kernel.org> llvm-svn: 292204
This commit is contained in:
parent
c0857a40e7
commit
e4975487f5
|
@ -33,7 +33,7 @@ using namespace llvm;
|
|||
|
||||
#define DEBUG_TYPE "bpf-lower"
|
||||
|
||||
static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg) {
|
||||
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg) {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
DAG.getContext()->diagnose(
|
||||
DiagnosticInfoUnsupported(*MF.getFunction(), Msg, DL.getDebugLoc()));
|
||||
|
@ -306,11 +306,23 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
|||
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
||||
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
||||
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
||||
auto GV = G->getGlobal();
|
||||
Twine Msg("A call to global function '" + StringRef(GV->getName())
|
||||
+ "' is not supported. "
|
||||
+ (GV->isDeclaration() ?
|
||||
"Only calls to predefined BPF helpers are allowed." :
|
||||
"Please use __attribute__((always_inline) to make sure"
|
||||
" this function is inlined."));
|
||||
fail(CLI.DL, DAG, Msg);
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, PtrVT,
|
||||
G->getOffset(), 0);
|
||||
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
||||
} else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
||||
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
|
||||
fail(CLI.DL, DAG, Twine("A call to built-in function '"
|
||||
+ StringRef(E->getSymbol())
|
||||
+ "' is not supported."));
|
||||
}
|
||||
|
||||
// Returns a chain & a flag for retval copy to use.
|
||||
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
||||
|
|
|
@ -470,6 +470,7 @@ def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)),
|
|||
|
||||
// Calls
|
||||
def : Pat<(BPFcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>;
|
||||
def : Pat<(BPFcall texternalsym:$dst), (JAL texternalsym:$dst)>;
|
||||
def : Pat<(BPFcall imm:$dst), (JAL imm:$dst)>;
|
||||
|
||||
// Loads
|
||||
|
|
|
@ -29,6 +29,11 @@ BPFMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
|
|||
return Printer.getSymbol(MO.getGlobal());
|
||||
}
|
||||
|
||||
MCSymbol *
|
||||
BPFMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const {
|
||||
return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
|
||||
}
|
||||
|
||||
MCOperand BPFMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
|
||||
MCSymbol *Sym) const {
|
||||
|
||||
|
@ -66,6 +71,9 @@ void BPFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
|
|||
break;
|
||||
case MachineOperand::MO_RegisterMask:
|
||||
continue;
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
|
||||
break;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
|
||||
break;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
|
||||
|
||||
MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
|
||||
MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpfel -show-mc-encoding | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpfel -show-mc-encoding | FileCheck %s
|
||||
|
||||
define void @test() #0 {
|
||||
entry:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpfeb -show-mc-encoding | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpfeb -show-mc-encoding | FileCheck %s
|
||||
; test big endian
|
||||
|
||||
define void @test() #0 {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpfel | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpfel | FileCheck %s
|
||||
|
||||
define void @test() #0 {
|
||||
entry:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
%struct.key_t = type { i32, [16 x i8] }
|
||||
|
||||
|
|
|
@ -52,14 +52,12 @@ declare i64 @llvm.bpf.load.word(i8*, i64) #1
|
|||
define i32 @ld_pseudo() #0 {
|
||||
entry:
|
||||
%call = tail call i64 @llvm.bpf.pseudo(i64 2, i64 3)
|
||||
tail call void @bar(i64 %call, i32 4) #2
|
||||
tail call void inttoptr (i64 4 to void (i64, i32)*)(i64 %call, i32 4) #2
|
||||
ret i32 0
|
||||
; CHECK-LABEL: ld_pseudo:
|
||||
; CHECK: ld_pseudo r1, 2, 3 # encoding: [0x18,0x21,0x00,0x00,0x03,0x00
|
||||
}
|
||||
|
||||
declare void @bar(i64, i32) #1
|
||||
|
||||
declare i64 @llvm.bpf.pseudo(i64, i64) #2
|
||||
|
||||
define i32 @bswap(i64 %a, i64 %b, i64 %c) #0 {
|
||||
|
|
|
@ -52,14 +52,12 @@ declare i64 @llvm.bpf.load.word(i8*, i64) #1
|
|||
define i32 @ld_pseudo() #0 {
|
||||
entry:
|
||||
%call = tail call i64 @llvm.bpf.pseudo(i64 2, i64 3)
|
||||
tail call void @bar(i64 %call, i32 4) #2
|
||||
tail call void inttoptr (i64 4 to void (i64, i32)*)(i64 %call, i32 4) #2
|
||||
ret i32 0
|
||||
; CHECK-LABEL: ld_pseudo:
|
||||
; CHECK: ld_pseudo r1, 2, 3
|
||||
}
|
||||
|
||||
declare void @bar(i64, i32) #1
|
||||
|
||||
declare i64 @llvm.bpf.pseudo(i64, i64) #2
|
||||
|
||||
define i32 @bswap(i64 %a, i64 %b, i64 %c) #0 {
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
; RUN: llc -march=bpfel -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s
|
||||
|
||||
; CHECK: if r2 s> r1 goto
|
||||
; CHECK: call
|
||||
; CHECK: call 1
|
||||
; CHECK: exit
|
||||
; CHECK: call 2
|
||||
; CHECK: exit
|
||||
|
||||
declare void @a()
|
||||
declare void @b()
|
||||
|
||||
define void @foo(i32 %a) {
|
||||
%b = icmp sgt i32 %a, -1
|
||||
br i1 %b, label %x, label %y
|
||||
x:
|
||||
call void @a()
|
||||
call void inttoptr (i64 1 to void ()*)()
|
||||
ret void
|
||||
y:
|
||||
call void @b()
|
||||
call void inttoptr (i64 2 to void ()*)()
|
||||
ret void
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpfel | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpfel | FileCheck %s
|
||||
|
||||
@foo_printf.fmt = private unnamed_addr constant [9 x i8] c"hello \0A\00", align 1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -march=bpf | FileCheck %s
|
||||
; RUN: not llc < %s -march=bpf | FileCheck %s
|
||||
|
||||
%struct.bpf_map_def = type { i32, i32, i32, i32 }
|
||||
%struct.__sk_buff = type opaque
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
; RUN: not llc -march=bpfel < %s 2>&1 >/dev/null | FileCheck %s
|
||||
|
||||
; CHECK: error: warn_call.c
|
||||
; CHECK: built-in function 'memcpy'
|
||||
; CHECK: error: warn_call.c
|
||||
; CHECK: global function 'foo'
|
||||
; CHECK: global function 'bar'
|
||||
define i8* @warn(i8* returned, i8*, i64) local_unnamed_addr #0 !dbg !6 {
|
||||
tail call void @llvm.dbg.value(metadata i8* %0, i64 0, metadata !14, metadata !17), !dbg !18
|
||||
tail call void @llvm.dbg.value(metadata i8* %1, i64 0, metadata !15, metadata !17), !dbg !19
|
||||
tail call void @llvm.dbg.value(metadata i64 %2, i64 0, metadata !16, metadata !17), !dbg !20
|
||||
tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 %2, i32 1, i1 false), !dbg !21
|
||||
%4 = tail call i8* @foo(i8* %0, i8* %1, i64 %2) #5, !dbg !22
|
||||
%5 = tail call fastcc i8* @bar(i8* %0), !dbg !23
|
||||
ret i8* %5, !dbg !24
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1
|
||||
|
||||
declare i8* @foo(i8*, i8*, i64) local_unnamed_addr #2
|
||||
|
||||
; Function Attrs: noinline nounwind readnone
|
||||
define internal fastcc i8* @bar(i8* readnone returned) unnamed_addr #3 !dbg !25 {
|
||||
tail call void @llvm.dbg.value(metadata i8* null, i64 0, metadata !28, metadata !17), !dbg !30
|
||||
tail call void @llvm.dbg.value(metadata i64 0, i64 0, metadata !29, metadata !17), !dbg !31
|
||||
ret i8* %0, !dbg !32
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #4
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4}
|
||||
!llvm.ident = !{!5}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 (trunk 292174) (llvm/trunk 292179)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "warn_call.c", directory: "/w/llvm/bld")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{!"clang version 5.0.0 (trunk 292174) (llvm/trunk 292179)"}
|
||||
!6 = distinct !DISubprogram(name: "warn", scope: !1, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !13)
|
||||
!7 = !DISubroutineType(types: !8)
|
||||
!8 = !{!9, !9, !10, !12}
|
||||
!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
|
||||
!11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null)
|
||||
!12 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned)
|
||||
!13 = !{!14, !15, !16}
|
||||
!14 = !DILocalVariable(name: "dst", arg: 1, scope: !6, file: !1, line: 4, type: !9)
|
||||
!15 = !DILocalVariable(name: "src", arg: 2, scope: !6, file: !1, line: 4, type: !10)
|
||||
!16 = !DILocalVariable(name: "len", arg: 3, scope: !6, file: !1, line: 4, type: !12)
|
||||
!17 = !DIExpression()
|
||||
!18 = !DILocation(line: 4, column: 18, scope: !6)
|
||||
!19 = !DILocation(line: 4, column: 35, scope: !6)
|
||||
!20 = !DILocation(line: 4, column: 54, scope: !6)
|
||||
!21 = !DILocation(line: 6, column: 2, scope: !6)
|
||||
!22 = !DILocation(line: 7, column: 2, scope: !6)
|
||||
!23 = !DILocation(line: 8, column: 9, scope: !6)
|
||||
!24 = !DILocation(line: 8, column: 2, scope: !6)
|
||||
!25 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 2, type: !7, isLocal: true, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !26)
|
||||
!26 = !{!27, !28, !29}
|
||||
!27 = !DILocalVariable(name: "dst", arg: 1, scope: !25, file: !1, line: 2, type: !9)
|
||||
!28 = !DILocalVariable(name: "src", arg: 2, scope: !25, file: !1, line: 2, type: !10)
|
||||
!29 = !DILocalVariable(name: "len", arg: 3, scope: !25, file: !1, line: 2, type: !12)
|
||||
!30 = !DILocation(line: 2, column: 67, scope: !25)
|
||||
!31 = !DILocation(line: 2, column: 86, scope: !25)
|
||||
!32 = !DILocation(line: 2, column: 93, scope: !25)
|
Loading…
Reference in New Issue