1 //===- sanstats.cpp - Sanitizer statistics dumper -------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This tool dumps statistics information from files in the format produced
10 // by clang's -fsanitize-stats feature.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
15 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/ErrorOr.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Transforms/Utils/SanitizerStats.h"
26 static cl::opt
<std::string
> ClInputFile(cl::Positional
, cl::Required
,
27 cl::desc("<filename>"));
29 static cl::opt
<bool> ClDemangle("demangle", cl::init(false),
30 cl::desc("Print demangled function name."));
32 inline uint64_t KindFromData(uint64_t Data
, char SizeofPtr
) {
33 return Data
>> (SizeofPtr
* 8 - kSanitizerStatKindBits
);
36 inline uint64_t CountFromData(uint64_t Data
, char SizeofPtr
) {
37 return Data
& ((1ull << (SizeofPtr
* 8 - kSanitizerStatKindBits
)) - 1);
40 static uint64_t ReadLE(char Size
, const char *Begin
, const char *End
) {
43 while (Begin
< End
&& Pos
!= Size
) {
44 Result
|= uint64_t(uint8_t(*Begin
)) << (Pos
* 8);
51 static const char *ReadModule(char SizeofPtr
, const char *Begin
,
53 const char *FilenameBegin
= Begin
;
54 while (Begin
!= End
&& *Begin
)
58 std::string
Filename(FilenameBegin
, Begin
- FilenameBegin
);
60 if (!llvm::sys::fs::exists(Filename
))
61 Filename
= std::string(llvm::sys::path::parent_path(ClInputFile
)) +
62 std::string(llvm::sys::path::filename(Filename
));
68 symbolize::LLVMSymbolizer::Options SymbolizerOptions
;
69 SymbolizerOptions
.Demangle
= ClDemangle
;
70 SymbolizerOptions
.UseSymbolTable
= true;
71 symbolize::LLVMSymbolizer
Symbolizer(SymbolizerOptions
);
74 uint64_t Addr
= ReadLE(SizeofPtr
, Begin
, End
);
76 uint64_t Data
= ReadLE(SizeofPtr
, Begin
, End
);
81 if (Addr
== 0 && Data
== 0)
86 // As the instrumentation tracks the return address and not
87 // the address of the call to `__sanitizer_stat_report` we
88 // remove one from the address to get the correct DI.
89 // TODO: it would be neccessary to set proper section index here.
90 // object::SectionedAddress::UndefSection works for only absolute addresses.
91 if (Expected
<DILineInfo
> LineInfo
= Symbolizer
.symbolizeCode(
92 Filename
, {Addr
- 1, object::SectionedAddress::UndefSection
})) {
93 llvm::outs() << format_hex(Addr
- 1, 18) << ' ' << LineInfo
->FileName
94 << ':' << LineInfo
->Line
<< ' ' << LineInfo
->FunctionName
97 logAllUnhandledErrors(LineInfo
.takeError(), llvm::outs(), "<error> ");
100 switch (KindFromData(Data
, SizeofPtr
)) {
101 case SanStat_CFI_VCall
:
102 llvm::outs() << "cfi-vcall";
104 case SanStat_CFI_NVCall
:
105 llvm::outs() << "cfi-nvcall";
107 case SanStat_CFI_DerivedCast
:
108 llvm::outs() << "cfi-derived-cast";
110 case SanStat_CFI_UnrelatedCast
:
111 llvm::outs() << "cfi-unrelated-cast";
113 case SanStat_CFI_ICall
:
114 llvm::outs() << "cfi-icall";
117 llvm::outs() << "<unknown>";
121 llvm::outs() << " " << CountFromData(Data
, SizeofPtr
) << '\n';
125 int main(int argc
, char **argv
) {
126 cl::ParseCommandLineOptions(argc
, argv
,
127 "Sanitizer Statistics Processing Tool");
129 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MBOrErr
= MemoryBuffer::getFile(
130 ClInputFile
, /*IsText=*/false, /*RequiresNullTerminator=*/false);
132 errs() << argv
[0] << ": " << ClInputFile
<< ": "
133 << MBOrErr
.getError().message() << '\n';
136 std::unique_ptr
<MemoryBuffer
> MB
= std::move(MBOrErr
.get());
137 const char *Begin
= MB
->getBufferStart(), *End
= MB
->getBufferEnd();
139 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
142 char SizeofPtr
= *Begin
++;
143 while (Begin
!= End
) {
144 Begin
= ReadModule(SizeofPtr
, Begin
, End
);
145 if (Begin
== nullptr) {
146 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
149 assert(Begin
<= End
);