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/Symbolize.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/ErrorOr.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Transforms/Utils/SanitizerStats.h"
25 static cl::opt
<std::string
> ClInputFile(cl::Positional
, cl::Required
,
26 cl::desc("<filename>"));
28 static cl::opt
<bool> ClDemangle("demangle", cl::init(false),
29 cl::desc("Print demangled function name."));
31 inline uint64_t KindFromData(uint64_t Data
, char SizeofPtr
) {
32 return Data
>> (SizeofPtr
* 8 - kSanitizerStatKindBits
);
35 inline uint64_t CountFromData(uint64_t Data
, char SizeofPtr
) {
36 return Data
& ((1ull << (SizeofPtr
* 8 - kSanitizerStatKindBits
)) - 1);
39 uint64_t ReadLE(char Size
, const char *Begin
, const char *End
) {
42 while (Begin
< End
&& Pos
!= Size
) {
43 Result
|= uint64_t(uint8_t(*Begin
)) << (Pos
* 8);
50 const char *ReadModule(char SizeofPtr
, const char *Begin
, const char *End
) {
51 const char *FilenameBegin
= Begin
;
52 while (Begin
!= End
&& *Begin
)
56 std::string
Filename(FilenameBegin
, Begin
- FilenameBegin
);
58 if (!llvm::sys::fs::exists(Filename
))
59 Filename
= std::string(llvm::sys::path::parent_path(ClInputFile
)) +
60 std::string(llvm::sys::path::filename(Filename
));
66 symbolize::LLVMSymbolizer::Options SymbolizerOptions
;
67 SymbolizerOptions
.Demangle
= ClDemangle
;
68 SymbolizerOptions
.UseSymbolTable
= true;
69 symbolize::LLVMSymbolizer
Symbolizer(SymbolizerOptions
);
72 uint64_t Addr
= ReadLE(SizeofPtr
, Begin
, End
);
74 uint64_t Data
= ReadLE(SizeofPtr
, Begin
, End
);
79 if (Addr
== 0 && Data
== 0)
84 // As the instrumentation tracks the return address and not
85 // the address of the call to `__sanitizer_stat_report` we
86 // remove one from the address to get the correct DI.
87 // TODO: it would be neccessary to set proper section index here.
88 // object::SectionedAddress::UndefSection works for only absolute addresses.
89 if (Expected
<DILineInfo
> LineInfo
= Symbolizer
.symbolizeCode(
90 Filename
, {Addr
- 1, object::SectionedAddress::UndefSection
})) {
91 llvm::outs() << format_hex(Addr
- 1, 18) << ' ' << LineInfo
->FileName
92 << ':' << LineInfo
->Line
<< ' ' << LineInfo
->FunctionName
95 logAllUnhandledErrors(LineInfo
.takeError(), llvm::outs(), "<error> ");
98 switch (KindFromData(Data
, SizeofPtr
)) {
99 case SanStat_CFI_VCall
:
100 llvm::outs() << "cfi-vcall";
102 case SanStat_CFI_NVCall
:
103 llvm::outs() << "cfi-nvcall";
105 case SanStat_CFI_DerivedCast
:
106 llvm::outs() << "cfi-derived-cast";
108 case SanStat_CFI_UnrelatedCast
:
109 llvm::outs() << "cfi-unrelated-cast";
111 case SanStat_CFI_ICall
:
112 llvm::outs() << "cfi-icall";
115 llvm::outs() << "<unknown>";
119 llvm::outs() << " " << CountFromData(Data
, SizeofPtr
) << '\n';
123 int main(int argc
, char **argv
) {
124 cl::ParseCommandLineOptions(argc
, argv
,
125 "Sanitizer Statistics Processing Tool");
127 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MBOrErr
=
128 MemoryBuffer::getFile(ClInputFile
, -1, false);
130 errs() << argv
[0] << ": " << ClInputFile
<< ": "
131 << MBOrErr
.getError().message() << '\n';
134 std::unique_ptr
<MemoryBuffer
> MB
= std::move(MBOrErr
.get());
135 const char *Begin
= MB
->getBufferStart(), *End
= MB
->getBufferEnd();
137 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
140 char SizeofPtr
= *Begin
++;
141 while (Begin
!= End
) {
142 Begin
= ReadModule(SizeofPtr
, Begin
, End
);
143 if (Begin
== nullptr) {
144 errs() << argv
[0] << ": " << ClInputFile
<< ": short read\n";
147 assert(Begin
<= End
);