mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
UBSAN: emit distinctive traps
Sometimes people get minimal crash reports after a UBSAN incident. This change tags each trap with an integer representing the kind of failure encountered, which can aid in tracking down the root cause of the problem.
This commit is contained in:
parent
30acd5d783
commit
0fd5aa6df8
@ -19605,6 +19605,35 @@ This intrinsic is lowered to code which is intended to cause an
|
||||
execution trap with the intention of requesting the attention of a
|
||||
debugger.
|
||||
|
||||
'``llvm.ubsantrap``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
::
|
||||
|
||||
declare void @llvm.ubsantrap(i8 immarg) cold noreturn nounwind
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.ubsantrap``' intrinsic.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
An integer describing the kind of failure detected.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This intrinsic is lowered to code which is intended to cause an execution trap,
|
||||
embedding the argument into encoding of that trap somehow to discriminate
|
||||
crashes if possible.
|
||||
|
||||
Equivalent to ``@llvm.trap`` for targets that do not support this behaviour.
|
||||
|
||||
'``llvm.stackprotector``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -1012,6 +1012,9 @@ enum NodeType {
|
||||
/// DEBUGTRAP - Trap intended to get the attention of a debugger.
|
||||
DEBUGTRAP,
|
||||
|
||||
/// UBSANTRAP - Trap with an immediate describing the kind of sanitizer failure.
|
||||
UBSANTRAP,
|
||||
|
||||
/// PREFETCH - This corresponds to a prefetch intrinsic. The first operand
|
||||
/// is the chain. The other operands are the address to prefetch,
|
||||
/// read / write specifier, locality specifier and instruction / data cache
|
||||
|
@ -1255,6 +1255,8 @@ def int_trap : Intrinsic<[], [], [IntrNoReturn, IntrCold]>,
|
||||
GCCBuiltin<"__builtin_trap">;
|
||||
def int_debugtrap : Intrinsic<[]>,
|
||||
GCCBuiltin<"__builtin_debugtrap">;
|
||||
def int_ubsantrap : Intrinsic<[], [llvm_i8_ty],
|
||||
[IntrNoReturn, IntrCold, ImmArg<ArgIndex<0>>]>;
|
||||
|
||||
// Support for dynamic deoptimization (or de-specialization)
|
||||
def int_experimental_deoptimize : Intrinsic<[llvm_any_ty], [llvm_vararg_ty],
|
||||
|
@ -212,6 +212,8 @@ def SDTCatchret : SDTypeProfile<0, 2, [ // catchret
|
||||
|
||||
def SDTNone : SDTypeProfile<0, 0, []>; // ret, trap
|
||||
|
||||
def SDTUBSANTrap : SDTypeProfile<0, 1, []>; // ubsantrap
|
||||
|
||||
def SDTLoad : SDTypeProfile<1, 1, [ // load
|
||||
SDTCisPtrTy<1>
|
||||
]>;
|
||||
@ -575,6 +577,8 @@ def trap : SDNode<"ISD::TRAP" , SDTNone,
|
||||
[SDNPHasChain, SDNPSideEffect]>;
|
||||
def debugtrap : SDNode<"ISD::DEBUGTRAP" , SDTNone,
|
||||
[SDNPHasChain, SDNPSideEffect]>;
|
||||
def ubsantrap : SDNode<"ISD::UBSANTRAP" , SDTUBSANTrap,
|
||||
[SDNPHasChain, SDNPSideEffect]>;
|
||||
|
||||
def prefetch : SDNode<"ISD::PREFETCH" , SDTPrefetch,
|
||||
[SDNPHasChain, SDNPMayLoad, SDNPMayStore,
|
||||
|
@ -1107,6 +1107,18 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
|
||||
// They'll be converted to Copy(To/From)Reg.
|
||||
Action = TargetLowering::Legal;
|
||||
break;
|
||||
case ISD::UBSANTRAP:
|
||||
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));
|
||||
if (Action == TargetLowering::Expand) {
|
||||
// replace ISD::UBSANTRAP with ISD::TRAP
|
||||
SDValue NewVal;
|
||||
NewVal = DAG.getNode(ISD::TRAP, SDLoc(Node), Node->getVTList(),
|
||||
Node->getOperand(0));
|
||||
ReplaceNode(Node, NewVal.getNode());
|
||||
LegalizeOp(NewVal.getNode());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ISD::DEBUGTRAP:
|
||||
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));
|
||||
if (Action == TargetLowering::Expand) {
|
||||
|
@ -6481,6 +6481,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
|
||||
setValue(&I, getValue(I.getArgOperand(0)));
|
||||
return;
|
||||
|
||||
case Intrinsic::ubsantrap:
|
||||
case Intrinsic::debugtrap:
|
||||
case Intrinsic::trap: {
|
||||
StringRef TrapFuncName =
|
||||
@ -6488,12 +6489,31 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
|
||||
.getAttribute(AttributeList::FunctionIndex, "trap-func-name")
|
||||
.getValueAsString();
|
||||
if (TrapFuncName.empty()) {
|
||||
ISD::NodeType Op = (Intrinsic == Intrinsic::trap) ?
|
||||
ISD::TRAP : ISD::DEBUGTRAP;
|
||||
DAG.setRoot(DAG.getNode(Op, sdl,MVT::Other, getRoot()));
|
||||
switch (Intrinsic) {
|
||||
case Intrinsic::trap:
|
||||
DAG.setRoot(DAG.getNode(ISD::TRAP, sdl, MVT::Other, getRoot()));
|
||||
break;
|
||||
case Intrinsic::debugtrap:
|
||||
DAG.setRoot(DAG.getNode(ISD::DEBUGTRAP, sdl, MVT::Other, getRoot()));
|
||||
break;
|
||||
case Intrinsic::ubsantrap:
|
||||
DAG.setRoot(DAG.getNode(
|
||||
ISD::UBSANTRAP, sdl, MVT::Other, getRoot(),
|
||||
DAG.getTargetConstant(
|
||||
cast<ConstantInt>(I.getArgOperand(0))->getZExtValue(), sdl,
|
||||
MVT::i32)));
|
||||
break;
|
||||
default: llvm_unreachable("unknown trap intrinsic");
|
||||
}
|
||||
return;
|
||||
}
|
||||
TargetLowering::ArgListTy Args;
|
||||
if (Intrinsic == Intrinsic::ubsantrap) {
|
||||
Args.push_back(TargetLoweringBase::ArgListEntry());
|
||||
Args[0].Val = I.getArgOperand(0);
|
||||
Args[0].Node = getValue(Args[0].Val);
|
||||
Args[0].Ty = Args[0].Val->getType();
|
||||
}
|
||||
|
||||
TargetLowering::CallLoweringInfo CLI(DAG);
|
||||
CLI.setDebugLoc(sdl).setChain(getRoot()).setLibCallee(
|
||||
|
@ -394,6 +394,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
|
||||
case ISD::STACKRESTORE: return "stackrestore";
|
||||
case ISD::TRAP: return "trap";
|
||||
case ISD::DEBUGTRAP: return "debugtrap";
|
||||
case ISD::UBSANTRAP: return "ubsantrap";
|
||||
case ISD::LIFETIME_START: return "lifetime.start";
|
||||
case ISD::LIFETIME_END: return "lifetime.end";
|
||||
case ISD::PSEUDO_PROBE:
|
||||
|
@ -886,6 +886,8 @@ void TargetLoweringBase::initActions() {
|
||||
// On most systems, DEBUGTRAP and TRAP have no difference. The "Expand"
|
||||
// here is to inform DAG Legalizer to replace DEBUGTRAP with TRAP.
|
||||
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Expand);
|
||||
|
||||
setOperationAction(ISD::UBSANTRAP, MVT::Other, Expand);
|
||||
}
|
||||
|
||||
MVT TargetLoweringBase::getScalarShiftAmountTy(const DataLayout &DL,
|
||||
|
@ -816,6 +816,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
|
||||
// Trap.
|
||||
setOperationAction(ISD::TRAP, MVT::Other, Legal);
|
||||
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
|
||||
setOperationAction(ISD::UBSANTRAP, MVT::Other, Legal);
|
||||
|
||||
// We combine OR nodes for bitfield operations.
|
||||
setTargetDAGCombine(ISD::OR);
|
||||
|
@ -6685,6 +6685,16 @@ def : Pat<(i32 (trunc GPR64sp:$src)),
|
||||
def : Pat<(trap), (BRK 1)>;
|
||||
def : Pat<(debugtrap), (BRK 0xF000)>;
|
||||
|
||||
def ubsan_trap_xform : SDNodeXForm<timm, [{
|
||||
return CurDAG->getTargetConstant(N->getZExtValue() | ('U' << 8), SDLoc(N), MVT::i32);
|
||||
}]>;
|
||||
|
||||
def ubsan_trap_imm : TImmLeaf<i32, [{
|
||||
return isUInt<8>(Imm);
|
||||
}], ubsan_trap_xform>;
|
||||
|
||||
def : Pat<(ubsantrap ubsan_trap_imm:$kind), (BRK ubsan_trap_imm:$kind)>;
|
||||
|
||||
// Multiply high patterns which multiply the lower subvector using smull/umull
|
||||
// and the upper subvector with smull2/umull2. Then shuffle the high the high
|
||||
// part of both results together.
|
||||
|
@ -4832,6 +4832,10 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
|
||||
case Intrinsic::debugtrap:
|
||||
MIRBuilder.buildInstr(AArch64::BRK, {}, {}).addImm(0xF000);
|
||||
break;
|
||||
case Intrinsic::ubsantrap:
|
||||
MIRBuilder.buildInstr(AArch64::BRK, {}, {})
|
||||
.addImm(I.getOperand(0).getImm() | ('U' << 8));
|
||||
break;
|
||||
}
|
||||
|
||||
I.eraseFromParent();
|
||||
|
@ -494,6 +494,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
|
||||
|
||||
setOperationAction(ISD::TRAP, MVT::Other, Legal);
|
||||
setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
|
||||
setOperationAction(ISD::UBSANTRAP, MVT::Other, Legal);
|
||||
|
||||
// VASTART needs to be custom lowered to use the VarArgsFrameIndex
|
||||
setOperationAction(ISD::VASTART , MVT::Other, Custom);
|
||||
|
@ -49,6 +49,7 @@ let Uses = [EFLAGS] in
|
||||
def INT3 : I<0xcc, RawFrm, (outs), (ins), "int3", [(int_x86_int (i8 3))]>;
|
||||
} // SchedRW
|
||||
|
||||
def UBSAN_UD1 : PseudoI<(outs), (ins i32imm:$kind), [(ubsantrap (i32 timm:$kind))]>;
|
||||
// The long form of "int $3" turns into int3 as a size optimization.
|
||||
// FIXME: This doesn't work because InstAlias can't match immediate constants.
|
||||
//def : InstAlias<"int\t$3", (INT3)>;
|
||||
|
@ -2599,6 +2599,15 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case X86::UBSAN_UD1:
|
||||
EmitAndCountInstruction(MCInstBuilder(X86::UD1Lm)
|
||||
.addReg(X86::EAX)
|
||||
.addReg(X86::EAX)
|
||||
.addImm(1)
|
||||
.addReg(X86::NoRegister)
|
||||
.addImm(MI->getOperand(0).getImm())
|
||||
.addReg(X86::NoRegister));
|
||||
return;
|
||||
}
|
||||
|
||||
MCInst TmpInst;
|
||||
|
18
test/CodeGen/AArch64/ubsantrap.ll
Normal file
18
test/CodeGen/AArch64/ubsantrap.ll
Normal file
@ -0,0 +1,18 @@
|
||||
; RUN: llc -mtriple=arm64-apple-ios %s -o - | FileCheck %s
|
||||
|
||||
define void @test_ubsantrap() {
|
||||
; CHECK-LABEL: test_ubsantrap
|
||||
; CHECK: brk #0x550c
|
||||
call void @llvm.ubsantrap(i8 12)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_ubsantrap_function() {
|
||||
; CHECK-LABEL: test_ubsantrap_function:
|
||||
; CHECK: mov w0, #12
|
||||
; CHECK: bl _wibble
|
||||
call void @llvm.ubsantrap(i8 12) "trap-func-name"="wibble"
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.ubsantrap(i8)
|
18
test/CodeGen/X86/ubsantrap.ll
Normal file
18
test/CodeGen/X86/ubsantrap.ll
Normal file
@ -0,0 +1,18 @@
|
||||
; RUN: llc -mtriple=x86_64-linux-gnu %s -o - | FileCheck %s
|
||||
|
||||
define void @test_ubsantrap() {
|
||||
; CHECK-LABEL: test_ubsantrap
|
||||
; CHECK: ud1l 12(%eax), %eax
|
||||
call void @llvm.ubsantrap(i8 12)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test_ubsantrap_function() {
|
||||
; CHECK-LABEL: test_ubsantrap_function:
|
||||
; CHECK: movl $12, %edi
|
||||
; CHECK: callq wibble
|
||||
call void @llvm.ubsantrap(i8 12) "trap-func-name"="wibble"
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.ubsantrap(i8)
|
Loading…
Reference in New Issue
Block a user