cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
195 lines
6.0 KiB
C++
195 lines
6.0 KiB
C++
//===- bolt/Passes/StokeInfo.cpp ------------------------------------------===//
|
|
//
|
|
// 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 file implements the StokeInfo class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "bolt/Passes/StokeInfo.h"
|
|
#include "bolt/Core/BinaryFunctionCallGraph.h"
|
|
#include "bolt/Passes/DataflowInfoManager.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#define DEBUG_TYPE "stoke"
|
|
|
|
using namespace llvm;
|
|
using namespace bolt;
|
|
|
|
namespace opts {
|
|
static cl::OptionCategory StokeOptCategory("STOKE pass options");
|
|
|
|
static cl::opt<std::string>
|
|
StokeOutputDataFilename("stoke-out",
|
|
cl::desc("output data (.csv) for Stoke's use"),
|
|
cl::Optional,
|
|
cl::cat(StokeOptCategory));
|
|
}
|
|
|
|
namespace llvm {
|
|
namespace bolt {
|
|
|
|
void getRegNameFromBitVec(const BinaryContext &BC, const BitVector &RegV,
|
|
std::set<std::string> *NameVec = nullptr) {
|
|
for (int RegIdx : RegV.set_bits()) {
|
|
LLVM_DEBUG(dbgs() << BC.MRI->getName(RegIdx) << " ");
|
|
if (NameVec)
|
|
NameVec->insert(std::string(BC.MRI->getName(RegIdx)));
|
|
}
|
|
LLVM_DEBUG(dbgs() << "\n");
|
|
}
|
|
|
|
void StokeInfo::checkInstr(const BinaryFunction &BF, StokeFuncInfo &FuncInfo) {
|
|
MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get();
|
|
BitVector RegV(NumRegs, false);
|
|
for (const BinaryBasicBlock *BB : BF.getLayout().blocks()) {
|
|
if (BB->empty())
|
|
continue;
|
|
|
|
// Skip function with exception handling.
|
|
if (BB->throw_size() || BB->lp_size()) {
|
|
FuncInfo.Omitted = true;
|
|
return;
|
|
}
|
|
|
|
for (const MCInst &It : *BB) {
|
|
if (MIB->isPseudo(It))
|
|
continue;
|
|
// skip function with exception handling yet
|
|
if (MIB->isInvoke(It)) {
|
|
FuncInfo.Omitted = true;
|
|
return;
|
|
}
|
|
// check if this function contains call instruction
|
|
if (MIB->isCall(It)) {
|
|
FuncInfo.HasCall = true;
|
|
const MCSymbol *TargetSymbol = MIB->getTargetSymbol(It);
|
|
// if it is an indirect call, skip
|
|
if (TargetSymbol == nullptr) {
|
|
FuncInfo.Omitted = true;
|
|
return;
|
|
}
|
|
}
|
|
// check if this function modify stack or heap
|
|
// TODO: more accurate analysis
|
|
bool IsPush = MIB->isPush(It);
|
|
bool IsRipAddr = MIB->hasPCRelOperand(It);
|
|
if (IsPush)
|
|
FuncInfo.StackOut = true;
|
|
|
|
if (MIB->mayStore(It) && !IsPush && !IsRipAddr)
|
|
FuncInfo.HeapOut = true;
|
|
|
|
if (IsRipAddr)
|
|
FuncInfo.HasRipAddr = true;
|
|
} // end of for (auto &It : ...)
|
|
} // end of for (auto *BB : ...)
|
|
}
|
|
|
|
bool StokeInfo::checkFunction(BinaryFunction &BF, DataflowInfoManager &DInfo,
|
|
RegAnalysis &RA, StokeFuncInfo &FuncInfo) {
|
|
|
|
std::string Name = BF.getSymbol()->getName().str();
|
|
|
|
if (!BF.isSimple() || BF.isMultiEntry() || BF.empty())
|
|
return false;
|
|
BF.getBinaryContext().outs()
|
|
<< " STOKE-INFO: analyzing function " << Name << "\n";
|
|
|
|
FuncInfo.FuncName = Name;
|
|
FuncInfo.Offset = BF.getFileOffset();
|
|
FuncInfo.Size = BF.getMaxSize();
|
|
FuncInfo.NumInstrs = BF.getNumNonPseudos();
|
|
FuncInfo.NumBlocks = BF.size();
|
|
// early stop for large functions
|
|
if (FuncInfo.NumInstrs > 500)
|
|
return false;
|
|
|
|
FuncInfo.IsLoopFree = BF.isLoopFree();
|
|
if (!FuncInfo.IsLoopFree) {
|
|
const BinaryLoopInfo &BLI = BF.getLoopInfo();
|
|
FuncInfo.NumLoops = BLI.OuterLoops;
|
|
FuncInfo.MaxLoopDepth = BLI.MaximumDepth;
|
|
}
|
|
|
|
FuncInfo.HotSize = BF.estimateHotSize();
|
|
FuncInfo.TotalSize = BF.estimateSize();
|
|
FuncInfo.Score = BF.getFunctionScore();
|
|
|
|
checkInstr(BF, FuncInfo);
|
|
|
|
// register analysis
|
|
BinaryBasicBlock &EntryBB = BF.front();
|
|
assert(EntryBB.isEntryPoint() && "Weird, this should be the entry block!");
|
|
|
|
MCInst *FirstNonPseudo = EntryBB.getFirstNonPseudoInstr();
|
|
if (!FirstNonPseudo)
|
|
return false;
|
|
|
|
LLVM_DEBUG(dbgs() << "\t [DefIn]\n\t ");
|
|
BitVector LiveInBV =
|
|
*(DInfo.getLivenessAnalysis().getStateAt(FirstNonPseudo));
|
|
LiveInBV &= DefaultDefInMask;
|
|
getRegNameFromBitVec(BF.getBinaryContext(), LiveInBV, &FuncInfo.DefIn);
|
|
|
|
LLVM_DEBUG(dbgs() << "\t [LiveOut]\n\t ");
|
|
BitVector LiveOutBV = RA.getFunctionClobberList(&BF);
|
|
LiveOutBV &= DefaultLiveOutMask;
|
|
getRegNameFromBitVec(BF.getBinaryContext(), LiveOutBV, &FuncInfo.LiveOut);
|
|
|
|
BF.getBinaryContext().outs() << " STOKE-INFO: end function \n";
|
|
return true;
|
|
}
|
|
|
|
Error StokeInfo::runOnFunctions(BinaryContext &BC) {
|
|
BC.outs() << "STOKE-INFO: begin of stoke pass\n";
|
|
|
|
std::ofstream Outfile;
|
|
if (!opts::StokeOutputDataFilename.empty()) {
|
|
Outfile.open(opts::StokeOutputDataFilename);
|
|
} else {
|
|
BC.errs() << "STOKE-INFO: output file is required\n";
|
|
return Error::success();
|
|
}
|
|
|
|
// check some context meta data
|
|
LLVM_DEBUG(dbgs() << "\tTarget: " << BC.TheTarget->getName() << "\n");
|
|
LLVM_DEBUG(dbgs() << "\tTripleName " << BC.TripleName << "\n");
|
|
LLVM_DEBUG(dbgs() << "\tgetNumRegs " << BC.MRI->getNumRegs() << "\n");
|
|
|
|
BinaryFunctionCallGraph CG = buildCallGraph(BC);
|
|
RegAnalysis RA(BC, &BC.getBinaryFunctions(), &CG);
|
|
|
|
NumRegs = BC.MRI->getNumRegs();
|
|
assert(NumRegs > 0 && "STOKE-INFO: the target register number is incorrect!");
|
|
|
|
DefaultDefInMask.resize(NumRegs, false);
|
|
DefaultLiveOutMask.resize(NumRegs, false);
|
|
|
|
BC.MIB->getDefaultDefIn(DefaultDefInMask);
|
|
BC.MIB->getDefaultLiveOut(DefaultLiveOutMask);
|
|
|
|
getRegNameFromBitVec(BC, DefaultDefInMask);
|
|
getRegNameFromBitVec(BC, DefaultLiveOutMask);
|
|
|
|
StokeFuncInfo FuncInfo;
|
|
// analyze all functions
|
|
FuncInfo.printCsvHeader(Outfile);
|
|
for (auto &BF : BC.getBinaryFunctions()) {
|
|
DataflowInfoManager DInfo(BF.second, &RA, nullptr);
|
|
FuncInfo.reset();
|
|
if (checkFunction(BF.second, DInfo, RA, FuncInfo))
|
|
FuncInfo.printData(Outfile);
|
|
}
|
|
|
|
BC.outs() << "STOKE-INFO: end of stoke pass\n";
|
|
return Error::success();
|
|
}
|
|
|
|
} // namespace bolt
|
|
} // namespace llvm
|