llvm.org GIT mirror llvm / 32abccb
Introduce sanstats tool and llvm::CreateSanitizerStatReport function. This is part of a new statistics gathering feature for the sanitizers. See clang/docs/SanitizerStats.rst for further info and docs. Differential Revision: http://reviews.llvm.org/D16174 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257970 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 3 years ago
10 changed file(s) with 541 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 //===- SanitizerStats.h - Sanitizer statistics gathering -------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Declares functions and data structures for sanitizer statistics gathering.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H
14 #define LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H
15
16 #include "llvm/IR/IRBuilder.h"
17
18 namespace llvm {
19
20 // Number of bits in data that are used for the sanitizer kind. Needs to match
21 // __sanitizer::kKindBits in compiler-rt/lib/stats/stats.h
22 enum { kSanitizerStatKindBits = 3 };
23
24 enum SanitizerStatKind {
25 SanStat_CFI_VCall,
26 SanStat_CFI_NVCall,
27 SanStat_CFI_DerivedCast,
28 SanStat_CFI_UnrelatedCast,
29 SanStat_CFI_ICall,
30 };
31
32 struct SanitizerStatReport {
33 SanitizerStatReport(Module *M);
34
35 /// Generates code into B that increments a location-specific counter tagged
36 /// with the given sanitizer kind SK.
37 void create(IRBuilder<> &B, SanitizerStatKind SK);
38
39 /// Finalize module stats array and add global constructor to register it.
40 void finish();
41
42 private:
43 Module *M;
44 GlobalVariable *ModuleStatsGV;
45 ArrayType *StatTy;
46 StructType *EmptyModuleStatsTy;
47
48 std::vector Inits;
49 ArrayType *makeModuleStatsArrayTy();
50 StructType *makeModuleStatsTy();
51 };
52
53 }
54
55 #endif
2929 ModuleUtils.cpp
3030 PromoteMemoryToRegister.cpp
3131 SSAUpdater.cpp
32 SanitizerStats.cpp
3233 SimplifyCFG.cpp
3334 SimplifyIndVar.cpp
3435 SimplifyInstructions.cpp
0 //===- SanitizerStats.cpp - Sanitizer statistics gathering ----------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implements code generation for sanitizer statistics gathering.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Transforms/Utils/SanitizerStats.h"
14 #include "llvm/Transforms/Utils/ModuleUtils.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/DerivedTypes.h"
18 #include "llvm/IR/GlobalVariable.h"
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/IR/Module.h"
21
22 using namespace llvm;
23
24 SanitizerStatReport::SanitizerStatReport(Module *M) : M(M) {
25 StatTy = ArrayType::get(Type::getInt8PtrTy(M->getContext()), 2);
26 EmptyModuleStatsTy = makeModuleStatsTy();
27
28 ModuleStatsGV = new GlobalVariable(*M, EmptyModuleStatsTy, false,
29 GlobalValue::InternalLinkage, 0);
30 }
31
32 ArrayType *SanitizerStatReport::makeModuleStatsArrayTy() {
33 return ArrayType::get(StatTy, Inits.size());
34 }
35
36 StructType *SanitizerStatReport::makeModuleStatsTy() {
37 return StructType::get(M->getContext(), {Type::getInt8PtrTy(M->getContext()),
38 Type::getInt32Ty(M->getContext()),
39 makeModuleStatsArrayTy()});
40 }
41
42 void SanitizerStatReport::create(IRBuilder<> &B, SanitizerStatKind SK) {
43 Function *F = B.GetInsertBlock()->getParent();
44 Module *M = F->getParent();
45 PointerType *Int8PtrTy = B.getInt8PtrTy();
46 IntegerType *IntPtrTy = B.getIntPtrTy(M->getDataLayout());
47 ArrayType *StatTy = ArrayType::get(Int8PtrTy, 2);
48
49 Inits.push_back(ConstantArray::get(
50 StatTy,
51 {Constant::getNullValue(Int8PtrTy),
52 ConstantExpr::getIntToPtr(
53 ConstantInt::get(IntPtrTy, uint64_t(SK) << (IntPtrTy->getBitWidth() -
54 kSanitizerStatKindBits)),
55 Int8PtrTy)}));
56
57 FunctionType *StatReportTy =
58 FunctionType::get(B.getVoidTy(), Int8PtrTy, false);
59 Constant *StatReport = M->getOrInsertFunction(
60 "__sanitizer_stat_report", StatReportTy);
61
62 auto InitAddr = ConstantExpr::getGetElementPtr(
63 EmptyModuleStatsTy, ModuleStatsGV,
64 ArrayRef{
65 ConstantInt::get(IntPtrTy, 0), ConstantInt::get(B.getInt32Ty(), 2),
66 ConstantInt::get(IntPtrTy, Inits.size() - 1),
67 });
68 B.CreateCall(StatReport, ConstantExpr::getBitCast(InitAddr, Int8PtrTy));
69 }
70
71 void SanitizerStatReport::finish() {
72 if (Inits.empty()) {
73 ModuleStatsGV->eraseFromParent();
74 return;
75 }
76
77 PointerType *Int8PtrTy = Type::getInt8PtrTy(M->getContext());
78 IntegerType *Int32Ty = Type::getInt32Ty(M->getContext());
79 Type *VoidTy = Type::getVoidTy(M->getContext());
80
81 // Create a new ModuleStatsGV to replace the old one. We can't just set the
82 // old one's initializer because its type is different.
83 auto NewModuleStatsGV = new GlobalVariable(
84 *M, makeModuleStatsTy(), false, GlobalValue::InternalLinkage,
85 ConstantStruct::getAnon(
86 {Constant::getNullValue(Int8PtrTy),
87 ConstantInt::get(Int32Ty, Inits.size()),
88 ConstantArray::get(makeModuleStatsArrayTy(), Inits)}));
89 ModuleStatsGV->replaceAllUsesWith(
90 ConstantExpr::getBitCast(NewModuleStatsGV, ModuleStatsGV->getType()));
91 ModuleStatsGV->eraseFromParent();
92
93 // Create a global constructor to register NewModuleStatsGV.
94 auto F = Function::Create(FunctionType::get(VoidTy, false),
95 GlobalValue::InternalLinkage, "", M);
96 auto BB = BasicBlock::Create(M->getContext(), "", F);
97 IRBuilder<> B(BB);
98
99 FunctionType *StatInitTy = FunctionType::get(VoidTy, Int8PtrTy, false);
100 Constant *StatInit = M->getOrInsertFunction(
101 "__sanitizer_stat_init", StatInitTy);
102
103 B.CreateCall(StatInit, ConstantExpr::getBitCast(NewModuleStatsGV, Int8PtrTy));
104 B.CreateRetVoid();
105
106 appendToGlobalCtors(*M, F, 0);
107 }
6060 obj2yaml
6161 opt
6262 sancov
63 sanstats
6364 verify-uselistorder
6465 yaml-bench
6566 yaml2obj
281281 r"\bFileCheck\b",
282282 r"\bobj2yaml\b",
283283 NOJUNK + r"\bsancov\b",
284 NOJUNK + r"\bsanstats\b",
284285 r"\byaml2obj\b",
285286 r"\byaml-bench\b",
286287 r"\bverify-uselistorder\b",
0 # RUN: yaml2obj -format=elf %s > %t1.o
1 # RUN: yaml2obj -format=elf %s > %t2.o
2
3 # RUN: echo -ne "\x04" > %t.stats
4
5 # RUN: echo -n "%t1.o" >> %t.stats
6 # RUN: echo -ne "\x00" >> %t.stats
7 # RUN: echo -ne "\x01\x00\x00\x00\x01\x00\x00\x00" >> %t.stats
8 # RUN: echo -ne "\x11\x00\x00\x00\x02\x00\x00\x20" >> %t.stats
9 # RUN: echo -ne "\x21\x00\x00\x00\x03\x00\x00\x40" >> %t.stats
10 # RUN: echo -ne "\x01\x00\x00\x00\x04\x00\x00\x60" >> %t.stats
11 # RUN: echo -ne "\x11\x00\x00\x00\x05\x00\x00\x80" >> %t.stats
12 # RUN: echo -ne "\x21\x00\x00\x00\x06\x00\x00\xa0" >> %t.stats
13 # RUN: echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" >> %t.stats
14
15 # RUN: echo -n "%t2.o" >> %t.stats
16 # RUN: echo -ne "\x00" >> %t.stats
17 # RUN: echo -ne "\x21\x00\x00\x00\x07\x00\x00\x00" >> %t.stats
18 # RUN: echo -ne "\x11\x00\x00\x00\x08\x00\x00\x20" >> %t.stats
19 # RUN: echo -ne "\x01\x00\x00\x00\x09\x00\x00\x40" >> %t.stats
20 # RUN: echo -ne "\x21\x00\x00\x00\x0b\x00\x00\x60" >> %t.stats
21 # RUN: echo -ne "\x11\x00\x00\x00\x0c\x00\x00\x80" >> %t.stats
22 # RUN: echo -ne "\x01\x00\x00\x00\x0e\x00\x00\xa0" >> %t.stats
23 # RUN: echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" >> %t.stats
24
25 # RUN: sanstats %t.stats | FileCheck %s
26
27 # CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-vcall 1
28 # CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-nvcall 2
29 # CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-derived-cast 3
30 # CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-unrelated-cast 4
31 # CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-icall 5
32 # CHECK: /tmp{{[/\\]}}f.c:3 f3 6
33
34 # CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-vcall 7
35 # CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-nvcall 8
36 # CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-derived-cast 9
37 # CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-unrelated-cast 11
38 # CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-icall 12
39 # CHECK: /tmp{{[/\\]}}f.c:1 f1 14
40
41 ---
42 FileHeader:
43 Class: ELFCLASS64
44 Data: ELFDATA2LSB
45 Type: ET_REL
46 Machine: EM_X86_64
47 Sections:
48 - Name: .text
49 Type: SHT_PROGBITS
50 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
51 AddressAlign: 0x0000000000000010
52 Content: 554889E55DC3662E0F1F840000000000554889E55DC3662E0F1F840000000000554889E55DC3
53 - Name: .debug_str
54 Type: SHT_PROGBITS
55 Flags: [ SHF_MERGE, SHF_STRINGS ]
56 AddressAlign: 0x0000000000000001
57 Content: 636C616E672076657273696F6E20332E382E3020287472756E6B203235353339332920286C6C766D2F7472756E6B203235353734352900662E63002F746D7000663100663200663300
58 - Name: .debug_loc
59 Type: SHT_PROGBITS
60 AddressAlign: 0x0000000000000001
61 Content: ''
62 - Name: .debug_abbrev
63 Type: SHT_PROGBITS
64 AddressAlign: 0x0000000000000001
65 Content: 011101250E1305030E10171B0E110112060000022E00110112064018030E3A0B3B0B3F19000000
66 - Name: .debug_info
67 Type: SHT_PROGBITS
68 AddressAlign: 0x0000000000000001
69 Content: 660000000400000000000801000000000C0000000000000000000000000000000000000000002600000002000000000000000006000000015600000000010102000000000000000006000000015600000000010202000000000000000006000000015600000000010300
70 - Name: .rela.debug_info
71 Type: SHT_RELA
72 Link: .symtab
73 AddressAlign: 0x0000000000000008
74 Info: .debug_info
75 Relocations:
76 - Offset: 0x0000000000000006
77 Symbol: ''
78 Type: R_X86_64_32
79 - Offset: 0x000000000000000C
80 Symbol: ''
81 Type: R_X86_64_32
82 - Offset: 0x0000000000000012
83 Symbol: ''
84 Type: R_X86_64_32
85 Addend: 55
86 - Offset: 0x0000000000000016
87 Symbol: ''
88 Type: R_X86_64_32
89 - Offset: 0x000000000000001A
90 Symbol: ''
91 Type: R_X86_64_32
92 Addend: 59
93 - Offset: 0x000000000000001E
94 Symbol: ''
95 Type: R_X86_64_64
96 - Offset: 0x000000000000002B
97 Symbol: ''
98 Type: R_X86_64_64
99 - Offset: 0x0000000000000039
100 Symbol: ''
101 Type: R_X86_64_32
102 Addend: 64
103 - Offset: 0x0000000000000040
104 Symbol: ''
105 Type: R_X86_64_64
106 Addend: 16
107 - Offset: 0x000000000000004E
108 Symbol: ''
109 Type: R_X86_64_32
110 Addend: 67
111 - Offset: 0x0000000000000055
112 Symbol: ''
113 Type: R_X86_64_64
114 Addend: 32
115 - Offset: 0x0000000000000063
116 Symbol: ''
117 Type: R_X86_64_32
118 Addend: 70
119 - Name: .debug_ranges
120 Type: SHT_PROGBITS
121 AddressAlign: 0x0000000000000001
122 Content: ''
123 - Name: .debug_pubnames
124 Type: SHT_PROGBITS
125 AddressAlign: 0x0000000000000001
126 Content: 230000000200000000006A0000002A0000006631003F0000006632005400000066330000000000
127 - Name: .rela.debug_pubnames
128 Type: SHT_RELA
129 Link: .symtab
130 AddressAlign: 0x0000000000000008
131 Info: .debug_pubnames
132 Relocations:
133 - Offset: 0x0000000000000006
134 Symbol: ''
135 Type: R_X86_64_32
136 - Name: .comment
137 Type: SHT_PROGBITS
138 Flags: [ SHF_MERGE, SHF_STRINGS ]
139 AddressAlign: 0x0000000000000001
140 Content: 00636C616E672076657273696F6E20332E382E3020287472756E6B203235353339332920286C6C766D2F7472756E6B203235353734352900
141 - Name: .note.GNU-stack
142 Type: SHT_PROGBITS
143 AddressAlign: 0x0000000000000001
144 Content: ''
145 - Name: .eh_frame
146 Type: SHT_X86_64_UNWIND
147 Flags: [ SHF_ALLOC ]
148 AddressAlign: 0x0000000000000008
149 Content: 1400000000000000017A5200017810011B0C070890010000180000001C000000000000000600000000410E108602430D060000001800000038000000000000000600000000410E108602430D060000001C00000054000000000000000600000000410E108602430D0600000000000000
150 - Name: .rela.eh_frame
151 Type: SHT_RELA
152 Link: .symtab
153 AddressAlign: 0x0000000000000008
154 Info: .eh_frame
155 Relocations:
156 - Offset: 0x0000000000000020
157 Symbol: ''
158 Type: R_X86_64_PC32
159 - Offset: 0x000000000000003C
160 Symbol: ''
161 Type: R_X86_64_PC32
162 Addend: 16
163 - Offset: 0x0000000000000058
164 Symbol: ''
165 Type: R_X86_64_PC32
166 Addend: 32
167 - Name: .debug_line
168 Type: SHT_PROGBITS
169 AddressAlign: 0x0000000000000001
170 Content: 4300000002001A0000000101FB0E0D00010101010000000100000100662E630000000000000902000000000000000001050C0A4A0500BB050C0A4A0500BB050C0A4A0202000101
171 - Name: .rela.debug_line
172 Type: SHT_RELA
173 Link: .symtab
174 AddressAlign: 0x0000000000000008
175 Info: .debug_line
176 Relocations:
177 - Offset: 0x0000000000000027
178 Symbol: ''
179 Type: R_X86_64_64
180 Symbols:
181 Local:
182 - Name: f.c
183 Type: STT_FILE
184 - Type: STT_SECTION
185 Section: .text
186 - Type: STT_SECTION
187 Section: .debug_str
188 - Type: STT_SECTION
189 Section: .debug_abbrev
190 - Type: STT_SECTION
191 Section: .debug_info
192 - Type: STT_SECTION
193 Section: .debug_line
194 Global:
195 - Name: f1
196 Type: STT_FUNC
197 Section: .text
198 Size: 0x0000000000000006
199 - Name: f2
200 Type: STT_FUNC
201 Section: .text
202 Value: 0x0000000000000010
203 Size: 0x0000000000000006
204 - Name: f3
205 Type: STT_FUNC
206 Section: .text
207 Value: 0x0000000000000020
208 Size: 0x0000000000000006
209 ...
3232 llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
3333 llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
3434 llvm-cxxdump verify-uselistorder dsymutil llvm-pdbdump \
35 llvm-split sancov llvm-dwp
35 llvm-split sancov sanstats llvm-dwp
3636
3737 # If Intel JIT Events support is configured, build an extra tool to test it.
3838 ifeq ($(USE_INTEL_JITEVENTS), 1)
0 set(LLVM_LINK_COMPONENTS
1 Support
2 Symbolize
3 )
4
5 add_llvm_tool(sanstats
6 sanstats.cpp
7 )
0 ##===- tools/sanstats/Makefile -----------------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL := ../..
10 TOOLNAME := sanstats
11 LINK_COMPONENTS := Support Symbolize
12
13 # This tool has no plugins, optimize startup time.
14 TOOL_NO_EXPORTS := 1
15
16 include $(LEVEL)/Makefile.common
0 //===- sanstats.cpp - Sanitizer statistics dumper -------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tool dumps statistics information from files in the format produced
10 // by clang's -fsanitize-stats feature.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/ErrorOr.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Transforms/Utils/SanitizerStats.h"
19 #include
20
21 using namespace llvm;
22
23 static cl::opt ClInputFile(cl::Positional, cl::Required,
24 cl::desc(""));
25
26 static cl::opt ClDemangle("demangle", cl::init(false),
27 cl::desc("Print demangled function name."));
28
29 inline uint64_t KindFromData(uint64_t Data, char SizeofPtr) {
30 return Data >> (SizeofPtr * 8 - kSanitizerStatKindBits);
31 }
32
33 inline uint64_t CountFromData(uint64_t Data, char SizeofPtr) {
34 return Data & ((1ull << (SizeofPtr * 8 - kSanitizerStatKindBits)) - 1);
35 }
36
37 uint64_t ReadLE(char Size, const char *Begin, const char *End) {
38 uint64_t Result = 0;
39 char Pos = 0;
40 while (Begin < End && Pos != Size) {
41 Result |= uint64_t(uint8_t(*Begin)) << (Pos * 8);
42 ++Begin;
43 ++Pos;
44 }
45 return Result;
46 }
47
48 const char *ReadModule(char SizeofPtr, const char *Begin, const char *End) {
49 const char *FilenameBegin = Begin;
50 while (Begin != End && *Begin)
51 ++Begin;
52 if (Begin == End)
53 return 0;
54 StringRef Filename(FilenameBegin, Begin - FilenameBegin);
55
56 ++Begin;
57 if (Begin == End)
58 return 0;
59
60 symbolize::LLVMSymbolizer::Options SymbolizerOptions;
61 SymbolizerOptions.Demangle = ClDemangle;
62 SymbolizerOptions.UseSymbolTable = true;
63 symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions);
64
65 while (1) {
66 uint64_t Addr = ReadLE(SizeofPtr, Begin, End);
67 Begin += SizeofPtr;
68 uint64_t Data = ReadLE(SizeofPtr, Begin, End);
69 Begin += SizeofPtr;
70
71 if (Begin > End)
72 return 0;
73 if (Addr == 0 && Data == 0)
74 return Begin;
75 if (Begin == End)
76 return 0;
77
78 ErrorOr LineInfo = Symbolizer.symbolizeCode(Filename, Addr);
79 if (LineInfo) {
80 llvm::outs() << LineInfo->FileName << ':' << LineInfo->Line << ' '
81 << LineInfo->FunctionName << ' ';
82 } else {
83 llvm::outs() << " ";
84 }
85
86 switch (KindFromData(Data, SizeofPtr)) {
87 case SanStat_CFI_VCall:
88 llvm::outs() << "cfi-vcall";
89 break;
90 case SanStat_CFI_NVCall:
91 llvm::outs() << "cfi-nvcall";
92 break;
93 case SanStat_CFI_DerivedCast:
94 llvm::outs() << "cfi-derived-cast";
95 break;
96 case SanStat_CFI_UnrelatedCast:
97 llvm::outs() << "cfi-unrelated-cast";
98 break;
99 case SanStat_CFI_ICall:
100 llvm::outs() << "cfi-icall";
101 break;
102 default:
103 llvm::outs() << "";
104 break;
105 }
106
107 llvm::outs() << " " << CountFromData(Data, SizeofPtr) << '\n';
108 }
109 }
110
111 int main(int argc, char **argv) {
112 cl::ParseCommandLineOptions(argc, argv,
113 "Sanitizer Statistics Processing Tool");
114
115 ErrorOr> MBOrErr =
116 MemoryBuffer::getFile(ClInputFile, -1, false);
117 if (!MBOrErr) {
118 errs() << argv[0] << ": " << ClInputFile << ": "
119 << MBOrErr.getError().message() << '\n';
120 return 1;
121 }
122 std::unique_ptr MB = std::move(MBOrErr.get());
123 const char *Begin = MB->getBufferStart(), *End = MB->getBufferEnd();
124 if (Begin == End) {
125 errs() << argv[0] << ": " << ClInputFile << ": short read\n";
126 return 1;
127 }
128 char SizeofPtr = *Begin++;
129 while (Begin != End) {
130 Begin = ReadModule(SizeofPtr, Begin, End);
131 if (Begin == 0) {
132 errs() << argv[0] << ": " << ClInputFile << ": short read\n";
133 return 1;
134 }
135 assert(Begin <= End);
136 }
137 }