Skip to content

Commit 164c8e3

Browse files
dschuffRichard Diamond
authored and
Richard Diamond
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 (cherry picked from commit cb0dcd0) Conflicts: lib/Analysis/NaCl/PNaClABIVerifyModule.cpp tools/CMakeLists.txt tools/LLVMBuild.txt tools/Makefile tools/llc/llc.cpp
1 parent 986706f commit 164c8e3

File tree

11 files changed

+274
-67
lines changed

11 files changed

+274
-67
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: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16-
#include "llvm/ADT/Twine.h"
17-
#include "llvm/DerivedTypes.h"
18-
#include "llvm/Module.h"
1916
#include "llvm/Pass.h"
20-
21-
#include "llvm/Support/raw_ostream.h"
17+
#include "llvm/ADT/Twine.h"
2218
#include "llvm/Analysis/NaCl.h"
19+
#include "llvm/IR/DerivedTypes.h"
20+
#include "llvm/IR/Module.h"
21+
#include "llvm/Support/raw_ostream.h"
2322

2423
#include "PNaClABITypeChecker.h"
2524
using namespace llvm;
@@ -29,13 +28,23 @@ namespace {
2928
class PNaClABIVerifyModule : public ModulePass {
3029
public:
3130
static char ID;
32-
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+
}
3342
bool runOnModule(Module &M);
3443
virtual void print(raw_ostream &O, const Module *M) const;
3544
private:
3645
PNaClABITypeChecker TC;
37-
std::string ErrorsString;
38-
raw_string_ostream Errors;
46+
PNaClABIErrorReporter *Reporter;
47+
bool ReporterIsOwned;
3948
};
4049

4150
static const char *linkageName(GlobalValue::LinkageTypes LT) {
@@ -66,26 +75,24 @@ static const char *linkageName(GlobalValue::LinkageTypes LT) {
6675

6776
} // end anonymous namespace
6877

69-
PNaClABIVerifyModule::PNaClABIVerifyModule() : ModulePass(ID),
70-
Errors(ErrorsString) {}
71-
7278
bool PNaClABIVerifyModule::runOnModule(Module &M) {
7379
for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end();
7480
MI != ME; ++MI) {
7581
// Check types of global variables and their initializers
7682
if (!TC.isValidType(MI->getType())) {
7783
// GVs are pointers, so print the pointed-to type for clarity
78-
Errors << "Variable " + MI->getName() +
79-
" has disallowed type: " +
84+
Reporter->addError() << "Variable " << MI->getName() <<
85+
" has disallowed type: " <<
8086
PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0))
8187
+ "\n";
8288
} else if (MI->hasInitializer()) {
8389
// If the type of the global is bad, no point in checking its initializer
8490
Type *T = TC.checkTypesInConstant(MI->getInitializer());
85-
if (T)
86-
Errors << "Initializer for " + MI->getName() +
87-
" has disallowed type: " +
88-
PNaClABITypeChecker::getTypeName(T) + "\n";
91+
if (T) {
92+
Reporter->addError() << "Initializer for " << MI->getName() <<
93+
" has disallowed type: " <<
94+
PNaClABITypeChecker::getTypeName(T) << "\n";
95+
}
8996
}
9097

9198
// Check GV linkage types
@@ -96,54 +103,65 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
96103
case GlobalValue::PrivateLinkage:
97104
break;
98105
default:
99-
Errors << "Variable " + MI->getName() +
100-
" has disallowed linkage type: " +
101-
linkageName(MI->getLinkage()) + "\n";
106+
Reporter->addError() << "Variable " << MI->getName() <<
107+
" has disallowed linkage type: " <<
108+
linkageName(MI->getLinkage()) << "\n";
102109
}
103110
}
104111
// No aliases allowed for now.
105112
for (Module::alias_iterator MI = M.alias_begin(),
106-
E = M.alias_end(); MI != E; ++MI)
107-
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+
}
108117

109118
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
110119
// Check types of functions and their arguments
111120
FunctionType *FT = MI->getFunctionType();
112-
if (!TC.isValidType(FT->getReturnType()))
113-
Errors << "Function " + MI->getName() + " has disallowed return type: " +
114-
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+
}
115126
for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) {
116127
Type *PT = FT->getParamType(I);
117-
if (!TC.isValidType(PT))
118-
Errors << "Function " << MI->getName() << " argument " << I + 1 <<
119-
" has disallowed type: " <<
120-
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+
}
121133
}
122134
}
123135

124136
// Check named metadata nodes
125137
for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
126138
E = M.named_metadata_end(); I != E; ++I) {
127139
for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) {
128-
if (Type *T = TC.checkTypesInMDNode(I->getOperand(i)))
129-
Errors << "Named metadata node " + I->getName() +
130-
" refers to disallowed type: " +
131-
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+
}
132145
}
133146
}
134-
Errors.flush();
135147
return false;
136148
}
137149

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)
138154
void PNaClABIVerifyModule::print(llvm::raw_ostream &O, const Module *M) const {
139-
O << ErrorsString;
155+
Reporter->printErrors(O);
156+
Reporter->reset();
140157
}
141158

142159
char PNaClABIVerifyModule::ID = 0;
143160

144161
static RegisterPass<PNaClABIVerifyModule> X("verify-pnaclabi-module",
145162
"Verify module for PNaCl", false, false);
146163

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

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ add_llvm_tool_subdirectory(llvm-stress)
3838
add_llvm_tool_subdirectory(llvm-mcmarkup)
3939

4040
add_llvm_tool_subdirectory(llvm-symbolizer)
41+
add_subdirectory(pnacl-abicheck)
4142

4243
add_llvm_tool_subdirectory(llvm-c-test)
4344

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-lto llvm-mc llvm-nm llvm-objdump 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-lto llvm-mc llvm-nm llvm-objdump 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
@@ -31,7 +31,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \
3131
lli llvm-extract llvm-mc bugpoint llvm-bcanalyzer llvm-diff \
3232
macho-dump llvm-objdump llvm-readobj llvm-rtdyld \
3333
llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
34-
llvm-symbolizer obj2yaml yaml2obj llvm-c-test
34+
llvm-symbolizer obj2yaml yaml2obj llvm-c-test pnacl-abicheck
3535

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

0 commit comments

Comments
 (0)