1
0
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:
Tim Northover 2020-10-21 10:11:25 +01:00
parent 30acd5d783
commit 0fd5aa6df8
16 changed files with 138 additions and 3 deletions

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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

View File

@ -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],

View File

@ -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,

View File

@ -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) {

View File

@ -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(

View File

@ -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:

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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();

View File

@ -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);

View File

@ -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)>;

View File

@ -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;

View 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)

View 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)