forked from OSchip/llvm-project
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 llvm-svn: 257970
This commit is contained in:
parent
7f86ca1803
commit
f0f5e87083
|
@ -0,0 +1,56 @@
|
|||
//===- SanitizerStats.h - Sanitizer statistics gathering -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Declares functions and data structures for sanitizer statistics gathering.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H
|
||||
#define LLVM_TRANSFORMS_UTILS_SANITIZERSTATS_H
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Number of bits in data that are used for the sanitizer kind. Needs to match
|
||||
// __sanitizer::kKindBits in compiler-rt/lib/stats/stats.h
|
||||
enum { kSanitizerStatKindBits = 3 };
|
||||
|
||||
enum SanitizerStatKind {
|
||||
SanStat_CFI_VCall,
|
||||
SanStat_CFI_NVCall,
|
||||
SanStat_CFI_DerivedCast,
|
||||
SanStat_CFI_UnrelatedCast,
|
||||
SanStat_CFI_ICall,
|
||||
};
|
||||
|
||||
struct SanitizerStatReport {
|
||||
SanitizerStatReport(Module *M);
|
||||
|
||||
/// Generates code into B that increments a location-specific counter tagged
|
||||
/// with the given sanitizer kind SK.
|
||||
void create(IRBuilder<> &B, SanitizerStatKind SK);
|
||||
|
||||
/// Finalize module stats array and add global constructor to register it.
|
||||
void finish();
|
||||
|
||||
private:
|
||||
Module *M;
|
||||
GlobalVariable *ModuleStatsGV;
|
||||
ArrayType *StatTy;
|
||||
StructType *EmptyModuleStatsTy;
|
||||
|
||||
std::vector<Constant *> Inits;
|
||||
ArrayType *makeModuleStatsArrayTy();
|
||||
StructType *makeModuleStatsTy();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -30,6 +30,7 @@ add_llvm_library(LLVMTransformUtils
|
|||
ModuleUtils.cpp
|
||||
PromoteMemoryToRegister.cpp
|
||||
SSAUpdater.cpp
|
||||
SanitizerStats.cpp
|
||||
SimplifyCFG.cpp
|
||||
SimplifyIndVar.cpp
|
||||
SimplifyInstructions.cpp
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
//===- SanitizerStats.cpp - Sanitizer statistics gathering ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements code generation for sanitizer statistics gathering.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
SanitizerStatReport::SanitizerStatReport(Module *M) : M(M) {
|
||||
StatTy = ArrayType::get(Type::getInt8PtrTy(M->getContext()), 2);
|
||||
EmptyModuleStatsTy = makeModuleStatsTy();
|
||||
|
||||
ModuleStatsGV = new GlobalVariable(*M, EmptyModuleStatsTy, false,
|
||||
GlobalValue::InternalLinkage, 0);
|
||||
}
|
||||
|
||||
ArrayType *SanitizerStatReport::makeModuleStatsArrayTy() {
|
||||
return ArrayType::get(StatTy, Inits.size());
|
||||
}
|
||||
|
||||
StructType *SanitizerStatReport::makeModuleStatsTy() {
|
||||
return StructType::get(M->getContext(), {Type::getInt8PtrTy(M->getContext()),
|
||||
Type::getInt32Ty(M->getContext()),
|
||||
makeModuleStatsArrayTy()});
|
||||
}
|
||||
|
||||
void SanitizerStatReport::create(IRBuilder<> &B, SanitizerStatKind SK) {
|
||||
Function *F = B.GetInsertBlock()->getParent();
|
||||
Module *M = F->getParent();
|
||||
PointerType *Int8PtrTy = B.getInt8PtrTy();
|
||||
IntegerType *IntPtrTy = B.getIntPtrTy(M->getDataLayout());
|
||||
ArrayType *StatTy = ArrayType::get(Int8PtrTy, 2);
|
||||
|
||||
Inits.push_back(ConstantArray::get(
|
||||
StatTy,
|
||||
{Constant::getNullValue(Int8PtrTy),
|
||||
ConstantExpr::getIntToPtr(
|
||||
ConstantInt::get(IntPtrTy, uint64_t(SK) << (IntPtrTy->getBitWidth() -
|
||||
kSanitizerStatKindBits)),
|
||||
Int8PtrTy)}));
|
||||
|
||||
FunctionType *StatReportTy =
|
||||
FunctionType::get(B.getVoidTy(), Int8PtrTy, false);
|
||||
Constant *StatReport = M->getOrInsertFunction(
|
||||
"__sanitizer_stat_report", StatReportTy);
|
||||
|
||||
auto InitAddr = ConstantExpr::getGetElementPtr(
|
||||
EmptyModuleStatsTy, ModuleStatsGV,
|
||||
ArrayRef<Constant *>{
|
||||
ConstantInt::get(IntPtrTy, 0), ConstantInt::get(B.getInt32Ty(), 2),
|
||||
ConstantInt::get(IntPtrTy, Inits.size() - 1),
|
||||
});
|
||||
B.CreateCall(StatReport, ConstantExpr::getBitCast(InitAddr, Int8PtrTy));
|
||||
}
|
||||
|
||||
void SanitizerStatReport::finish() {
|
||||
if (Inits.empty()) {
|
||||
ModuleStatsGV->eraseFromParent();
|
||||
return;
|
||||
}
|
||||
|
||||
PointerType *Int8PtrTy = Type::getInt8PtrTy(M->getContext());
|
||||
IntegerType *Int32Ty = Type::getInt32Ty(M->getContext());
|
||||
Type *VoidTy = Type::getVoidTy(M->getContext());
|
||||
|
||||
// Create a new ModuleStatsGV to replace the old one. We can't just set the
|
||||
// old one's initializer because its type is different.
|
||||
auto NewModuleStatsGV = new GlobalVariable(
|
||||
*M, makeModuleStatsTy(), false, GlobalValue::InternalLinkage,
|
||||
ConstantStruct::getAnon(
|
||||
{Constant::getNullValue(Int8PtrTy),
|
||||
ConstantInt::get(Int32Ty, Inits.size()),
|
||||
ConstantArray::get(makeModuleStatsArrayTy(), Inits)}));
|
||||
ModuleStatsGV->replaceAllUsesWith(
|
||||
ConstantExpr::getBitCast(NewModuleStatsGV, ModuleStatsGV->getType()));
|
||||
ModuleStatsGV->eraseFromParent();
|
||||
|
||||
// Create a global constructor to register NewModuleStatsGV.
|
||||
auto F = Function::Create(FunctionType::get(VoidTy, false),
|
||||
GlobalValue::InternalLinkage, "", M);
|
||||
auto BB = BasicBlock::Create(M->getContext(), "", F);
|
||||
IRBuilder<> B(BB);
|
||||
|
||||
FunctionType *StatInitTy = FunctionType::get(VoidTy, Int8PtrTy, false);
|
||||
Constant *StatInit = M->getOrInsertFunction(
|
||||
"__sanitizer_stat_init", StatInitTy);
|
||||
|
||||
B.CreateCall(StatInit, ConstantExpr::getBitCast(NewModuleStatsGV, Int8PtrTy));
|
||||
B.CreateRetVoid();
|
||||
|
||||
appendToGlobalCtors(*M, F, 0);
|
||||
}
|
|
@ -61,6 +61,7 @@ set(LLVM_TEST_DEPENDS
|
|||
obj2yaml
|
||||
opt
|
||||
sancov
|
||||
sanstats
|
||||
verify-uselistorder
|
||||
yaml-bench
|
||||
yaml2obj
|
||||
|
|
|
@ -282,6 +282,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
|
|||
r"\bFileCheck\b",
|
||||
r"\bobj2yaml\b",
|
||||
NOJUNK + r"\bsancov\b",
|
||||
NOJUNK + r"\bsanstats\b",
|
||||
r"\byaml2obj\b",
|
||||
r"\byaml-bench\b",
|
||||
r"\bverify-uselistorder\b",
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
# RUN: yaml2obj -format=elf %s > %t1.o
|
||||
# RUN: yaml2obj -format=elf %s > %t2.o
|
||||
|
||||
# RUN: echo -ne "\x04" > %t.stats
|
||||
|
||||
# RUN: echo -n "%t1.o" >> %t.stats
|
||||
# RUN: echo -ne "\x00" >> %t.stats
|
||||
# RUN: echo -ne "\x01\x00\x00\x00\x01\x00\x00\x00" >> %t.stats
|
||||
# RUN: echo -ne "\x11\x00\x00\x00\x02\x00\x00\x20" >> %t.stats
|
||||
# RUN: echo -ne "\x21\x00\x00\x00\x03\x00\x00\x40" >> %t.stats
|
||||
# RUN: echo -ne "\x01\x00\x00\x00\x04\x00\x00\x60" >> %t.stats
|
||||
# RUN: echo -ne "\x11\x00\x00\x00\x05\x00\x00\x80" >> %t.stats
|
||||
# RUN: echo -ne "\x21\x00\x00\x00\x06\x00\x00\xa0" >> %t.stats
|
||||
# RUN: echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" >> %t.stats
|
||||
|
||||
# RUN: echo -n "%t2.o" >> %t.stats
|
||||
# RUN: echo -ne "\x00" >> %t.stats
|
||||
# RUN: echo -ne "\x21\x00\x00\x00\x07\x00\x00\x00" >> %t.stats
|
||||
# RUN: echo -ne "\x11\x00\x00\x00\x08\x00\x00\x20" >> %t.stats
|
||||
# RUN: echo -ne "\x01\x00\x00\x00\x09\x00\x00\x40" >> %t.stats
|
||||
# RUN: echo -ne "\x21\x00\x00\x00\x0b\x00\x00\x60" >> %t.stats
|
||||
# RUN: echo -ne "\x11\x00\x00\x00\x0c\x00\x00\x80" >> %t.stats
|
||||
# RUN: echo -ne "\x01\x00\x00\x00\x0e\x00\x00\xa0" >> %t.stats
|
||||
# RUN: echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" >> %t.stats
|
||||
|
||||
# RUN: sanstats %t.stats | FileCheck %s
|
||||
|
||||
# CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-vcall 1
|
||||
# CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-nvcall 2
|
||||
# CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-derived-cast 3
|
||||
# CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-unrelated-cast 4
|
||||
# CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-icall 5
|
||||
# CHECK: /tmp{{[/\\]}}f.c:3 f3 <unknown> 6
|
||||
|
||||
# CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-vcall 7
|
||||
# CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-nvcall 8
|
||||
# CHECK: /tmp{{[/\\]}}f.c:1 f1 cfi-derived-cast 9
|
||||
# CHECK: /tmp{{[/\\]}}f.c:3 f3 cfi-unrelated-cast 11
|
||||
# CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-icall 12
|
||||
# CHECK: /tmp{{[/\\]}}f.c:1 f1 <unknown> 14
|
||||
|
||||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: 554889E55DC3662E0F1F840000000000554889E55DC3662E0F1F840000000000554889E55DC3
|
||||
- Name: .debug_str
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_MERGE, SHF_STRINGS ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 636C616E672076657273696F6E20332E382E3020287472756E6B203235353339332920286C6C766D2F7472756E6B203235353734352900662E63002F746D7000663100663200663300
|
||||
- Name: .debug_loc
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .debug_abbrev
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 011101250E1305030E10171B0E110112060000022E00110112064018030E3A0B3B0B3F19000000
|
||||
- Name: .debug_info
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 660000000400000000000801000000000C0000000000000000000000000000000000000000002600000002000000000000000006000000015600000000010102000000000000000006000000015600000000010202000000000000000006000000015600000000010300
|
||||
- Name: .rela.debug_info
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .debug_info
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000006
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
- Offset: 0x000000000000000C
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
- Offset: 0x0000000000000012
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
Addend: 55
|
||||
- Offset: 0x0000000000000016
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
- Offset: 0x000000000000001A
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
Addend: 59
|
||||
- Offset: 0x000000000000001E
|
||||
Symbol: ''
|
||||
Type: R_X86_64_64
|
||||
- Offset: 0x000000000000002B
|
||||
Symbol: ''
|
||||
Type: R_X86_64_64
|
||||
- Offset: 0x0000000000000039
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
Addend: 64
|
||||
- Offset: 0x0000000000000040
|
||||
Symbol: ''
|
||||
Type: R_X86_64_64
|
||||
Addend: 16
|
||||
- Offset: 0x000000000000004E
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
Addend: 67
|
||||
- Offset: 0x0000000000000055
|
||||
Symbol: ''
|
||||
Type: R_X86_64_64
|
||||
Addend: 32
|
||||
- Offset: 0x0000000000000063
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
Addend: 70
|
||||
- Name: .debug_ranges
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .debug_pubnames
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 230000000200000000006A0000002A0000006631003F0000006632005400000066330000000000
|
||||
- Name: .rela.debug_pubnames
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .debug_pubnames
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000006
|
||||
Symbol: ''
|
||||
Type: R_X86_64_32
|
||||
- Name: .comment
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_MERGE, SHF_STRINGS ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 00636C616E672076657273696F6E20332E382E3020287472756E6B203235353339332920286C6C766D2F7472756E6B203235353734352900
|
||||
- Name: .note.GNU-stack
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .eh_frame
|
||||
Type: SHT_X86_64_UNWIND
|
||||
Flags: [ SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000008
|
||||
Content: 1400000000000000017A5200017810011B0C070890010000180000001C000000000000000600000000410E108602430D060000001800000038000000000000000600000000410E108602430D060000001C00000054000000000000000600000000410E108602430D0600000000000000
|
||||
- Name: .rela.eh_frame
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .eh_frame
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000020
|
||||
Symbol: ''
|
||||
Type: R_X86_64_PC32
|
||||
- Offset: 0x000000000000003C
|
||||
Symbol: ''
|
||||
Type: R_X86_64_PC32
|
||||
Addend: 16
|
||||
- Offset: 0x0000000000000058
|
||||
Symbol: ''
|
||||
Type: R_X86_64_PC32
|
||||
Addend: 32
|
||||
- Name: .debug_line
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: 4300000002001A0000000101FB0E0D00010101010000000100000100662E630000000000000902000000000000000001050C0A4A0500BB050C0A4A0500BB050C0A4A0202000101
|
||||
- Name: .rela.debug_line
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .debug_line
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000027
|
||||
Symbol: ''
|
||||
Type: R_X86_64_64
|
||||
Symbols:
|
||||
Local:
|
||||
- Name: f.c
|
||||
Type: STT_FILE
|
||||
- Type: STT_SECTION
|
||||
Section: .text
|
||||
- Type: STT_SECTION
|
||||
Section: .debug_str
|
||||
- Type: STT_SECTION
|
||||
Section: .debug_abbrev
|
||||
- Type: STT_SECTION
|
||||
Section: .debug_info
|
||||
- Type: STT_SECTION
|
||||
Section: .debug_line
|
||||
Global:
|
||||
- Name: f1
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Size: 0x0000000000000006
|
||||
- Name: f2
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0000000000000010
|
||||
Size: 0x0000000000000006
|
||||
- Name: f3
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0000000000000020
|
||||
Size: 0x0000000000000006
|
||||
...
|
|
@ -33,7 +33,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \
|
|||
llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
|
||||
llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
|
||||
llvm-cxxdump verify-uselistorder dsymutil llvm-pdbdump \
|
||||
llvm-split sancov llvm-dwp
|
||||
llvm-split sancov sanstats llvm-dwp
|
||||
|
||||
# If Intel JIT Events support is configured, build an extra tool to test it.
|
||||
ifeq ($(USE_INTEL_JITEVENTS), 1)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Support
|
||||
Symbolize
|
||||
)
|
||||
|
||||
add_llvm_tool(sanstats
|
||||
sanstats.cpp
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
##===- tools/sanstats/Makefile -----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL := ../..
|
||||
TOOLNAME := sanstats
|
||||
LINK_COMPONENTS := Support Symbolize
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS := 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
|
@ -0,0 +1,138 @@
|
|||
//===- sanstats.cpp - Sanitizer statistics dumper -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tool dumps statistics information from files in the format produced
|
||||
// by clang's -fsanitize-stats feature.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Transforms/Utils/SanitizerStats.h"
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string> ClInputFile(cl::Positional, cl::Required,
|
||||
cl::desc("<filename>"));
|
||||
|
||||
static cl::opt<bool> ClDemangle("demangle", cl::init(false),
|
||||
cl::desc("Print demangled function name."));
|
||||
|
||||
inline uint64_t KindFromData(uint64_t Data, char SizeofPtr) {
|
||||
return Data >> (SizeofPtr * 8 - kSanitizerStatKindBits);
|
||||
}
|
||||
|
||||
inline uint64_t CountFromData(uint64_t Data, char SizeofPtr) {
|
||||
return Data & ((1ull << (SizeofPtr * 8 - kSanitizerStatKindBits)) - 1);
|
||||
}
|
||||
|
||||
uint64_t ReadLE(char Size, const char *Begin, const char *End) {
|
||||
uint64_t Result = 0;
|
||||
char Pos = 0;
|
||||
while (Begin < End && Pos != Size) {
|
||||
Result |= uint64_t(uint8_t(*Begin)) << (Pos * 8);
|
||||
++Begin;
|
||||
++Pos;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
const char *ReadModule(char SizeofPtr, const char *Begin, const char *End) {
|
||||
const char *FilenameBegin = Begin;
|
||||
while (Begin != End && *Begin)
|
||||
++Begin;
|
||||
if (Begin == End)
|
||||
return 0;
|
||||
StringRef Filename(FilenameBegin, Begin - FilenameBegin);
|
||||
|
||||
++Begin;
|
||||
if (Begin == End)
|
||||
return 0;
|
||||
|
||||
symbolize::LLVMSymbolizer::Options SymbolizerOptions;
|
||||
SymbolizerOptions.Demangle = ClDemangle;
|
||||
SymbolizerOptions.UseSymbolTable = true;
|
||||
symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions);
|
||||
|
||||
while (1) {
|
||||
uint64_t Addr = ReadLE(SizeofPtr, Begin, End);
|
||||
Begin += SizeofPtr;
|
||||
uint64_t Data = ReadLE(SizeofPtr, Begin, End);
|
||||
Begin += SizeofPtr;
|
||||
|
||||
if (Begin > End)
|
||||
return 0;
|
||||
if (Addr == 0 && Data == 0)
|
||||
return Begin;
|
||||
if (Begin == End)
|
||||
return 0;
|
||||
|
||||
ErrorOr<DILineInfo> LineInfo = Symbolizer.symbolizeCode(Filename, Addr);
|
||||
if (LineInfo) {
|
||||
llvm::outs() << LineInfo->FileName << ':' << LineInfo->Line << ' '
|
||||
<< LineInfo->FunctionName << ' ';
|
||||
} else {
|
||||
llvm::outs() << "<error> ";
|
||||
}
|
||||
|
||||
switch (KindFromData(Data, SizeofPtr)) {
|
||||
case SanStat_CFI_VCall:
|
||||
llvm::outs() << "cfi-vcall";
|
||||
break;
|
||||
case SanStat_CFI_NVCall:
|
||||
llvm::outs() << "cfi-nvcall";
|
||||
break;
|
||||
case SanStat_CFI_DerivedCast:
|
||||
llvm::outs() << "cfi-derived-cast";
|
||||
break;
|
||||
case SanStat_CFI_UnrelatedCast:
|
||||
llvm::outs() << "cfi-unrelated-cast";
|
||||
break;
|
||||
case SanStat_CFI_ICall:
|
||||
llvm::outs() << "cfi-icall";
|
||||
break;
|
||||
default:
|
||||
llvm::outs() << "<unknown>";
|
||||
break;
|
||||
}
|
||||
|
||||
llvm::outs() << " " << CountFromData(Data, SizeofPtr) << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"Sanitizer Statistics Processing Tool");
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
|
||||
MemoryBuffer::getFile(ClInputFile, -1, false);
|
||||
if (!MBOrErr) {
|
||||
errs() << argv[0] << ": " << ClInputFile << ": "
|
||||
<< MBOrErr.getError().message() << '\n';
|
||||
return 1;
|
||||
}
|
||||
std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
|
||||
const char *Begin = MB->getBufferStart(), *End = MB->getBufferEnd();
|
||||
if (Begin == End) {
|
||||
errs() << argv[0] << ": " << ClInputFile << ": short read\n";
|
||||
return 1;
|
||||
}
|
||||
char SizeofPtr = *Begin++;
|
||||
while (Begin != End) {
|
||||
Begin = ReadModule(SizeofPtr, Begin, End);
|
||||
if (Begin == 0) {
|
||||
errs() << argv[0] << ": " << ClInputFile << ": short read\n";
|
||||
return 1;
|
||||
}
|
||||
assert(Begin <= End);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue