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::OptionCategory
Cat("sanstats Options");
28 static cl::opt
<std::string
> ClInputFile(cl::Positional
, cl::Required
,
29 cl::desc("<filename>"));
31 static cl::opt
<bool> ClDemangle("demangle", cl::init(false),
32 cl::desc("Print demangled function name"),
35 inline uint64_t KindFromData(uint64_t Data
, char SizeofPtr
) {
36 return Data
>> (SizeofPtr
* 8 - kSanitizerStatKindBits
);
39 inline uint64_t CountFromData(uint64_t Data
, char SizeofPtr
) {
40 return Data
& ((1ull << (SizeofPtr
* 8 - kSanitizerStatKindBits
)) - 1);
43 static uint64_t ReadLE(char Size
, const char *Begin
, const char *End
) {
46 while (Begin
< End
&& Pos
!= Size
) {
47 Result
|= uint64_t(uint8_t(*Begin
)) << (Pos
* 8);
54 static const char *ReadModule(char SizeofPtr
, const char *Begin
,
56 const char *FilenameBegin
= Begin
;
57 while (Begin
!= End
&& *Begin
)
61 std::string
Filename(FilenameBegin
, Begin
- FilenameBegin
);
63 if (!llvm::sys::fs::exists(Filename
))
64 Filename
= std::string(llvm::sys::path::parent_path(ClInputFile
)) +
65 std::string(llvm::sys::path::filename(Filename
));
71 symbolize::LLVMSymbolizer::Options SymbolizerOptions
;
72 SymbolizerOptions
.Demangle
= ClDemangle
;
73 SymbolizerOptions
.UseSymbolTable
= true;
74 symbolize::LLVMSymbolizer
Symbolizer(SymbolizerOptions
);
77 uint64_t Addr
= ReadLE(SizeofPtr
, Begin
, End
);
79 uint64_t Data
= ReadLE(SizeofPtr
, Begin
, End
);
84 if (Addr
== 0 && Data
== 0)
89 // As the instrumentation tracks the return address and not
90 // the address of the call to `__sanitizer_stat_report` we
91 // remove one from the address to get the correct DI.
92 // TODO: it would be neccessary to set proper section index here.
93 // object::SectionedAddress::UndefSection works for only absolute addresses.
94 if (Expected
<DILineInfo
> LineInfo
= Symbolizer
.symbolizeCode(
95 Filename
, {Addr
- 1, object::SectionedAddress::UndefSection
})) {
96 llvm::outs() << format_hex(Addr
- 1, 18) << ' ' << LineInfo
->FileName
97 << ':' << LineInfo
->Line
<< ' ' << LineInfo
->FunctionName
100 logAllUnhandledErrors(LineInfo
.takeError(), llvm::outs(), "<error> ");
103 switch (KindFromData(Data
, SizeofPtr
)) {
104 case SanStat_CFI_VCall
:
105 llvm::outs() << "cfi-vcall";
107 case SanStat_CFI_NVCall
:
108 llvm::outs() << "cfi-nvcall";
110 case SanStat_CFI_DerivedCast
:
111 llvm::outs() << "cfi-derived-cast";
113 case SanStat_CFI_UnrelatedCast
:
114 llvm::outs() << "cfi-unrelated-cast";
116 case SanStat_CFI_ICall
:
117 llvm::outs() << "cfi-icall";
120 llvm::outs() << "<unknown>";
124 llvm::outs() << " " << CountFromData(Data
, SizeofPtr
) << '\n';
128 int main(int argc
, char **argv
) {
129 cl::HideUnrelatedOptions(Cat
);
130 cl::ParseCommandLineOptions(argc
, argv
,
131 "Sanitizer Statistics Processing Tool");
133 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MBOrErr
= MemoryBuffer::getFile(
134 ClInputFile
, /*IsText=*/false, /*RequiresNullTerminator=*/false);
136 errs() << argv
[0] << ": " << ClInputFile
<< ": "
137 << MBOrErr
.getError().message() << '\n';
140 std::unique_ptr
<MemoryBuffer
> MB
= std::move(MBOrErr
.get());
141 const char *Begin
= MB
->getBufferStart(), *End
= MB
->getBufferEnd();
143 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
146 char SizeofPtr
= *Begin
++;
147 while (Begin
!= End
) {
148 Begin
= ReadModule(SizeofPtr
, Begin
, End
);
149 if (Begin
== nullptr) {
150 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
153 assert(Begin
<= End
);