LLVM: lib/DWARFCFIChecker/DWARFCFIAnalysis.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

30#include

31

32using namespace llvm;

33

37

40

42 return Reg == RHS.Reg && Offset == RHS.Offset;

43 }

44};

45

46static std::optional

48 auto CFALocation = UnwindRow.getCFAValue();

49 if (CFALocation.getLocation() !=

51 return std::nullopt;

52

53 return CFARegOffsetInfo(CFALocation.getRegister(), CFALocation.getOffset());

54}

55

59 assert(MaybeLoc && "the register should be included in the unwinding row");

60 auto Loc = *MaybeLoc;

61

62 switch (Loc.getLocation()) {

67

68

69

71

72

73

74 return {};

76 return {Reg};

78 return {Loc.getRegister()};

79 }

80 llvm_unreachable("Unknown dwarf::UnwindLocation::Location enum");

81}

82

84 bool IsEH,

86 : State(Context), Context(Context), MCII(MCII),

87 MCRI(Context->getRegisterInfo()), IsEH(IsEH) {

88

90 if (MCRI->get(LLVMReg).IsArtificial || MCRI->get(LLVMReg).IsConstant)

91 continue;

92

93 DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);

94

95

96

97

99 }

100

101

103 nullptr, MCRI->getDwarfRegNum(MCRI->getProgramCounter(), IsEH)));

104

105 for (auto &&InitialFrameStateCFIDirective :

106 Context->getAsmInfo()->getInitialFrameState())

107 State.update(InitialFrameStateCFIDirective);

108

109 auto MaybeCurrentRow = State.getCurrentUnwindRow();

110 assert(MaybeCurrentRow && "there should be at least one row");

113 "the CFA information should be describable in [reg + offset] in here");

114 auto CFA = *MaybeCFA;

115

116

117

119

120

121 for (auto &&Directive : Prologue)

123}

124

128

129 auto MaybePrevRow = State.getCurrentUnwindRow();

130 assert(MaybePrevRow && "the analysis should have initialized the "

131 "state with at least one row by now");

132 auto PrevRow = *MaybePrevRow;

133

134 for (auto &&Directive : Directives)

136

139 Reads.insert(MCRI->getDwarfRegNum(

142 Writes.insert(MCRI->getDwarfRegNum(

144

147 if (Op.isReg()) {

150 MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));

151 else if (Op.getReg())

153 MCRI->getDwarfRegNum(getSuperReg(MCRI, Op.getReg()), IsEH));

154 }

155 }

156

157 auto MaybeNextRow = State.getCurrentUnwindRow();

158 assert(MaybeNextRow && "previous row existed, so should the current row");

159 auto NextRow = *MaybeNextRow;

160

161 checkCFADiff(Inst, PrevRow, NextRow, Reads, Writes);

162

164 DWARFRegNum Reg = MCRI->getDwarfRegNum(LLVMReg, IsEH);

165

166 checkRegDiff(Inst, Reg, PrevRow, NextRow, Reads, Writes);

167 }

168}

169

170void DWARFCFIAnalysis::checkRegDiff(const MCInst &Inst, DWARFRegNum Reg,

177

178

179

180 if (!MaybePrevLoc) {

181 assert(!MaybeNextLoc && "the register unwind info suddenly appeared here");

182 return;

183 }

184 assert(MaybeNextLoc && "the register unwind info suddenly vanished here");

185

186 auto PrevLoc = MaybePrevLoc.value();

187 auto NextLoc = MaybeNextLoc.value();

188

190 if (!MaybeLLVMReg) {

191 if (!(PrevLoc == NextLoc))

192 Context->reportWarning(

194 formatv("the dwarf register {0} does not have a LLVM number, but its "

195 "unwind info changed. Ignoring this change",

197 return;

198 }

199 const char *RegName = MCRI->getName(*MaybeLLVMReg);

200

201

202

203

204

205

206

207

208

209 if (PrevLoc == NextLoc) {

211 if (Writes.count(UsedReg)) {

212 auto MaybeLLVMUsedReg = MCRI->getLLVMRegNum(UsedReg, IsEH);

213 assert(MaybeLLVMUsedReg && "instructions will always write to a "

214 "register that has an LLVM register number");

215 Context->reportError(

217 formatv("changed register {1}, that register {0}'s unwinding rule "

218 "uses, but there is no CFI directives about it",

219 RegName, MCRI->getName(*MaybeLLVMUsedReg)));

220 return;

221 }

222 return;

223 }

224

225 if (PrevLoc.getLocation() != NextLoc.getLocation()) {

226 Context->reportWarning(

228 formatv("validating changes happening to register {0} unwinding "

229 "rule structure is not implemented yet",

231 return;

232 }

235 Context->reportWarning(

237 formatv("validating changes happening to register {0} unwinding "

238 "rule register set is not implemented yet",

240 return;

241 }

242

244 if (Writes.count(UsedReg)) {

245 Context->reportWarning(

247 formatv("register {0} unwinding rule's offset is changed, and one of "

248 "the rule's registers is modified, but validating the "

249 "modification amount is not implemented yet",

251 return;

252 }

253

254 Context->reportError(

255 Inst.getLoc(), formatv("register {0} unwinding rule's offset is changed, "

256 "but not any of the rule's registers are modified",

258}

259

260void DWARFCFIAnalysis::checkCFADiff(const MCInst &Inst,

265

268

269 if (!MaybePrevCFA) {

270 if (MaybeNextCFA) {

271 Context->reportWarning(Inst.getLoc(),

272 "CFA rule changed to [reg + offset], this "

273 "transition will not be checked");

274 return;

275 }

276

277 Context->reportWarning(Inst.getLoc(),

278 "CFA rule is not [reg + offset], not checking it");

279 return;

280 }

281

282 if (!MaybeNextCFA) {

283 Context->reportWarning(Inst.getLoc(),

284 "CFA rule changed from [reg + offset], this "

285 "transition will not be checked");

286 return;

287 }

288

289 auto PrevCFA = *MaybePrevCFA;

290 auto NextCFA = *MaybeNextCFA;

291

292 auto MaybeLLVMPrevReg = MCRI->getLLVMRegNum(PrevCFA.Reg, IsEH);

293 const char *PrevCFARegName =

294 MaybeLLVMPrevReg ? MCRI->getName(*MaybeLLVMPrevReg) : "";

295 auto MaybeLLVMNextReg = MCRI->getLLVMRegNum(NextCFA.Reg, IsEH);

296 const char *NextCFARegName =

297 MaybeLLVMNextReg ? MCRI->getName(*MaybeLLVMNextReg) : "";

298

299 if (PrevCFA == NextCFA) {

300 if (!Writes.count(PrevCFA.Reg))

301 return;

302

303 Context->reportError(

305 formatv("modified CFA register {0} but not changed CFA rule",

306 PrevCFARegName));

307 return;

308 }

309

310 if (PrevCFA.Reg != NextCFA.Reg) {

311 Context->reportWarning(

313 formatv("CFA register changed from register {0} to register {1}, "

314 "validating this change is not implemented yet",

315 PrevCFARegName, NextCFARegName));

316 return;

317 }

318

319 if (Writes.count(PrevCFA.Reg)) {

320 Context->reportWarning(

321 Inst.getLoc(), formatv("CFA offset is changed from {0} to {1}, and CFA "

322 "register {2} is modified, but validating the "

323 "modification amount is not implemented yet",

324 PrevCFA.Offset, NextCFA.Offset, PrevCFARegName));

325 return;

326 }

327

328 Context->reportError(

330 formatv("did not modify CFA register {0} but changed CFA rule",

331 PrevCFARegName));

332}

for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static std::optional< CFARegOffsetInfo > getCFARegOffsetInfo(const dwarf::UnwindRow &UnwindRow)

Definition DWARFCFIAnalysis.cpp:47

static SmallSet< DWARFRegNum, 4 > getUnwindRuleRegSet(const dwarf::UnwindRow &UnwindRow, DWARFRegNum Reg)

Definition DWARFCFIAnalysis.cpp:57

This file declares DWARFCFIAnalysis class.

This file declares DWARFCFIState class.

This file contains helper functions to find and list registers that are tracked by the unwinding info...

This file defines the SmallSet class.

This file defines the SmallVector class.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

LLVM_ABI void update(const MCInst &Inst, ArrayRef< MCCFIInstruction > Directives)

Definition DWARFCFIAnalysis.cpp:125

LLVM_ABI DWARFCFIAnalysis(MCContext *Context, MCInstrInfo const &MCII, bool IsEH, ArrayRef< MCCFIInstruction > Prologue)

Definition DWARFCFIAnalysis.cpp:83

static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register, SMLoc Loc={})

.cfi_undefined From now on the previous value of Register can't be restored anymore.

static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})

.cfi_offset Previous value of Register is saved at offset Offset from CFA.

static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, SMLoc Loc={})

.cfi_same_value Current value of Register is the same as in the previous frame.

Context object for machine code objects.

Instances of this class represent a single low-level machine instruction.

unsigned getNumOperands() const

unsigned getOpcode() const

const MCOperand & getOperand(unsigned i) const

Describe properties that are true of each instruction in the target description file.

unsigned char NumImplicitUses

unsigned char NumImplicitDefs

unsigned getNumDefs() const

Return the number of MachineOperands that are register definitions.

ArrayRef< MCPhysReg > implicit_defs() const

Return a list of registers that are potentially written by any instance of this machine instruction.

ArrayRef< MCPhysReg > implicit_uses() const

Return a list of registers that are potentially read by any instance of this machine instruction.

Interface to description of machine instruction set.

std::optional< MCRegister > getLLVMRegNum(uint64_t RegNum, bool isEH) const

Map a dwarf register back to a target register.

SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...

size_type count(const T &V) const

count - Return 1 if the element is in the set, 0 otherwise.

std::pair< const_iterator, bool > insert(const T &V)

insert - Insert an element into the set if it isn't already there.

std::optional< UnwindLocation > getRegisterLocation(uint32_t RegNum) const

Return the location for the register in RegNum if there is a location.

@ Undefined

Register is not available and can't be recovered.

@ Constant

Value is a constant value contained in "Offset": reg = Offset.

@ DWARFExpr

Register or CFA value is in or at a value found by evaluating a DWARF expression: reg = eval(dwarf_ex...

@ Same

Register value is in the register, nothing needs to be done to unwind it: reg = reg.

@ CFAPlusOffset

Register is in or at the CFA plus an offset: reg = CFA + offset reg = defef(CFA + offset)

@ Unspecified

Not specified.

@ RegPlusOffset

Register or CFA is in or at a register plus offset, optionally in an address space: reg = reg + offse...

A class that represents a single row in the unwind table that is decoded by parsing the DWARF Call Fr...

UnwindLocation & getCFAValue()

RegisterLocations & getRegisterLocations()

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

This is an optimization pass for GlobalISel generic memory operations.

SmallVector< MCPhysReg > getTrackingRegs(const MCRegisterInfo *MCRI)

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

DWARFExpression::Operation Op

MCRegister getSuperReg(const MCRegisterInfo *MCRI, MCRegister Reg)

bool operator==(const CFARegOffsetInfo &RHS) const

Definition DWARFCFIAnalysis.cpp:41

CFARegOffsetInfo(DWARFRegNum Reg, int64_t Offset)

Definition DWARFCFIAnalysis.cpp:38

DWARFRegNum Reg

Definition DWARFCFIAnalysis.cpp:35

int64_t Offset

Definition DWARFCFIAnalysis.cpp:36