diff --git a/contrib/llvm-project/FREEBSD-Xlist b/contrib/llvm-project/FREEBSD-Xlist index 4b581b177faf..5c1e8f837621 100644 --- a/contrib/llvm-project/FREEBSD-Xlist +++ b/contrib/llvm-project/FREEBSD-Xlist @@ -864,7 +864,8 @@ llvm/tools/llvm-dis/LLVMBuild.txt llvm/tools/llvm-dwarfdump/CMakeLists.txt llvm/tools/llvm-dwarfdump/LLVMBuild.txt llvm/tools/llvm-dwarfdump/fuzzer/ -llvm/tools/llvm-dwp/ +llvm/tools/llvm-dwp/CMakeLists.txt +llvm/tools/llvm-dwp/LLVMBuild.txt llvm/tools/llvm-elfabi/ llvm/tools/llvm-exegesis/ llvm/tools/llvm-extract/CMakeLists.txt @@ -911,12 +912,14 @@ llvm/tools/llvm-reduce/ llvm/tools/llvm-rtdyld/CMakeLists.txt llvm/tools/llvm-rtdyld/LLVMBuild.txt llvm/tools/llvm-shlib/ -llvm/tools/llvm-size/ +llvm/tools/llvm-size/CMakeLists.txt +llvm/tools/llvm-size/LLVMBuild.txt llvm/tools/llvm-special-case-list-fuzzer/ llvm/tools/llvm-split/ llvm/tools/llvm-stress/CMakeLists.txt llvm/tools/llvm-stress/LLVMBuild.txt -llvm/tools/llvm-strings/ +llvm/tools/llvm-strings/CMakeLists.txt +llvm/tools/llvm-strings/LLVMBuild.txt llvm/tools/llvm-symbolizer/CMakeLists.txt llvm/tools/llvm-undname/ llvm/tools/llvm-xray/CMakeLists.txt diff --git a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp index 370b14a337a5..12e17ac751b4 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp @@ -9677,7 +9677,8 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, uint64_t Size = getContext().getTypeSize(Ty); // Pass floating point values via FPRs if possible. - if (IsFixed && Ty->isFloatingType() && FLen >= Size && ArgFPRsLeft) { + if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() && + FLen >= Size && ArgFPRsLeft) { ArgFPRsLeft--; return ABIArgInfo::getDirect(); } diff --git a/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc new file mode 100644 index 000000000000..50951d5f4195 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc @@ -0,0 +1,31 @@ +//===-- int_mul_impl.inc - Integer multiplication -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helpers used by __mulsi3, __muldi3. +// +//===----------------------------------------------------------------------===// + +#if !defined(__riscv_mul) + .text + .align 2 + + .globl __mulxi3 + .type __mulxi3, @function +__mulxi3: + mv a2, a0 + mv a0, zero +.L1: + andi a3, a1, 1 + beqz a3, .L2 + add a0, a0, a2 +.L2: + srli a1, a1, 1 + slli a2, a2, 1 + bnez a1, .L1 + ret +#endif diff --git a/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S new file mode 100644 index 000000000000..9e292e8dd8b9 --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S @@ -0,0 +1,11 @@ +//===--- muldi3.S - Integer multiplication routines -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#if __riscv_xlen == 64 +#define __mulxi3 __muldi3 +#include "int_mul_impl.inc" +#endif diff --git a/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S index 5464919b26b9..cfafb7a0d7b3 100644 --- a/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S +++ b/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S @@ -1,4 +1,4 @@ -//===--- mulsi3.S - Integer multiplication routines routines ---===// +//===--- mulsi3.S - Integer multiplication routines -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,22 +6,7 @@ // //===----------------------------------------------------------------------===// -#if !defined(__riscv_mul) && __riscv_xlen == 32 - .text - .align 2 - - .globl __mulsi3 - .type __mulsi3, @function -__mulsi3: - mv a2, a0 - mv a0, zero -.L1: - andi a3, a1, 1 - beqz a3, .L2 - add a0, a0, a2 -.L2: - srli a1, a1, 1 - slli a2, a2, 1 - bnez a1, .L1 - ret +#if __riscv_xlen == 32 +#define __mulxi3 __mulsi3 +#include "int_mul_impl.inc" #endif diff --git a/contrib/llvm-project/libcxx/include/array b/contrib/llvm-project/libcxx/include/array index 88e9d57ff783..ddebf9159600 100644 --- a/contrib/llvm-project/libcxx/include/array +++ b/contrib/llvm-project/libcxx/include/array @@ -359,7 +359,7 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0> #ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES template && ...), void>::type + class = _EnableIf<__all<_IsSame<_Tp, _Args>::value...>::value> > array(_Tp, _Args...) -> array<_Tp, 1 + sizeof...(_Args)>; diff --git a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 6aed5796acc6..015b3d99fb0f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -271,8 +271,20 @@ SDValue DAGTypeLegalizer::PromoteIntRes_AtomicCmpSwap(AtomicSDNode *N, return Res.getValue(1); } - SDValue Op2 = GetPromotedInteger(N->getOperand(2)); + // Op2 is used for the comparison and thus must be extended according to the + // target's atomic operations. Op3 is merely stored and so can be left alone. + SDValue Op2 = N->getOperand(2); SDValue Op3 = GetPromotedInteger(N->getOperand(3)); + if (TLI.getTargetMachine().getTargetTriple().isRISCV()) { + // The comparison argument must be sign-extended for RISC-V. This is + // abstracted using a new TargetLowering hook in the main LLVM development + // branch, but handled here directly in order to fix the codegen bug for + // 10.x without breaking the libLLVM.so ABI. + Op2 = SExtPromotedInteger(Op2); + } else { + Op2 = GetPromotedInteger(Op2); + } + SDVTList VTs = DAG.getVTList(Op2.getValueType(), N->getValueType(1), MVT::Other); SDValue Res = DAG.getAtomicCmpSwap( diff --git a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 24ab65171a17..368e2100031f 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5490,9 +5490,20 @@ char TargetLowering::isNegatibleForFree(SDValue Op, SelectionDAG &DAG, EVT VT = Op.getValueType(); const SDNodeFlags Flags = Op->getFlags(); const TargetOptions &Options = DAG.getTarget().Options; - if (!Op.hasOneUse() && !(Op.getOpcode() == ISD::FP_EXTEND && - isFPExtFree(VT, Op.getOperand(0).getValueType()))) - return 0; + if (!Op.hasOneUse()) { + bool IsFreeExtend = Op.getOpcode() == ISD::FP_EXTEND && + isFPExtFree(VT, Op.getOperand(0).getValueType()); + + // If we already have the use of the negated floating constant, it is free + // to negate it even it has multiple uses. + bool IsFreeConstant = + Op.getOpcode() == ISD::ConstantFP && + !getNegatedExpression(Op, DAG, LegalOperations, ForCodeSize) + .use_empty(); + + if (!IsFreeExtend && !IsFreeConstant) + return 0; + } // Don't recurse exponentially. if (Depth > SelectionDAG::MaxRecursionDepth) @@ -5687,14 +5698,7 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG, ForCodeSize, Depth + 1); char V1 = isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); - // TODO: This is a hack. It is possible that costs have changed between now - // and the initial calls to isNegatibleForFree(). That is because we - // are rewriting the expression, and that may change the number of - // uses (and therefore the cost) of values. If the negation costs are - // equal, only negate this value if it is a constant. Otherwise, try - // operand 1. A better fix would eliminate uses as a cost factor or - // track the change in uses as we rewrite the expression. - if (V0 > V1 || (V0 == V1 && isa(Op.getOperand(0)))) { + if (V0 > V1) { // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) SDValue Neg0 = getNegatedExpression( Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); diff --git a/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index ea3e800a1ad2..651ad9ad4c83 100644 --- a/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -211,6 +211,24 @@ AArch64FrameLowering::getStackIDForScalableVectors() const { return TargetStackID::SVEVector; } +/// Returns the size of the fixed object area (allocated next to sp on entry) +/// On Win64 this may include a var args area and an UnwindHelp object for EH. +static unsigned getFixedObjectSize(const MachineFunction &MF, + const AArch64FunctionInfo *AFI, bool IsWin64, + bool IsFunclet) { + if (!IsWin64 || IsFunclet) { + // Only Win64 uses fixed objects, and then only for the function (not + // funclets) + return 0; + } else { + // Var args are stored here in the primary function. + const unsigned VarArgsArea = AFI->getVarArgsGPRSize(); + // To support EH funclets we allocate an UnwindHelp object + const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 8 : 0); + return alignTo(VarArgsArea + UnwindHelpObject, 16); + } +} + /// Returns the size of the entire SVE stackframe (calleesaves + spills). static StackOffset getSVEStackSize(const MachineFunction &MF) { const AArch64FunctionInfo *AFI = MF.getInfo(); @@ -959,10 +977,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - // Var args are accounted for in the containing function, so don't - // include them for funclets. - unsigned FixedObject = (IsWin64 && !IsFunclet) ? - alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; // All of the remaining stack allocations are for locals. @@ -993,32 +1008,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, ++MBBI; } - // The code below is not applicable to funclets. We have emitted all the SEH - // opcodes that we needed to emit. The FP and BP belong to the containing - // function. - if (IsFunclet) { - if (NeedsWinCFI) { - HasWinCFI = true; - BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd)) - .setMIFlag(MachineInstr::FrameSetup); - } - - // SEH funclets are passed the frame pointer in X1. If the parent - // function uses the base register, then the base register is used - // directly, and is not retrieved from X1. - if (F.hasPersonalityFn()) { - EHPersonality Per = classifyEHPersonality(F.getPersonalityFn()); - if (isAsynchronousEHPersonality(Per)) { - BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP) - .addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup); - MBB.addLiveIn(AArch64::X1); - } - } - - return; - } - - if (HasFP) { + // For funclets the FP belongs to the containing function. + if (!IsFunclet && HasFP) { // Only set up FP if we actually need to. int64_t FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0; @@ -1161,7 +1152,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, // Allocate space for the rest of the frame. if (NumBytes) { - const bool NeedsRealignment = RegInfo->needsStackRealignment(MF); + // Alignment is required for the parent frame, not the funclet + const bool NeedsRealignment = + !IsFunclet && RegInfo->needsStackRealignment(MF); unsigned scratchSPReg = AArch64::SP; if (NeedsRealignment) { @@ -1215,7 +1208,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, // FIXME: Clarify FrameSetup flags here. // Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is // needed. - if (RegInfo->hasBasePointer(MF)) { + // For funclets the BP belongs to the containing function. + if (!IsFunclet && RegInfo->hasBasePointer(MF)) { TII->copyPhysReg(MBB, MBBI, DL, RegInfo->getBaseRegister(), AArch64::SP, false); if (NeedsWinCFI) { @@ -1232,6 +1226,19 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, .setMIFlag(MachineInstr::FrameSetup); } + // SEH funclets are passed the frame pointer in X1. If the parent + // function uses the base register, then the base register is used + // directly, and is not retrieved from X1. + if (IsFunclet && F.hasPersonalityFn()) { + EHPersonality Per = classifyEHPersonality(F.getPersonalityFn()); + if (isAsynchronousEHPersonality(Per)) { + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP) + .addReg(AArch64::X1) + .setMIFlag(MachineInstr::FrameSetup); + MBB.addLiveIn(AArch64::X1); + } + } + if (needsFrameMoves) { const DataLayout &TD = MF.getDataLayout(); const int StackGrowth = isTargetDarwin(MF) @@ -1450,10 +1457,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF, bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - // Var args are accounted for in the containing function, so don't - // include them for funclets. - unsigned FixedObject = - (IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); uint64_t AfterCSRPopSize = ArgumentPopSize; auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; @@ -1679,7 +1683,9 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset) const auto &Subtarget = MF.getSubtarget(); bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + + unsigned FixedObject = + getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false); unsigned FPAdjust = isTargetDarwin(MF) ? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo()); return {ObjectOffset + FixedObject + FPAdjust, MVT::i8}; @@ -2632,9 +2638,14 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized( ++MBBI; // Create an UnwindHelp object. - int UnwindHelpFI = - MFI.CreateStackObject(/*size*/8, /*alignment*/16, false); + // The UnwindHelp object is allocated at the start of the fixed object area + int64_t FixedObject = + getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false); + int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8, + /*SPOffset*/ -FixedObject, + /*IsImmutable=*/false); EHInfo.UnwindHelpFrameIdx = UnwindHelpFI; + // We need to store -2 into the UnwindHelp object at the start of the // function. DebugLoc DL; @@ -2656,10 +2667,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP( const MachineFunction &MF, int FI, unsigned &FrameReg, bool IgnoreSPUpdates) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); - LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " - << MFI.getObjectOffset(FI) << "\n"); - FrameReg = AArch64::SP; - return MFI.getObjectOffset(FI); + if (IgnoreSPUpdates) { + LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " + << MFI.getObjectOffset(FI) << "\n"); + FrameReg = AArch64::SP; + return MFI.getObjectOffset(FI); + } + + return getFrameIndexReference(MF, FI, FrameReg); } /// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 4311df5dbeb8..20c5ac7b378a 100644 --- a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -298,6 +298,11 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, switch (ExtraCode[0]) { default: return true; // Unknown modifier. + case 'L': // A memory reference to the upper word of a double word op. + O << getDataLayout().getPointerSize() << "("; + printOperand(MI, OpNo, O); + O << ")"; + return false; case 'y': // A memory reference for an X-form instruction { const char *RegName = "r0"; @@ -309,7 +314,6 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, } case 'U': // Print 'u' for update form. case 'X': // Print 'x' for indexed form. - { // FIXME: Currently for PowerPC memory operands are always loaded // into a register, so we never get an update or indexed form. // This is bad even for offset forms, since even if we know we @@ -319,7 +323,6 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, assert(MI->getOperand(OpNo).isReg()); return false; } - } } assert(MI->getOperand(OpNo).isReg()); diff --git a/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index c60fc3fc6b42..f7cd19cbb8e7 100644 --- a/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -181,9 +181,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); - // Emit ".cfi_def_cfa $fp, 0" + // Emit ".cfi_def_cfa $fp, -RVFI->getVarArgsSaveSize()" unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( - nullptr, RI->getDwarfRegNum(FPReg, true), 0)); + nullptr, RI->getDwarfRegNum(FPReg, true), -RVFI->getVarArgsSaveSize())); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } diff --git a/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 5a2cffbc824c..a1e3e326a97a 100644 --- a/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -197,6 +197,14 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setTruncStoreAction(MVT::f64, MVT::f16, Expand); } + if (Subtarget.is64Bit() && + !(Subtarget.hasStdExtD() || Subtarget.hasStdExtF())) { + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom); + } + setOperationAction(ISD::GlobalAddress, XLenVT, Custom); setOperationAction(ISD::BlockAddress, XLenVT, Custom); setOperationAction(ISD::ConstantPool, XLenVT, Custom); @@ -876,6 +884,32 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, switch (N->getOpcode()) { default: llvm_unreachable("Don't know how to custom type legalize this operation!"); + case ISD::STRICT_FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: { + bool IsStrict = N->isStrictFPOpcode(); + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue Op0 = IsStrict ? N->getOperand(1) : N->getOperand(0); + RTLIB::Libcall LC; + if (N->getOpcode() == ISD::FP_TO_SINT || + N->getOpcode() == ISD::STRICT_FP_TO_SINT) + LC = RTLIB::getFPTOSINT(Op0.getValueType(), N->getValueType(0)); + else + LC = RTLIB::getFPTOUINT(Op0.getValueType(), N->getValueType(0)); + MakeLibCallOptions CallOptions; + EVT OpVT = Op0.getValueType(); + CallOptions.setTypeListBeforeSoften(OpVT, N->getValueType(0), true); + SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); + SDValue Result; + std::tie(Result, Chain) = + makeLibCall(DAG, LC, N->getValueType(0), Op0, CallOptions, DL, Chain); + Results.push_back(Result); + if (IsStrict) + Results.push_back(Chain); + break; + } case ISD::READCYCLECOUNTER: { assert(!Subtarget.is64Bit() && "READCYCLECOUNTER only has custom type legalization on riscv32"); diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp new file mode 100644 index 000000000000..21d53ed6d198 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp @@ -0,0 +1,3 @@ +#include "DWPError.h" +using namespace llvm; +char DWPError::ID; diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h new file mode 100644 index 000000000000..62025ed4caa5 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h @@ -0,0 +1,23 @@ +#ifndef TOOLS_LLVM_DWP_DWPERROR +#define TOOLS_LLVM_DWP_DWPERROR + +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace llvm { +class DWPError : public ErrorInfo { +public: + DWPError(std::string Info) : Info(std::move(Info)) {} + void log(raw_ostream &OS) const override { OS << Info; } + std::error_code convertToErrorCode() const override { + llvm_unreachable("Not implemented"); + } + static char ID; + +private: + std::string Info; +}; +} + +#endif diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h new file mode 100644 index 000000000000..7d41176b5619 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h @@ -0,0 +1,56 @@ +#ifndef TOOLS_LLVM_DWP_DWPSTRINGPOOL +#define TOOLS_LLVM_DWP_DWPSTRINGPOOL + +#include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include + +namespace llvm { +class DWPStringPool { + + struct CStrDenseMapInfo { + static inline const char *getEmptyKey() { + return reinterpret_cast(~static_cast(0)); + } + static inline const char *getTombstoneKey() { + return reinterpret_cast(~static_cast(1)); + } + static unsigned getHashValue(const char *Val) { + assert(Val != getEmptyKey() && "Cannot hash the empty key!"); + assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!"); + return (unsigned)hash_value(StringRef(Val)); + } + static bool isEqual(const char *LHS, const char *RHS) { + if (RHS == getEmptyKey()) + return LHS == getEmptyKey(); + if (RHS == getTombstoneKey()) + return LHS == getTombstoneKey(); + return strcmp(LHS, RHS) == 0; + } + }; + + MCStreamer &Out; + MCSection *Sec; + DenseMap Pool; + uint32_t Offset = 0; + +public: + DWPStringPool(MCStreamer &Out, MCSection *Sec) : Out(Out), Sec(Sec) {} + + uint32_t getOffset(const char *Str, unsigned Length) { + assert(strlen(Str) + 1 == Length && "Ensure length hint is correct"); + + auto Pair = Pool.insert(std::make_pair(Str, Offset)); + if (Pair.second) { + Out.SwitchSection(Sec); + Out.EmitBytes(StringRef(Str, Length)); + Offset += Length; + } + + return Pair.first->second; + } +}; +} + +#endif diff --git a/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp b/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp new file mode 100644 index 000000000000..23513ef8fb4e --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -0,0 +1,749 @@ +//===-- llvm-dwp.cpp - Split DWARF merging tool for llvm ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A utility for merging DWARF 5 Split DWARF .dwo files into .dwp (DWARF +// package files). +// +//===----------------------------------------------------------------------===// +#include "DWPError.h" +#include "DWPStringPool.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.inc" +#include "llvm/Object/Decompressor.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; + +cl::OptionCategory DwpCategory("Specific Options"); +static cl::list InputFiles(cl::Positional, cl::ZeroOrMore, + cl::desc(""), + cl::cat(DwpCategory)); + +static cl::list ExecFilenames( + "e", cl::ZeroOrMore, + cl::desc("Specify the executable/library files to get the list of *.dwo from"), + cl::value_desc("filename"), cl::cat(DwpCategory)); + +static cl::opt OutputFilename(cl::Required, "o", + cl::desc("Specify the output file."), + cl::value_desc("filename"), + cl::cat(DwpCategory)); + +static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings, + MCSection *StrOffsetSection, + StringRef CurStrSection, + StringRef CurStrOffsetSection) { + // Could possibly produce an error or warning if one of these was non-null but + // the other was null. + if (CurStrSection.empty() || CurStrOffsetSection.empty()) + return; + + DenseMap OffsetRemapping; + + DataExtractor Data(CurStrSection, true, 0); + uint64_t LocalOffset = 0; + uint64_t PrevOffset = 0; + while (const char *s = Data.getCStr(&LocalOffset)) { + OffsetRemapping[PrevOffset] = + Strings.getOffset(s, LocalOffset - PrevOffset); + PrevOffset = LocalOffset; + } + + Data = DataExtractor(CurStrOffsetSection, true, 0); + + Out.SwitchSection(StrOffsetSection); + + uint64_t Offset = 0; + uint64_t Size = CurStrOffsetSection.size(); + while (Offset < Size) { + auto OldOffset = Data.getU32(&Offset); + auto NewOffset = OffsetRemapping[OldOffset]; + Out.EmitIntValue(NewOffset, 4); + } +} + +static uint64_t getCUAbbrev(StringRef Abbrev, uint64_t AbbrCode) { + uint64_t CurCode; + uint64_t Offset = 0; + DataExtractor AbbrevData(Abbrev, true, 0); + while ((CurCode = AbbrevData.getULEB128(&Offset)) != AbbrCode) { + // Tag + AbbrevData.getULEB128(&Offset); + // DW_CHILDREN + AbbrevData.getU8(&Offset); + // Attributes + while (AbbrevData.getULEB128(&Offset) | AbbrevData.getULEB128(&Offset)) + ; + } + return Offset; +} + +struct CompileUnitIdentifiers { + uint64_t Signature = 0; + const char *Name = ""; + const char *DWOName = ""; +}; + +static Expected +getIndexedString(dwarf::Form Form, DataExtractor InfoData, + uint64_t &InfoOffset, StringRef StrOffsets, StringRef Str) { + if (Form == dwarf::DW_FORM_string) + return InfoData.getCStr(&InfoOffset); + if (Form != dwarf::DW_FORM_GNU_str_index) + return make_error( + "string field encoded without DW_FORM_string or DW_FORM_GNU_str_index"); + auto StrIndex = InfoData.getULEB128(&InfoOffset); + DataExtractor StrOffsetsData(StrOffsets, true, 0); + uint64_t StrOffsetsOffset = 4 * StrIndex; + uint64_t StrOffset = StrOffsetsData.getU32(&StrOffsetsOffset); + DataExtractor StrData(Str, true, 0); + return StrData.getCStr(&StrOffset); +} + +static Expected getCUIdentifiers(StringRef Abbrev, + StringRef Info, + StringRef StrOffsets, + StringRef Str) { + uint64_t Offset = 0; + DataExtractor InfoData(Info, true, 0); + dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32; + uint64_t Length = InfoData.getU32(&Offset); + // If the length is 0xffffffff, then this indictes that this is a DWARF 64 + // stream and the length is actually encoded into a 64 bit value that follows. + if (Length == 0xffffffffU) { + Format = dwarf::DwarfFormat::DWARF64; + Length = InfoData.getU64(&Offset); + } + uint16_t Version = InfoData.getU16(&Offset); + InfoData.getU32(&Offset); // Abbrev offset (should be zero) + uint8_t AddrSize = InfoData.getU8(&Offset); + + uint32_t AbbrCode = InfoData.getULEB128(&Offset); + + DataExtractor AbbrevData(Abbrev, true, 0); + uint64_t AbbrevOffset = getCUAbbrev(Abbrev, AbbrCode); + auto Tag = static_cast(AbbrevData.getULEB128(&AbbrevOffset)); + if (Tag != dwarf::DW_TAG_compile_unit) + return make_error("top level DIE is not a compile unit"); + // DW_CHILDREN + AbbrevData.getU8(&AbbrevOffset); + uint32_t Name; + dwarf::Form Form; + CompileUnitIdentifiers ID; + Optional Signature = None; + while ((Name = AbbrevData.getULEB128(&AbbrevOffset)) | + (Form = static_cast(AbbrevData.getULEB128(&AbbrevOffset))) && + (Name != 0 || Form != 0)) { + switch (Name) { + case dwarf::DW_AT_name: { + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.Name = *EName; + break; + } + case dwarf::DW_AT_GNU_dwo_name: { + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.DWOName = *EName; + break; + } + case dwarf::DW_AT_GNU_dwo_id: + Signature = InfoData.getU64(&Offset); + break; + default: + DWARFFormValue::skipValue(Form, InfoData, &Offset, + dwarf::FormParams({Version, AddrSize, Format})); + } + } + if (!Signature) + return make_error("compile unit missing dwo_id"); + ID.Signature = *Signature; + return ID; +} + +struct UnitIndexEntry { + DWARFUnitIndex::Entry::SectionContribution Contributions[8]; + std::string Name; + std::string DWOName; + StringRef DWPName; +}; + +static StringRef getSubsection(StringRef Section, + const DWARFUnitIndex::Entry &Entry, + DWARFSectionKind Kind) { + const auto *Off = Entry.getOffset(Kind); + if (!Off) + return StringRef(); + return Section.substr(Off->Offset, Off->Length); +} + +static void addAllTypesFromDWP( + MCStreamer &Out, MapVector &TypeIndexEntries, + const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, + const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) { + Out.SwitchSection(OutputTypes); + for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { + auto *I = E.getOffsets(); + if (!I) + continue; + auto P = TypeIndexEntries.insert(std::make_pair(E.getSignature(), TUEntry)); + if (!P.second) + continue; + auto &Entry = P.first->second; + // Zero out the debug_info contribution + Entry.Contributions[0] = {}; + for (auto Kind : TUIndex.getColumnKinds()) { + auto &C = Entry.Contributions[Kind - DW_SECT_INFO]; + C.Offset += I->Offset; + C.Length = I->Length; + ++I; + } + auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; + Out.EmitBytes(Types.substr( + C.Offset - TUEntry.Contributions[DW_SECT_TYPES - DW_SECT_INFO].Offset, + C.Length)); + C.Offset = TypesOffset; + TypesOffset += C.Length; + } +} + +static void addAllTypes(MCStreamer &Out, + MapVector &TypeIndexEntries, + MCSection *OutputTypes, + const std::vector &TypesSections, + const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { + for (StringRef Types : TypesSections) { + Out.SwitchSection(OutputTypes); + uint64_t Offset = 0; + DataExtractor Data(Types, true, 0); + while (Data.isValidOffset(Offset)) { + UnitIndexEntry Entry = CUEntry; + // Zero out the debug_info contribution + Entry.Contributions[0] = {}; + auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; + C.Offset = TypesOffset; + auto PrevOffset = Offset; + // Length of the unit, including the 4 byte length field. + C.Length = Data.getU32(&Offset) + 4; + + Data.getU16(&Offset); // Version + Data.getU32(&Offset); // Abbrev offset + Data.getU8(&Offset); // Address size + auto Signature = Data.getU64(&Offset); + Offset = PrevOffset + C.Length; + + auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); + if (!P.second) + continue; + + Out.EmitBytes(Types.substr(PrevOffset, C.Length)); + TypesOffset += C.Length; + } + } +} + +static void +writeIndexTable(MCStreamer &Out, ArrayRef ContributionOffsets, + const MapVector &IndexEntries, + uint32_t DWARFUnitIndex::Entry::SectionContribution::*Field) { + for (const auto &E : IndexEntries) + for (size_t i = 0; i != array_lengthof(E.second.Contributions); ++i) + if (ContributionOffsets[i]) + Out.EmitIntValue(E.second.Contributions[i].*Field, 4); +} + +static void +writeIndex(MCStreamer &Out, MCSection *Section, + ArrayRef ContributionOffsets, + const MapVector &IndexEntries) { + if (IndexEntries.empty()) + return; + + unsigned Columns = 0; + for (auto &C : ContributionOffsets) + if (C) + ++Columns; + + std::vector Buckets(NextPowerOf2(3 * IndexEntries.size() / 2)); + uint64_t Mask = Buckets.size() - 1; + size_t i = 0; + for (const auto &P : IndexEntries) { + auto S = P.first; + auto H = S & Mask; + auto HP = ((S >> 32) & Mask) | 1; + while (Buckets[H]) { + assert(S != IndexEntries.begin()[Buckets[H] - 1].first && + "Duplicate unit"); + H = (H + HP) & Mask; + } + Buckets[H] = i + 1; + ++i; + } + + Out.SwitchSection(Section); + Out.EmitIntValue(2, 4); // Version + Out.EmitIntValue(Columns, 4); // Columns + Out.EmitIntValue(IndexEntries.size(), 4); // Num Units + Out.EmitIntValue(Buckets.size(), 4); // Num Buckets + + // Write the signatures. + for (const auto &I : Buckets) + Out.EmitIntValue(I ? IndexEntries.begin()[I - 1].first : 0, 8); + + // Write the indexes. + for (const auto &I : Buckets) + Out.EmitIntValue(I, 4); + + // Write the column headers (which sections will appear in the table) + for (size_t i = 0; i != ContributionOffsets.size(); ++i) + if (ContributionOffsets[i]) + Out.EmitIntValue(i + DW_SECT_INFO, 4); + + // Write the offsets. + writeIndexTable(Out, ContributionOffsets, IndexEntries, + &DWARFUnitIndex::Entry::SectionContribution::Offset); + + // Write the lengths. + writeIndexTable(Out, ContributionOffsets, IndexEntries, + &DWARFUnitIndex::Entry::SectionContribution::Length); +} + +std::string buildDWODescription(StringRef Name, StringRef DWPName, StringRef DWOName) { + std::string Text = "\'"; + Text += Name; + Text += '\''; + if (!DWPName.empty()) { + Text += " (from "; + if (!DWOName.empty()) { + Text += '\''; + Text += DWOName; + Text += "' in "; + } + Text += '\''; + Text += DWPName; + Text += "')"; + } + return Text; +} + +static Error createError(StringRef Name, Error E) { + return make_error( + ("failure while decompressing compressed section: '" + Name + "', " + + llvm::toString(std::move(E))) + .str()); +} + +static Error +handleCompressedSection(std::deque> &UncompressedSections, + StringRef &Name, StringRef &Contents) { + if (!Decompressor::isGnuStyle(Name)) + return Error::success(); + + Expected Dec = + Decompressor::create(Name, Contents, false /*IsLE*/, false /*Is64Bit*/); + if (!Dec) + return createError(Name, Dec.takeError()); + + UncompressedSections.emplace_back(); + if (Error E = Dec->resizeAndDecompress(UncompressedSections.back())) + return createError(Name, std::move(E)); + + Name = Name.substr(2); // Drop ".z" + Contents = UncompressedSections.back(); + return Error::success(); +} + +static Error handleSection( + const StringMap> &KnownSections, + const MCSection *StrSection, const MCSection *StrOffsetSection, + const MCSection *TypesSection, const MCSection *CUIndexSection, + const MCSection *TUIndexSection, const SectionRef &Section, MCStreamer &Out, + std::deque> &UncompressedSections, + uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry, + StringRef &CurStrSection, StringRef &CurStrOffsetSection, + std::vector &CurTypesSection, StringRef &InfoSection, + StringRef &AbbrevSection, StringRef &CurCUIndexSection, + StringRef &CurTUIndexSection) { + if (Section.isBSS()) + return Error::success(); + + if (Section.isVirtual()) + return Error::success(); + + Expected NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = *NameOrErr; + + Expected ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + StringRef Contents = *ContentsOrErr; + + if (auto Err = handleCompressedSection(UncompressedSections, Name, Contents)) + return Err; + + Name = Name.substr(Name.find_first_not_of("._")); + + auto SectionPair = KnownSections.find(Name); + if (SectionPair == KnownSections.end()) + return Error::success(); + + if (DWARFSectionKind Kind = SectionPair->second.second) { + auto Index = Kind - DW_SECT_INFO; + if (Kind != DW_SECT_TYPES) { + CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; + ContributionOffsets[Index] += + (CurEntry.Contributions[Index].Length = Contents.size()); + } + + switch (Kind) { + case DW_SECT_INFO: + InfoSection = Contents; + break; + case DW_SECT_ABBREV: + AbbrevSection = Contents; + break; + default: + break; + } + } + + MCSection *OutSection = SectionPair->second.first; + if (OutSection == StrOffsetSection) + CurStrOffsetSection = Contents; + else if (OutSection == StrSection) + CurStrSection = Contents; + else if (OutSection == TypesSection) + CurTypesSection.push_back(Contents); + else if (OutSection == CUIndexSection) + CurCUIndexSection = Contents; + else if (OutSection == TUIndexSection) + CurTUIndexSection = Contents; + else { + Out.SwitchSection(OutSection); + Out.EmitBytes(Contents); + } + return Error::success(); +} + +static Error +buildDuplicateError(const std::pair &PrevE, + const CompileUnitIdentifiers &ID, StringRef DWPName) { + return make_error( + std::string("Duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " + + buildDWODescription(PrevE.second.Name, PrevE.second.DWPName, + PrevE.second.DWOName) + + " and " + buildDWODescription(ID.Name, DWPName, ID.DWOName)); +} + +static Expected> +getDWOFilenames(StringRef ExecFilename) { + auto ErrOrObj = object::ObjectFile::createObjectFile(ExecFilename); + if (!ErrOrObj) + return ErrOrObj.takeError(); + + const ObjectFile &Obj = *ErrOrObj.get().getBinary(); + std::unique_ptr DWARFCtx = DWARFContext::create(Obj); + + SmallVector DWOPaths; + for (const auto &CU : DWARFCtx->compile_units()) { + const DWARFDie &Die = CU->getUnitDIE(); + std::string DWOName = dwarf::toString( + Die.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); + if (DWOName.empty()) + continue; + std::string DWOCompDir = + dwarf::toString(Die.find(dwarf::DW_AT_comp_dir), ""); + if (!DWOCompDir.empty()) { + SmallString<16> DWOPath; + sys::path::append(DWOPath, DWOCompDir, DWOName); + DWOPaths.emplace_back(DWOPath.data(), DWOPath.size()); + } else { + DWOPaths.push_back(std::move(DWOName)); + } + } + return std::move(DWOPaths); +} + +static Error write(MCStreamer &Out, ArrayRef Inputs) { + const auto &MCOFI = *Out.getContext().getObjectFileInfo(); + MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); + MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); + MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); + MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); + MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); + const StringMap> KnownSections = { + {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, + {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, + {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, + {"debug_str.dwo", {StrSection, static_cast(0)}}, + {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, + {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, + {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, + {"debug_cu_index", {CUIndexSection, static_cast(0)}}, + {"debug_tu_index", {TUIndexSection, static_cast(0)}}}; + + MapVector IndexEntries; + MapVector TypeIndexEntries; + + uint32_t ContributionOffsets[8] = {}; + + DWPStringPool Strings(Out, StrSection); + + SmallVector, 128> Objects; + Objects.reserve(Inputs.size()); + + std::deque> UncompressedSections; + + for (const auto &Input : Inputs) { + auto ErrOrObj = object::ObjectFile::createObjectFile(Input); + if (!ErrOrObj) + return ErrOrObj.takeError(); + + auto &Obj = *ErrOrObj->getBinary(); + Objects.push_back(std::move(*ErrOrObj)); + + UnitIndexEntry CurEntry = {}; + + StringRef CurStrSection; + StringRef CurStrOffsetSection; + std::vector CurTypesSection; + StringRef InfoSection; + StringRef AbbrevSection; + StringRef CurCUIndexSection; + StringRef CurTUIndexSection; + + for (const auto &Section : Obj.sections()) + if (auto Err = handleSection( + KnownSections, StrSection, StrOffsetSection, TypesSection, + CUIndexSection, TUIndexSection, Section, Out, + UncompressedSections, ContributionOffsets, CurEntry, + CurStrSection, CurStrOffsetSection, CurTypesSection, InfoSection, + AbbrevSection, CurCUIndexSection, CurTUIndexSection)) + return Err; + + if (InfoSection.empty()) + continue; + + writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, + CurStrOffsetSection); + + if (CurCUIndexSection.empty()) { + Expected EID = getCUIdentifiers( + AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); + if (!EID) + return createFileError(Input, EID.takeError()); + const auto &ID = *EID; + auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); + if (!P.second) + return buildDuplicateError(*P.first, ID, ""); + P.first->second.Name = ID.Name; + P.first->second.DWOName = ID.DWOName; + addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, + CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + continue; + } + + DWARFUnitIndex CUIndex(DW_SECT_INFO); + DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); + if (!CUIndex.parse(CUIndexData)) + return make_error("Failed to parse cu_index"); + + for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { + auto *I = E.getOffsets(); + if (!I) + continue; + auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); + Expected EID = getCUIdentifiers( + getSubsection(AbbrevSection, E, DW_SECT_ABBREV), + getSubsection(InfoSection, E, DW_SECT_INFO), + getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), + CurStrSection); + if (!EID) + return createFileError(Input, EID.takeError()); + const auto &ID = *EID; + if (!P.second) + return buildDuplicateError(*P.first, ID, Input); + auto &NewEntry = P.first->second; + NewEntry.Name = ID.Name; + NewEntry.DWOName = ID.DWOName; + NewEntry.DWPName = Input; + for (auto Kind : CUIndex.getColumnKinds()) { + auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; + C.Offset += I->Offset; + C.Length = I->Length; + ++I; + } + } + + if (!CurTypesSection.empty()) { + if (CurTypesSection.size() != 1) + return make_error("multiple type unit sections in .dwp file"); + DWARFUnitIndex TUIndex(DW_SECT_TYPES); + DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); + if (!TUIndex.parse(TUIndexData)) + return make_error("Failed to parse tu_index"); + addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, + CurTypesSection.front(), CurEntry, + ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + } + } + + // Lie about there being no info contributions so the TU index only includes + // the type unit contribution + ContributionOffsets[0] = 0; + writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, + TypeIndexEntries); + + // Lie about the type contribution + ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0; + // Unlie about the info contribution + ContributionOffsets[0] = 1; + + writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, + IndexEntries); + + return Error::success(); +} + +static int error(const Twine &Error, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("error: ") + Error + "\n"; + return 1; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "merge split dwarf (.dwo) files\n"); + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + + std::string ErrorStr; + StringRef Context = "dwarf streamer init"; + + Triple TheTriple("x86_64-linux-gnu"); + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget("", TheTriple, ErrorStr); + if (!TheTarget) + return error(ErrorStr, Context); + std::string TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return error(Twine("no register info for target ") + TripleName, Context); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); + if (!MAI) + return error("no asm info for target " + TripleName, Context); + + MCObjectFileInfo MOFI; + MCContext MC(MAI.get(), MRI.get(), &MOFI); + MOFI.InitMCObjectFileInfo(TheTriple, /*PIC*/ false, MC); + + std::unique_ptr MSTI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return error("no subtarget info for target " + TripleName, Context); + + MCTargetOptions Options; + auto MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, Options); + if (!MAB) + return error("no asm backend for target " + TripleName, Context); + + std::unique_ptr MII(TheTarget->createMCInstrInfo()); + if (!MII) + return error("no instr info info for target " + TripleName, Context); + + MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, MC); + if (!MCE) + return error("no code emitter for target " + TripleName, Context); + + // Create the output file. + std::error_code EC; + ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None); + Optional BOS; + raw_pwrite_stream *OS; + if (EC) + return error(Twine(OutputFilename) + ": " + EC.message(), Context); + if (OutFile.os().supportsSeeking()) { + OS = &OutFile.os(); + } else { + BOS.emplace(OutFile.os()); + OS = BOS.getPointer(); + } + + std::unique_ptr MS(TheTarget->createMCObjectStreamer( + TheTriple, MC, std::unique_ptr(MAB), + MAB->createObjectWriter(*OS), std::unique_ptr(MCE), *MSTI, + MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false)); + if (!MS) + return error("no object streamer for target " + TripleName, Context); + + std::vector DWOFilenames = InputFiles; + for (const auto &ExecFilename : ExecFilenames) { + auto DWOs = getDWOFilenames(ExecFilename); + if (!DWOs) { + logAllUnhandledErrors(DWOs.takeError(), WithColor::error()); + return 1; + } + DWOFilenames.insert(DWOFilenames.end(), + std::make_move_iterator(DWOs->begin()), + std::make_move_iterator(DWOs->end())); + } + + if (auto Err = write(*MS, DWOFilenames)) { + logAllUnhandledErrors(std::move(Err), WithColor::error()); + return 1; + } + + MS->Finish(); + OutFile.keep(); + return 0; +} diff --git a/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp new file mode 100644 index 000000000000..46ece5a6f0c9 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp @@ -0,0 +1,894 @@ +//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like traditional Unix "size", +// that is, it prints out the size of each section, and the total size of all +// sections. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; +using namespace object; + +cl::OptionCategory SizeCat("llvm-size Options"); + +enum OutputFormatTy { berkeley, sysv, darwin }; +static cl::opt + OutputFormat("format", cl::desc("Specify output format"), + cl::values(clEnumVal(sysv, "System V format"), + clEnumVal(berkeley, "Berkeley format"), + clEnumVal(darwin, "Darwin -m format")), + cl::init(berkeley), cl::cat(SizeCat)); + +static cl::opt + OutputFormatShort(cl::desc("Specify output format"), + cl::values(clEnumValN(sysv, "A", "System V format"), + clEnumValN(berkeley, "B", "Berkeley format"), + clEnumValN(darwin, "m", "Darwin -m format")), + cl::init(berkeley), cl::cat(SizeCat)); + +static bool BerkeleyHeaderPrinted = false; +static bool MoreThanOneFile = false; +static uint64_t TotalObjectText = 0; +static uint64_t TotalObjectData = 0; +static uint64_t TotalObjectBss = 0; +static uint64_t TotalObjectTotal = 0; + +cl::opt + DarwinLongFormat("l", + cl::desc("When format is darwin, use long format " + "to include addresses and offsets."), + cl::cat(SizeCat)); + +cl::opt + ELFCommons("common", + cl::desc("Print common symbols in the ELF file. When using " + "Berkeley format, this is added to bss."), + cl::init(false), cl::cat(SizeCat)); + +static cl::list + ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore, cl::cat(SizeCat)); +static bool ArchAll = false; + +enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; +static cl::opt Radix( + "radix", cl::desc("Print size in radix"), cl::init(decimal), + cl::values(clEnumValN(octal, "8", "Print size in octal"), + clEnumValN(decimal, "10", "Print size in decimal"), + clEnumValN(hexadecimal, "16", "Print size in hexadecimal")), + cl::cat(SizeCat)); + +static cl::opt RadixShort( + cl::desc("Print size in radix:"), + cl::values(clEnumValN(octal, "o", "Print size in octal"), + clEnumValN(decimal, "d", "Print size in decimal"), + clEnumValN(hexadecimal, "x", "Print size in hexadecimal")), + cl::init(decimal), cl::cat(SizeCat)); + +static cl::opt + TotalSizes("totals", + cl::desc("Print totals of all objects - Berkeley format only"), + cl::init(false), cl::cat(SizeCat)); + +static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"), + cl::aliasopt(TotalSizes)); + +static cl::list + InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); + +static cl::extrahelp + HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); + +static bool HadError = false; + +static std::string ToolName; + +static void error(const Twine &Message, StringRef File) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; +} + +// This version of error() prints the archive name and member name, for example: +// "libx.a(foo.o)" after the ToolName before the error message. It sets +// HadError but returns allowing the code to move on to other archive members. +static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, + StringRef ArchitectureName = StringRef()) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << FileName << "'"; + + Expected NameOrErr = C.getName(); + // TODO: if we have a error getting the name then it would be nice to print + // the index of which archive member this is and or its offset in the + // archive instead of "???" as the name. + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + errs() << "(" << "???" << ")"; + } else + errs() << "(" << NameOrErr.get() << ")"; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS); + OS.flush(); + errs() << ": " << Buf << "\n"; +} + +// This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName +// before the error message. It sets HadError but returns allowing the code to +// move on to other architecture slices. +static void error(llvm::Error E, StringRef FileName, + StringRef ArchitectureName = StringRef()) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << FileName << "'"; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS); + OS.flush(); + errs() << ": " << Buf << "\n"; +} + +/// Get the length of the string that represents @p num in Radix including the +/// leading 0x or 0 for hexadecimal and octal respectively. +static size_t getNumLengthAsString(uint64_t num) { + APInt conv(64, num); + SmallString<32> result; + conv.toString(result, Radix, false, true); + return result.size(); +} + +/// Return the printing format for the Radix. +static const char *getRadixFmt() { + switch (Radix) { + case octal: + return PRIo64; + case decimal: + return PRIu64; + case hexadecimal: + return PRIx64; + } + return nullptr; +} + +/// Remove unneeded ELF sections from calculation +static bool considerForSize(ObjectFile *Obj, SectionRef Section) { + if (!Obj->isELF()) + return true; + switch (static_cast(Section).getType()) { + case ELF::SHT_NULL: + case ELF::SHT_SYMTAB: + case ELF::SHT_STRTAB: + case ELF::SHT_REL: + case ELF::SHT_RELA: + return false; + } + return true; +} + +/// Total size of all ELF common symbols +static uint64_t getCommonSize(ObjectFile *Obj) { + uint64_t TotalCommons = 0; + for (auto &Sym : Obj->symbols()) + if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common) + TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); + return TotalCommons; +} + +/// Print the size of each Mach-O segment and section in @p MachO. +/// +/// This is when used when @c OutputFormat is darwin and produces the same +/// output as darwin's size(1) -m output. +static void printDarwinSectionSizes(MachOObjectFile *MachO) { + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + if (Radix == hexadecimal) + fmt << "0x"; + fmt << "%" << radix_fmt; + + uint32_t Filetype = MachO->getHeader().filetype; + + uint64_t total = 0; + for (const auto &Load : MachO->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg.vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + outs() << format(fmt.str().c_str(), Sec.size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + uint64_t Seg_vmsize = Seg.vmsize; + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg_vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + uint64_t Sec_size = Sec.size; + outs() << format(fmt.str().c_str(), Sec_size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } + } + outs() << "total " << format(fmt.str().c_str(), total) << "\n"; +} + +/// Print the summary sizes of the standard Mach-O segments in @p MachO. +/// +/// This is when used when @c OutputFormat is berkeley with a Mach-O file and +/// produces the same output as darwin's size(1) default output. +static void printDarwinSegmentSizes(MachOObjectFile *MachO) { + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_objc = 0; + uint64_t total_others = 0; + for (const auto &Load : MachO->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } + } + uint64_t total = total_text + total_data + total_objc + total_others; + + if (!BerkeleyHeaderPrinted) { + outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; + BerkeleyHeaderPrinted = true; + } + outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" + << total_others << "\t" << total << "\t" << format("%" PRIx64, total) + << "\t"; +} + +/// Print the size of each section in @p Obj. +/// +/// The format used is determined by @c OutputFormat and @c Radix. +static void printObjectSectionSizes(ObjectFile *Obj) { + uint64_t total = 0; + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // let it fall through to OutputFormat berkeley. + MachOObjectFile *MachO = dyn_cast(Obj); + if (OutputFormat == darwin && MachO) + printDarwinSectionSizes(MachO); + // If we have a MachOObjectFile and the OutputFormat is berkeley print as + // darwin's default berkeley format for Mach-O files. + else if (MachO && OutputFormat == berkeley) + printDarwinSegmentSizes(MachO); + else if (OutputFormat == sysv) { + // Run two passes over all sections. The first gets the lengths needed for + // formatting the output. The second actually does the output. + std::size_t max_name_len = strlen("section"); + std::size_t max_size_len = strlen("size"); + std::size_t max_addr_len = strlen("addr"); + for (const SectionRef &Section : Obj->sections()) { + if (!considerForSize(Obj, Section)) + continue; + uint64_t size = Section.getSize(); + total += size; + + Expected name_or_err = Section.getName(); + if (!name_or_err) { + error(name_or_err.takeError(), Obj->getFileName()); + return; + } + + uint64_t addr = Section.getAddress(); + max_name_len = std::max(max_name_len, name_or_err->size()); + max_size_len = std::max(max_size_len, getNumLengthAsString(size)); + max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); + } + + // Add extra padding. + max_name_len += 2; + max_size_len += 2; + max_addr_len += 2; + + // Setup header format. + fmt << "%-" << max_name_len << "s " + << "%" << max_size_len << "s " + << "%" << max_addr_len << "s\n"; + + // Print header + outs() << format(fmt.str().c_str(), static_cast("section"), + static_cast("size"), + static_cast("addr")); + fmtbuf.clear(); + + // Setup per section format. + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << " " + << "%#" << max_addr_len << radix_fmt << "\n"; + + // Print each section. + for (const SectionRef &Section : Obj->sections()) { + if (!considerForSize(Obj, Section)) + continue; + + Expected name_or_err = Section.getName(); + if (!name_or_err) { + error(name_or_err.takeError(), Obj->getFileName()); + return; + } + + uint64_t size = Section.getSize(); + uint64_t addr = Section.getAddress(); + outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); + } + + if (ELFCommons) { + uint64_t CommonSize = getCommonSize(Obj); + total += CommonSize; + outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), + CommonSize, static_cast(0)); + } + + // Print total. + fmtbuf.clear(); + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << "\n"; + outs() << format(fmt.str().c_str(), static_cast("Total"), + total) + << "\n\n"; + } else { + // The Berkeley format does not display individual section sizes. It + // displays the cumulative size for each section type. + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_bss = 0; + + // Make one pass over the section table to calculate sizes. + for (const SectionRef &Section : Obj->sections()) { + uint64_t size = Section.getSize(); + bool isText = Section.isBerkeleyText(); + bool isData = Section.isBerkeleyData(); + bool isBSS = Section.isBSS(); + if (isText) + total_text += size; + else if (isData) + total_data += size; + else if (isBSS) + total_bss += size; + } + + if (ELFCommons) + total_bss += getCommonSize(Obj); + + total = total_text + total_data + total_bss; + + if (TotalSizes) { + TotalObjectText += total_text; + TotalObjectData += total_data; + TotalObjectBss += total_bss; + TotalObjectTotal += total; + } + + if (!BerkeleyHeaderPrinted) { + outs() << " text\t" + " data\t" + " bss\t" + " " + << (Radix == octal ? "oct" : "dec") + << "\t" + " hex\t" + "filename\n"; + BerkeleyHeaderPrinted = true; + } + + // Print result. + fmt << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t"; + outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); + fmtbuf.clear(); + fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" + << "%7" PRIx64 "\t"; + outs() << format(fmt.str().c_str(), total, total); + } +} + +/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there +/// is a list of architecture flags specified then check to make sure this +/// Mach-O file is one of those architectures or all architectures was +/// specificed. If not then an error is generated and this routine returns +/// false. Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { + auto *MachO = dyn_cast(O); + + if (!MachO || ArchAll || ArchFlags.empty()) + return true; + + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); + } + if (none_of(ArchFlags, [&](const std::string &Name) { + return Name == T.getArchName(); + })) { + error("no architecture specified", Filename); + return false; + } + return true; +} + +/// Print the section sizes for @p file. If @p file is an archive, print the +/// section sizes for each archive member. +static void printFileSectionSizes(StringRef file) { + + // Attempt to open the binary. + Expected> BinaryOrErr = createBinary(file); + if (!BinaryOrErr) { + error(BinaryOrErr.takeError(), file); + return; + } + Binary &Bin = *BinaryOrErr.get().getBinary(); + + if (Archive *a = dyn_cast(&Bin)) { + // This is an archive. Iterate over each member and display its sizes. + Error Err = Error::success(); + for (auto &C : a->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + error(std::move(E), a->getFileName(), C); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (!checkMachOAndArchFlags(o, file)) + return; + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; + else + outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; + } + } + } + if (Err) + error(std::move(Err), a->getFileName()); + } else if (MachOUniversalBinary *UB = + dyn_cast(&Bin)) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && !ArchFlags.empty()) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchFlagName()) { + ArchFound = true; + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "): \n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType( + UO.takeError())) { + error(std::move(E), file, ArchFlags.size() > 1 ? + StringRef(I->getArchFlagName()) : StringRef()); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its + // sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, + ArchFlags.size() > 1 ? + StringRef(I->getArchFlagName()) : StringRef()); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")" + << " (for architecture " << I->getArchFlagName() + << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) { + outs() << UA->getFileName() << "(" << o->getFileName() + << ")"; + if (ArchFlags.size() > 1) + outs() << " (for architecture " << I->getArchFlagName() + << ")"; + outs() << "\n"; + } else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + } + } + if (!ArchFound) { + error("file does not contain architecture " + ArchFlags[i], file); + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchFlagName()) { + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "):\n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its + // sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() + << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool MoreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile || MoreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "):"; + outs() << "\n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile || MoreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file, MoreThanOneArch ? + StringRef(I->getArchFlagName()) : StringRef()); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? + StringRef(I->getArchFlagName()) : StringRef()); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + } + } else if (ObjectFile *o = dyn_cast(&Bin)) { + if (!checkMachOAndArchFlags(o, file)) + return; + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin && MoreThanOneFile) + outs() << o->getFileName() << ":\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile) + outs() << o->getFileName(); + outs() << "\n"; + } + } else { + error("unsupported file type", file); + } +} + +static void printBerkeleyTotals() { + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + fmt << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t"; + outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, + TotalObjectBss); + fmtbuf.clear(); + fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" + << "%7" PRIx64 "\t"; + outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) + << "(TOTALS)\n"; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::HideUnrelatedOptions(SizeCat); + cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); + + ToolName = argv[0]; + if (OutputFormatShort.getNumOccurrences()) + OutputFormat = static_cast(OutputFormatShort); + if (RadixShort.getNumOccurrences()) + Radix = RadixShort.getValue(); + + for (StringRef Arch : ArchFlags) { + if (Arch == "all") { + ArchAll = true; + } else { + if (!MachOObjectFile::isValidArch(Arch)) { + outs() << ToolName << ": for the -arch option: Unknown architecture " + << "named '" << Arch << "'"; + return 1; + } + } + } + + if (InputFilenames.empty()) + InputFilenames.push_back("a.out"); + + MoreThanOneFile = InputFilenames.size() > 1; + llvm::for_each(InputFilenames, printFileSectionSizes); + if (OutputFormat == berkeley && TotalSizes) + printBerkeleyTotals(); + + if (HadError) + return 1; +} diff --git a/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp b/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp new file mode 100644 index 000000000000..51313d73401e --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp @@ -0,0 +1,120 @@ +//===-- llvm-strings.cpp - Printable String dumping utility ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like binutils "strings", that is, it +// prints out printable strings in a binary, objdump, or archive file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Binary.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" +#include +#include + +using namespace llvm; +using namespace llvm::object; + +static cl::list InputFileNames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); + +static cl::opt + PrintFileName("print-file-name", + cl::desc("Print the name of the file before each string")); +static cl::alias PrintFileNameShort("f", cl::desc(""), + cl::aliasopt(PrintFileName)); + +static cl::opt + MinLength("bytes", cl::desc("Print sequences of the specified length"), + cl::init(4)); +static cl::alias MinLengthShort("n", cl::desc(""), cl::aliasopt(MinLength)); + +static cl::opt + AllSections("all", + cl::desc("Check all sections, not just the data section")); +static cl::alias AllSectionsShort("a", cl::desc(""), + cl::aliasopt(AllSections)); + +enum radix { none, octal, hexadecimal, decimal }; +static cl::opt + Radix("radix", cl::desc("print the offset within the file"), + cl::values(clEnumValN(octal, "o", "octal"), + clEnumValN(hexadecimal, "x", "hexadecimal"), + clEnumValN(decimal, "d", "decimal")), + cl::init(none)); +static cl::alias RadixShort("t", cl::desc(""), cl::aliasopt(Radix)); + +static cl::extrahelp + HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); + +static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) { + auto print = [&OS, FileName](unsigned Offset, StringRef L) { + if (L.size() < static_cast(MinLength)) + return; + if (PrintFileName) + OS << FileName << ": "; + switch (Radix) { + case none: + break; + case octal: + OS << format("%7o ", Offset); + break; + case hexadecimal: + OS << format("%7x ", Offset); + break; + case decimal: + OS << format("%7u ", Offset); + break; + } + OS << L << '\n'; + }; + + const char *B = Contents.begin(); + const char *P = nullptr, *E = nullptr, *S = nullptr; + for (P = Contents.begin(), E = Contents.end(); P < E; ++P) { + if (isPrint(*P) || *P == '\t') { + if (S == nullptr) + S = P; + } else if (S) { + print(S - B, StringRef(S, P - S)); + S = nullptr; + } + } + if (S) + print(S - B, StringRef(S, E - S)); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "llvm string dumper\n"); + if (MinLength == 0) { + errs() << "invalid minimum string length 0\n"; + return EXIT_FAILURE; + } + + if (InputFileNames.empty()) + InputFileNames.push_back("-"); + + for (const auto &File : InputFileNames) { + ErrorOr> Buffer = + MemoryBuffer::getFileOrSTDIN(File); + if (std::error_code EC = Buffer.getError()) + errs() << File << ": " << EC.message() << '\n'; + else + strings(llvm::outs(), File == "-" ? "{standard input}" : File, + Buffer.get()->getMemBufferRef().getBuffer()); + } + + return EXIT_SUCCESS; +} diff --git a/lib/clang/include/VCSVersion.inc b/lib/clang/include/VCSVersion.inc index 733a51913377..e175e797bf3e 100644 --- a/lib/clang/include/VCSVersion.inc +++ b/lib/clang/include/VCSVersion.inc @@ -1,14 +1,14 @@ // $FreeBSD$ -#define LLVM_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLVM_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git" -#define CLANG_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define CLANG_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define CLANG_REPOSITORY "git@github.com:llvm/llvm-project.git" // - -#define LLD_REVISION "llvmorg-10.0.0-129-gd24d5c8e308-1300007" +#define LLD_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d-1300007" #define LLD_REPOSITORY "FreeBSD" -#define LLDB_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLDB_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLDB_REPOSITORY "git@github.com:llvm/llvm-project.git" diff --git a/lib/clang/include/llvm/Support/VCSRevision.h b/lib/clang/include/llvm/Support/VCSRevision.h index 32e0fcf01995..9f084aa4a801 100644 --- a/lib/clang/include/llvm/Support/VCSRevision.h +++ b/lib/clang/include/llvm/Support/VCSRevision.h @@ -1,3 +1,3 @@ /* $FreeBSD$ */ -#define LLVM_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLVM_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git" diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 28e17cc6ff5b..5d12d34dcdcd 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -1493,6 +1493,7 @@ OLD_FILES+=usr/bin/llvm-cxxfilt OLD_FILES+=usr/bin/llvm-diff OLD_FILES+=usr/bin/llvm-dis OLD_FILES+=usr/bin/llvm-dwarfdump +OLD_FILES+=usr/bin/llvm-dwp OLD_FILES+=usr/bin/llvm-extract OLD_FILES+=usr/bin/llvm-link OLD_FILES+=usr/bin/llvm-lto @@ -1503,6 +1504,8 @@ OLD_FILES+=usr/bin/llvm-modextract OLD_FILES+=usr/bin/llvm-objcopy OLD_FILES+=usr/bin/llvm-pdbutil OLD_FILES+=usr/bin/llvm-rtdyld +OLD_FILES+=usr/bin/llvm-size +OLD_FILES+=usr/bin/llvm-strings OLD_FILES+=usr/bin/llvm-xray OLD_FILES+=usr/bin/opt OLD_FILES+=usr/share/man/man1/bugpoint.1.gz @@ -1518,6 +1521,8 @@ OLD_FILES+=usr/share/man/man1/llvm-extract.1.gz OLD_FILES+=usr/share/man/man1/llvm-link.1.gz OLD_FILES+=usr/share/man/man1/llvm-objcopy.1.gz OLD_FILES+=usr/share/man/man1/llvm-pdbutil.1.gz +OLD_FILES+=usr/share/man/man1/llvm-size.1.gz +OLD_FILES+=usr/share/man/man1/llvm-strings.1.gz OLD_FILES+=usr/share/man/man1/opt.1.gz .endif @@ -2078,6 +2083,7 @@ OLD_FILES+=usr/share/man/man1/gcov.1.gz OLD_FILES+=usr/bin/llvm-cov OLD_FILES+=usr/bin/llvm-profdata OLD_FILES+=usr/share/man/man1/llvm-cov.1.gz +OLD_FILES+=usr/share/man/man1/llvm-profdata.1.gz .endif .if ${MK_GDB} == no diff --git a/usr.bin/clang/Makefile b/usr.bin/clang/Makefile index 5ac0607338e3..68b3c1537d90 100644 --- a/usr.bin/clang/Makefile +++ b/usr.bin/clang/Makefile @@ -27,6 +27,7 @@ SUBDIR+= llvm-cxxfilt SUBDIR+= llvm-diff SUBDIR+= llvm-dis SUBDIR+= llvm-dwarfdump +SUBDIR+= llvm-dwp SUBDIR+= llvm-extract SUBDIR+= llvm-link SUBDIR+= llvm-lto @@ -37,6 +38,8 @@ SUBDIR+= llvm-modextract SUBDIR+= llvm-objcopy SUBDIR+= llvm-pdbutil SUBDIR+= llvm-rtdyld +SUBDIR+= llvm-size +SUBDIR+= llvm-strings SUBDIR+= llvm-xray SUBDIR+= opt .endif diff --git a/usr.bin/clang/llvm-dwp/Makefile b/usr.bin/clang/llvm-dwp/Makefile new file mode 100644 index 000000000000..a9d5d4f94e84 --- /dev/null +++ b/usr.bin/clang/llvm-dwp/Makefile @@ -0,0 +1,12 @@ +# $FreeBSD$ + +PROG_CXX= llvm-dwp +MAN= + +SRCDIR= llvm/tools/llvm-dwp +SRCS+= DWPError.cpp +SRCS+= llvm-dwp.cpp + +LIBADD+= z + +.include "../llvm.prog.mk" diff --git a/usr.bin/clang/llvm-size/Makefile b/usr.bin/clang/llvm-size/Makefile new file mode 100644 index 000000000000..a4a387aabf6f --- /dev/null +++ b/usr.bin/clang/llvm-size/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG_CXX= llvm-size + +SRCDIR= llvm/tools/llvm-size +SRCS+= llvm-size.cpp + +.include "../llvm.prog.mk" diff --git a/usr.bin/clang/llvm-size/llvm-size.1 b/usr.bin/clang/llvm-size/llvm-size.1 new file mode 100644 index 000000000000..b89fbea69765 --- /dev/null +++ b/usr.bin/clang/llvm-size/llvm-size.1 @@ -0,0 +1,275 @@ +.\" $FreeBSD$ +.\" Man page generated from reStructuredText. +. +.TH "LLVM-SIZE" "1" "2020-06-26" "10" "LLVM" +.SH NAME +llvm-size \- print size information +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.SH SYNOPSIS +.sp +\fBllvm\-size\fP [\fIoptions\fP] [\fIinput...\fP] +.SH DESCRIPTION +.sp +\fBllvm\-size\fP is a tool that prints size information for binary files. +It is intended to be a drop\-in replacement for GNU\(aqs \fBsize\fP\&. +.sp +The tool prints size information for each \fBinput\fP specified. If no input is +specified, the program prints size information for \fBa.out\fP\&. If "\fB\-\fP" is +specified as an input file, \fBllvm\-size\fP reads a file from the standard +input stream. If an input is an archive, size information will be displayed for +all its members. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-A +Equivalent to \fI\%\-\-format\fP with a value of \fBsysv\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-arch= +Architecture(s) from Mach\-O universal binaries to display information for. +.UNINDENT +.INDENT 0.0 +.TP +.B \-B +Equivalent to \fI\%\-\-format\fP with a value of \fBberkeley\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-common +Include ELF common symbol sizes in bss size for \fBberkeley\fP output format, or +as a separate section entry for \fBsysv\fP output. If not specified, these +symbols are ignored. +.UNINDENT +.INDENT 0.0 +.TP +.B \-d +Equivalent to \fI\%\-\-radix\fP with a value of \fB10\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-l +Display verbose address and offset information for segments and sections in +Mach\-O files in \fBdarwin\fP format. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-format= +Set the output format to the \fB\fP specified. Available \fB\fP +options are \fBberkeley\fP (the default), \fBsysv\fP and \fBdarwin\fP\&. +.sp +Berkeley output summarises text, data and bss sizes in each file, as shown +below for a typical pair of ELF files: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=berkeley test.o test2.o + text data bss dec hex filename + 182 16 5 203 cb test.elf + 82 8 1 91 5b test2.o +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +For Mach\-O files, the output format is slightly different: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=berkeley macho.obj macho2.obj +__TEXT __DATA __OBJC others dec hex +4 8 0 0 12 c macho.obj +16 32 0 0 48 30 macho2.obj +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Sysv output displays size and address information for most sections, with each +file being listed separately: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=sysv test.elf test2.o + test.elf : + section size addr + .eh_frame 92 2097496 + .text 90 2101248 + .data 16 2105344 + .bss 5 2105360 + .comment 209 0 + Total 412 + + test2.o : + section size addr + .text 26 0 + .data 8 0 + .bss 1 0 + .comment 106 0 + .note.GNU\-stack 0 0 + .eh_frame 56 0 + .llvm_addrsig 2 0 + Total 199 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBdarwin\fP format only affects Mach\-O input files. If an input of a different +file format is specified, \fBllvm\-size\fP falls back to \fBberkeley\fP +format. When producing \fBdarwin\fP format, the tool displays information about +segments and sections: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=darwin macho.obj macho2.obj + macho.obj: + Segment : 12 + Section (__TEXT, __text): 4 + Section (__DATA, __data): 8 + total 12 + total 12 + macho2.obj: + Segment : 48 + Section (__TEXT, __text): 16 + Section (__DATA, __data): 32 + total 48 + total 48 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help, \-h +Display a summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help\-list +Display an uncategorized summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-m +Equivalent to \fI\%\-\-format\fP with a value of \fBdarwin\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-o +Equivalent to \fI\%\-\-radix\fP with a value of \fB8\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-radix= +Display size information in the specified radix. Permitted values are \fB8\fP, +\fB10\fP (the default) and \fB16\fP for octal, decimal and hexadecimal output +respectively. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-radix=8 test.o + text data bss oct hex filename + 0152 04 04 162 72 test.o + +$ llvm\-size \-\-radix=10 test.o + text data bss dec hex filename + 106 4 4 114 72 test.o + +$ llvm\-size \-\-radix=16 test.o + text data bss dec hex filename + 0x6a 0x4 0x4 114 72 test.o +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-totals, \-t +Applies only to \fBberkeley\fP output format. Display the totals for all listed +fields, in addition to the individual file listings. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-totals test.elf test2.o + text data bss dec hex filename + 182 16 5 203 cb test.elf + 82 8 1 91 5b test2.o + 264 24 6 294 126 (TOTALS) +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-version +Display the version of the \fBllvm\-size\fP executable. +.UNINDENT +.INDENT 0.0 +.TP +.B \-x +Equivalent to \fI\%\-\-radix\fP with a value of \fB16\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B @ +Read command\-line options from response file \fB\fP\&. +.UNINDENT +.SH EXIT STATUS +.sp +\fBllvm\-size\fP exits with a non\-zero exit code if there is an error. +Otherwise, it exits with code 0. +.SH BUGS +.sp +To report bugs, please visit <\fI\%http://llvm.org/bugs/\fP>. +.SH AUTHOR +Maintained by the LLVM Team (https://llvm.org/). +.SH COPYRIGHT +2003-2020, LLVM Project +.\" Generated by docutils manpage writer. +. diff --git a/usr.bin/clang/llvm-strings/Makefile b/usr.bin/clang/llvm-strings/Makefile new file mode 100644 index 000000000000..bb5f28867d38 --- /dev/null +++ b/usr.bin/clang/llvm-strings/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG_CXX= llvm-strings +MAN= + +SRCDIR= llvm/tools/llvm-strings +SRCS+= llvm-strings.cpp + +.include "../llvm.prog.mk" diff --git a/usr.bin/clang/llvm-strings/llvm-strings.1 b/usr.bin/clang/llvm-strings/llvm-strings.1 new file mode 100644 index 000000000000..27e5f6e49648 --- /dev/null +++ b/usr.bin/clang/llvm-strings/llvm-strings.1 @@ -0,0 +1,179 @@ +.\" $FreeBSD$ +.\" Man page generated from reStructuredText. +. +.TH "LLVM-STRINGS" "1" "2020-06-26" "10" "LLVM" +.SH NAME +llvm-strings \- print strings +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.SH SYNOPSIS +.sp +\fBllvm\-strings\fP [\fIoptions\fP] [\fIinput...\fP] +.SH DESCRIPTION +.sp +\fBllvm\-strings\fP is a tool intended as a drop\-in replacement for GNU\(aqs +\fBstrings\fP, which looks for printable strings in files and writes them +to the standard output stream. A printable string is any sequence of four (by +default) or more printable ASCII characters. The end of the file, or any other +byte, terminates the current sequence. +.sp +\fBllvm\-strings\fP looks for strings in each \fBinput\fP file specified. +Unlike GNU \fBstrings\fP it looks in the entire input file, regardless of +file format, rather than restricting the search to certain sections of object +files. If "\fB\-\fP" is specified as an \fBinput\fP, or no \fBinput\fP is specified, +the program reads from the standard input stream. +.SH EXAMPLE +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ cat input.txt +bars +foo +wibble blob +$ llvm\-strings input.txt +bars +wibble blob +.ft P +.fi +.UNINDENT +.UNINDENT +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-\-all, \-a +Silently ignored. Present for GNU \fBstrings\fP compatibility. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-bytes=, \-n +Set the minimum number of printable ASCII characters required for a sequence of +bytes to be considered a string. The default value is 4. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help, \-h +Display a summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help\-list +Display an uncategorized summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-print\-file\-name, \-f +Display the name of the containing file before each string. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-strings \-\-print\-file\-name test.o test.elf +test.o: _Z5hellov +test.o: some_bss +test.o: test.cpp +test.o: main +test.elf: test.cpp +test.elf: test2.cpp +test.elf: _Z5hellov +test.elf: main +test.elf: some_bss +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-radix=, \-t +Display the offset within the file of each string, before the string and using +the specified radix. Valid \fB\fP values are \fBo\fP, \fBd\fP and \fBx\fP for +octal, decimal and hexadecimal respectively. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-strings \-\-radix=o test.o + 1054 _Z5hellov + 1066 .rela.text + 1101 .comment + 1112 some_bss + 1123 .bss + 1130 test.cpp + 1141 main +$ llvm\-strings \-\-radix=d test.o + 556 _Z5hellov + 566 .rela.text + 577 .comment + 586 some_bss + 595 .bss + 600 test.cpp + 609 main +$ llvm\-strings \-t x test.o + 22c _Z5hellov + 236 .rela.text + 241 .comment + 24a some_bss + 253 .bss + 258 test.cpp + 261 main +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-version +Display the version of the \fBllvm\-strings\fP executable. +.UNINDENT +.INDENT 0.0 +.TP +.B @ +Read command\-line options from response file \fB\fP\&. +.UNINDENT +.SH EXIT STATUS +.sp +\fBllvm\-strings\fP exits with a non\-zero exit code if there is an error. +Otherwise, it exits with code 0. +.SH BUGS +.sp +To report bugs, please visit <\fI\%http://llvm.org/bugs/\fP>. +.SH AUTHOR +Maintained by the LLVM Team (https://llvm.org/). +.SH COPYRIGHT +2003-2020, LLVM Project +.\" Generated by docutils manpage writer. +.