Skip to content

Commit cb0dcd0

Browse files
committed
ABI verifier: Add standalone tool pnacl-abicheck
This CL adds a standalone tool pnacl-abicheck for checking the ABI validity of a bitcode file. It also adds a flag pnaclabi-verify to llc to enable the same checking in llc. It also improves the mechanism for handling and reporting validation errors and uses it in both tools. [email protected],[email protected] BUG= https://code.google.com/p/nativeclient/issues/detail?id=2309 Review URL: https://codereview.chromium.org/12449014
1 parent 79da56a commit cb0dcd0

File tree

11 files changed

+271
-63
lines changed

11 files changed

+271
-63
lines changed

include/llvm/Analysis/NaCl.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,44 @@
1010
#ifndef LLVM_ANALYSIS_NACL_H
1111
#define LLVM_ANALYSIS_NACL_H
1212

13+
#include "llvm/Support/raw_ostream.h"
14+
#include <string>
15+
1316
namespace llvm {
1417

1518
class FunctionPass;
1619
class ModulePass;
1720

18-
FunctionPass *createPNaClABIVerifyFunctionsPass();
19-
ModulePass *createPNaClABIVerifyModulePass();
21+
class PNaClABIErrorReporter {
22+
public:
23+
PNaClABIErrorReporter() : ErrorCount(0), Errors(ErrorString) {}
24+
// Return the number of verification errors from the last run.
25+
int getErrorCount() { return ErrorCount; }
26+
// Print the error messages to O
27+
void printErrors(llvm::raw_ostream &O) {
28+
Errors.flush();
29+
O << ErrorString;
30+
}
31+
// Increments the error count and returns an ostream to which the error
32+
// message can be streamed.
33+
raw_ostream &addError() {
34+
ErrorCount++;
35+
return Errors;
36+
}
37+
// Reset the error count and error messages.
38+
void reset() {
39+
ErrorCount = 0;
40+
Errors.flush();
41+
ErrorString.clear();
42+
}
43+
private:
44+
int ErrorCount;
45+
std::string ErrorString;
46+
raw_string_ostream Errors;
47+
};
48+
49+
FunctionPass *createPNaClABIVerifyFunctionsPass(PNaClABIErrorReporter * Reporter);
50+
ModulePass *createPNaClABIVerifyModulePass(PNaClABIErrorReporter * Reporter);
2051

2152
}
2253

lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
#include "llvm/Pass.h"
1616
#include "llvm/ADT/Twine.h"
17+
#include "llvm/Analysis/NaCl.h"
1718
#include "llvm/IR/Function.h"
1819
#include "llvm/IR/Instructions.h"
1920
#include "llvm/IR/Metadata.h"
2021
#include "llvm/Support/raw_ostream.h"
21-
#include "llvm/Analysis/NaCl.h"
2222

2323
#include "PNaClABITypeChecker.h"
2424
using namespace llvm;
@@ -30,22 +30,29 @@ namespace {
3030
class PNaClABIVerifyFunctions : public FunctionPass {
3131
public:
3232
static char ID;
33-
PNaClABIVerifyFunctions() : FunctionPass(ID), Errors(ErrorsString) {}
33+
PNaClABIVerifyFunctions() : FunctionPass(ID),
34+
Reporter(new PNaClABIErrorReporter),
35+
ReporterIsOwned(true) {}
36+
explicit PNaClABIVerifyFunctions(PNaClABIErrorReporter *Reporter_) :
37+
FunctionPass(ID),
38+
Reporter(Reporter_),
39+
ReporterIsOwned(false) {}
40+
~PNaClABIVerifyFunctions() {
41+
if (ReporterIsOwned)
42+
delete Reporter;
43+
}
3444
bool runOnFunction(Function &F);
3545
virtual void print(raw_ostream &O, const Module *M) const;
3646
private:
3747
PNaClABITypeChecker TC;
38-
std::string ErrorsString;
39-
raw_string_ostream Errors;
48+
PNaClABIErrorReporter *Reporter;
49+
bool ReporterIsOwned;
4050
};
4151

4252
} // and anonymous namespace
4353

4454
bool PNaClABIVerifyFunctions::runOnFunction(Function &F) {
45-
// For now just start with new errors on each function; this may change
46-
// once we want to do something with them other than just calling print()
47-
ErrorsString.clear();
48-
// TODO: only report one error per instruction
55+
// TODO: only report one error per instruction?
4956
for (Function::const_iterator FI = F.begin(), FE = F.end();
5057
FI != FE; ++FI) {
5158
for (BasicBlock::const_iterator BBI = FI->begin(), BBE = FI->end();
@@ -59,9 +66,9 @@ bool PNaClABIVerifyFunctions::runOnFunction(Function &F) {
5966
case Instruction::ExtractElement:
6067
case Instruction::InsertElement:
6168
case Instruction::ShuffleVector:
62-
Errors << "Function " + F.getName() +
63-
" has disallowed instruction: " +
64-
BBI->getOpcodeName() + "\n";
69+
Reporter->addError() << "Function " << F.getName() <<
70+
" has disallowed instruction: " <<
71+
BBI->getOpcodeName() << "\n";
6572
break;
6673

6774
// Terminator instructions
@@ -126,9 +133,9 @@ bool PNaClABIVerifyFunctions::runOnFunction(Function &F) {
126133
}
127134
// Check the types. First check the type of the instruction.
128135
if (!TC.isValidType(BBI->getType())) {
129-
Errors << "Function " + F.getName() +
130-
" has instruction with disallowed type: " +
131-
PNaClABITypeChecker::getTypeName(BBI->getType()) + "\n";
136+
Reporter->addError() << "Function " << F.getName() <<
137+
" has instruction with disallowed type: " <<
138+
PNaClABITypeChecker::getTypeName(BBI->getType()) << "\n";
132139
}
133140

134141
// Check the instruction operands. Operands which are Instructions will
@@ -141,10 +148,11 @@ bool PNaClABIVerifyFunctions::runOnFunction(Function &F) {
141148
OI != OE; OI++) {
142149
if (isa<Constant>(OI) && !isa<GlobalValue>(OI)) {
143150
Type *T = TC.checkTypesInConstant(cast<Constant>(*OI));
144-
if (T)
145-
Errors << "Function " + F.getName() +
146-
" has instruction operand with disallowed type: " +
147-
PNaClABITypeChecker::getTypeName(T) + "\n";
151+
if (T) {
152+
Reporter->addError() << "Function " << F.getName() <<
153+
" has instruction operand with disallowed type: " <<
154+
PNaClABITypeChecker::getTypeName(T) << "\n";
155+
}
148156
}
149157
}
150158

@@ -153,28 +161,33 @@ bool PNaClABIVerifyFunctions::runOnFunction(Function &F) {
153161
BBI->getAllMetadataOtherThanDebugLoc(MDForInst);
154162
for (unsigned i = 0, e = MDForInst.size(); i != e; i++) {
155163
Type *T = TC.checkTypesInMDNode(MDForInst[i].second);
156-
if (T)
157-
Errors << "Function " + F.getName() +
158-
" has instruction metadata containing disallowed type: " +
159-
PNaClABITypeChecker::getTypeName(T) + "\n";
164+
if (T) {
165+
Reporter->addError() << "Function " << F.getName() <<
166+
" has instruction metadata containing disallowed type: " <<
167+
PNaClABITypeChecker::getTypeName(T) << "\n";
168+
}
160169
}
161170
}
162171
}
163172

164-
Errors.flush();
165173
return false;
166174
}
167175

176+
// This method exists so that the passes can easily be run with opt -analyze.
177+
// In this case the default constructor is used and we want to reset the error
178+
// messages after each print.
168179
void PNaClABIVerifyFunctions::print(llvm::raw_ostream &O, const Module *M)
169180
const {
170-
O << ErrorsString;
181+
Reporter->printErrors(O);
182+
Reporter->reset();
171183
}
172184

173185
char PNaClABIVerifyFunctions::ID = 0;
174186

175187
static RegisterPass<PNaClABIVerifyFunctions> X("verify-pnaclabi-functions",
176188
"Verify functions for PNaCl", false, false);
177189

178-
FunctionPass *llvm::createPNaClABIVerifyFunctionsPass() {
179-
return new PNaClABIVerifyFunctions();
190+
FunctionPass *llvm::createPNaClABIVerifyFunctionsPass(
191+
PNaClABIErrorReporter *Reporter) {
192+
return new PNaClABIVerifyFunctions(Reporter);
180193
}

lib/Analysis/NaCl/PNaClABIVerifyModule.cpp

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
//===----------------------------------------------------------------------===//
1515

1616
#include "llvm/Pass.h"
17-
#include "llvm/Analysis/NaCl.h"
1817
#include "llvm/ADT/Twine.h"
18+
#include "llvm/Analysis/NaCl.h"
1919
#include "llvm/IR/DerivedTypes.h"
2020
#include "llvm/IR/Module.h"
2121
#include "llvm/Support/raw_ostream.h"
@@ -28,13 +28,23 @@ namespace {
2828
class PNaClABIVerifyModule : public ModulePass {
2929
public:
3030
static char ID;
31-
PNaClABIVerifyModule();
31+
PNaClABIVerifyModule() : ModulePass(ID),
32+
Reporter(new PNaClABIErrorReporter),
33+
ReporterIsOwned(true) {}
34+
explicit PNaClABIVerifyModule(PNaClABIErrorReporter *Reporter_) :
35+
ModulePass(ID),
36+
Reporter(Reporter_),
37+
ReporterIsOwned(false) {}
38+
~PNaClABIVerifyModule() {
39+
if (ReporterIsOwned)
40+
delete Reporter;
41+
}
3242
bool runOnModule(Module &M);
3343
virtual void print(raw_ostream &O, const Module *M) const;
3444
private:
3545
PNaClABITypeChecker TC;
36-
std::string ErrorsString;
37-
raw_string_ostream Errors;
46+
PNaClABIErrorReporter *Reporter;
47+
bool ReporterIsOwned;
3848
};
3949

4050
static const char *linkageName(GlobalValue::LinkageTypes LT) {
@@ -65,26 +75,24 @@ static const char *linkageName(GlobalValue::LinkageTypes LT) {
6575

6676
} // end anonymous namespace
6777

68-
PNaClABIVerifyModule::PNaClABIVerifyModule() : ModulePass(ID),
69-
Errors(ErrorsString) {}
70-
7178
bool PNaClABIVerifyModule::runOnModule(Module &M) {
7279
for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end();
7380
MI != ME; ++MI) {
7481
// Check types of global variables and their initializers
7582
if (!TC.isValidType(MI->getType())) {
7683
// GVs are pointers, so print the pointed-to type for clarity
77-
Errors << "Variable " + MI->getName() +
78-
" has disallowed type: " +
84+
Reporter->addError() << "Variable " << MI->getName() <<
85+
" has disallowed type: " <<
7986
PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0))
8087
+ "\n";
8188
} else if (MI->hasInitializer()) {
8289
// If the type of the global is bad, no point in checking its initializer
8390
Type *T = TC.checkTypesInConstant(MI->getInitializer());
84-
if (T)
85-
Errors << "Initializer for " + MI->getName() +
86-
" has disallowed type: " +
87-
PNaClABITypeChecker::getTypeName(T) + "\n";
91+
if (T) {
92+
Reporter->addError() << "Initializer for " << MI->getName() <<
93+
" has disallowed type: " <<
94+
PNaClABITypeChecker::getTypeName(T) << "\n";
95+
}
8896
}
8997

9098
// Check GV linkage types
@@ -95,54 +103,65 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
95103
case GlobalValue::PrivateLinkage:
96104
break;
97105
default:
98-
Errors << "Variable " + MI->getName() +
99-
" has disallowed linkage type: " +
100-
linkageName(MI->getLinkage()) + "\n";
106+
Reporter->addError() << "Variable " << MI->getName() <<
107+
" has disallowed linkage type: " <<
108+
linkageName(MI->getLinkage()) << "\n";
101109
}
102110
}
103111
// No aliases allowed for now.
104112
for (Module::alias_iterator MI = M.alias_begin(),
105-
E = M.alias_end(); MI != E; ++MI)
106-
Errors << "Variable " + MI->getName() + " is an alias (disallowed)\n";
113+
E = M.alias_end(); MI != E; ++MI) {
114+
Reporter->addError() << "Variable " << MI->getName() <<
115+
" is an alias (disallowed)\n";
116+
}
107117

108118
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
109119
// Check types of functions and their arguments
110120
FunctionType *FT = MI->getFunctionType();
111-
if (!TC.isValidType(FT->getReturnType()))
112-
Errors << "Function " + MI->getName() + " has disallowed return type: " +
113-
PNaClABITypeChecker::getTypeName(FT->getReturnType()) + "\n";
121+
if (!TC.isValidType(FT->getReturnType())) {
122+
Reporter->addError() << "Function " << MI->getName() <<
123+
" has disallowed return type: " <<
124+
PNaClABITypeChecker::getTypeName(FT->getReturnType()) << "\n";
125+
}
114126
for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) {
115127
Type *PT = FT->getParamType(I);
116-
if (!TC.isValidType(PT))
117-
Errors << "Function " << MI->getName() << " argument " << I + 1 <<
118-
" has disallowed type: " <<
119-
PNaClABITypeChecker::getTypeName(PT) + "\n";
128+
if (!TC.isValidType(PT)) {
129+
Reporter->addError() << "Function " << MI->getName() << " argument " <<
130+
I + 1 << " has disallowed type: " <<
131+
PNaClABITypeChecker::getTypeName(PT) << "\n";
132+
}
120133
}
121134
}
122135

123136
// Check named metadata nodes
124137
for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
125138
E = M.named_metadata_end(); I != E; ++I) {
126139
for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) {
127-
if (Type *T = TC.checkTypesInMDNode(I->getOperand(i)))
128-
Errors << "Named metadata node " + I->getName() +
129-
" refers to disallowed type: " +
130-
PNaClABITypeChecker::getTypeName(T) + "\n";
140+
if (Type *T = TC.checkTypesInMDNode(I->getOperand(i))) {
141+
Reporter->addError() << "Named metadata node " << I->getName() <<
142+
" refers to disallowed type: " <<
143+
PNaClABITypeChecker::getTypeName(T) << "\n";
144+
}
131145
}
132146
}
133-
Errors.flush();
134147
return false;
135148
}
136149

150+
// This method exists so that the passes can easily be run with opt -analyze.
151+
// In this case the default constructor is used and we want to reset the error
152+
// messages after each print (this is more of an issue for the FunctionPass
153+
// than the ModulePass)
137154
void PNaClABIVerifyModule::print(llvm::raw_ostream &O, const Module *M) const {
138-
O << ErrorsString;
155+
Reporter->printErrors(O);
156+
Reporter->reset();
139157
}
140158

141159
char PNaClABIVerifyModule::ID = 0;
142160

143161
static RegisterPass<PNaClABIVerifyModule> X("verify-pnaclabi-module",
144162
"Verify module for PNaCl", false, false);
145163

146-
ModulePass *llvm::createPNaClABIVerifyModulePass() {
147-
return new PNaClABIVerifyModule();
164+
ModulePass *llvm::createPNaClABIVerifyModulePass(
165+
PNaClABIErrorReporter *Reporter) {
166+
return new PNaClABIVerifyModule(Reporter);
148167
}

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ add_subdirectory(llvm-stress)
4242
add_subdirectory(llvm-mcmarkup)
4343

4444
add_subdirectory(llvm-symbolizer)
45+
add_subdirectory(pnacl-abicheck)
4546

4647
if( NOT WIN32 )
4748
add_subdirectory(lto)

tools/LLVMBuild.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
;===------------------------------------------------------------------------===;
1717

1818
[common]
19-
subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup
19+
subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup pnacl-abicheck
2020

2121
[component_0]
2222
type = Group

tools/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \
3535
llvm-diff macho-dump llvm-objdump llvm-readobj \
3636
llvm-rtdyld llvm-dwarfdump llvm-cov \
3737
llvm-size llvm-stress llvm-mcmarkup bc-wrap pso-stub \
38-
llvm-symbolizer
38+
llvm-symbolizer pnacl-abicheck
3939

4040
# If Intel JIT Events support is configured, build an extra tool to test it.
4141
ifeq ($(USE_INTEL_JITEVENTS), 1)

0 commit comments

Comments
 (0)