1 //===- sanstats.cpp - Sanitizer statistics dumper -------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This tool dumps statistics information from files in the format produced
11 // by clang's -fsanitize-stats feature.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/ErrorOr.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Transforms/Utils/SanitizerStats.h"
24 static cl::opt
<std::string
> ClInputFile(cl::Positional
, cl::Required
,
25 cl::desc("<filename>"));
27 static cl::opt
<bool> ClDemangle("demangle", cl::init(false),
28 cl::desc("Print demangled function name."));
30 inline uint64_t KindFromData(uint64_t Data
, char SizeofPtr
) {
31 return Data
>> (SizeofPtr
* 8 - kSanitizerStatKindBits
);
34 inline uint64_t CountFromData(uint64_t Data
, char SizeofPtr
) {
35 return Data
& ((1ull << (SizeofPtr
* 8 - kSanitizerStatKindBits
)) - 1);
38 uint64_t ReadLE(char Size
, const char *Begin
, const char *End
) {
41 while (Begin
< End
&& Pos
!= Size
) {
42 Result
|= uint64_t(uint8_t(*Begin
)) << (Pos
* 8);
49 const char *ReadModule(char SizeofPtr
, const char *Begin
, const char *End
) {
50 const char *FilenameBegin
= Begin
;
51 while (Begin
!= End
&& *Begin
)
55 StringRef
Filename(FilenameBegin
, Begin
- FilenameBegin
);
61 symbolize::LLVMSymbolizer::Options SymbolizerOptions
;
62 SymbolizerOptions
.Demangle
= ClDemangle
;
63 SymbolizerOptions
.UseSymbolTable
= true;
64 symbolize::LLVMSymbolizer
Symbolizer(SymbolizerOptions
);
67 uint64_t Addr
= ReadLE(SizeofPtr
, Begin
, End
);
69 uint64_t Data
= ReadLE(SizeofPtr
, Begin
, End
);
74 if (Addr
== 0 && Data
== 0)
79 // As the instrumentation tracks the return address and not
80 // the address of the call to `__sanitizer_stat_report` we
81 // remove one from the address to get the correct DI.
82 if (Expected
<DILineInfo
> LineInfo
=
83 Symbolizer
.symbolizeCode(Filename
, Addr
- 1)) {
84 llvm::outs() << LineInfo
->FileName
<< ':' << LineInfo
->Line
<< ' '
85 << LineInfo
->FunctionName
<< ' ';
87 logAllUnhandledErrors(LineInfo
.takeError(), llvm::outs(), "<error> ");
90 switch (KindFromData(Data
, SizeofPtr
)) {
91 case SanStat_CFI_VCall
:
92 llvm::outs() << "cfi-vcall";
94 case SanStat_CFI_NVCall
:
95 llvm::outs() << "cfi-nvcall";
97 case SanStat_CFI_DerivedCast
:
98 llvm::outs() << "cfi-derived-cast";
100 case SanStat_CFI_UnrelatedCast
:
101 llvm::outs() << "cfi-unrelated-cast";
103 case SanStat_CFI_ICall
:
104 llvm::outs() << "cfi-icall";
107 llvm::outs() << "<unknown>";
111 llvm::outs() << " " << CountFromData(Data
, SizeofPtr
) << '\n';
115 int main(int argc
, char **argv
) {
116 cl::ParseCommandLineOptions(argc
, argv
,
117 "Sanitizer Statistics Processing Tool");
119 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MBOrErr
=
120 MemoryBuffer::getFile(ClInputFile
, -1, false);
122 errs() << argv
[0] << ": " << ClInputFile
<< ": "
123 << MBOrErr
.getError().message() << '\n';
126 std::unique_ptr
<MemoryBuffer
> MB
= std::move(MBOrErr
.get());
127 const char *Begin
= MB
->getBufferStart(), *End
= MB
->getBufferEnd();
129 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
132 char SizeofPtr
= *Begin
++;
133 while (Begin
!= End
) {
134 Begin
= ReadModule(SizeofPtr
, Begin
, End
);
135 if (Begin
== nullptr) {
136 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
139 assert(Begin
<= End
);