reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
//===- sanstats.cpp - Sanitizer statistics dumper -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// 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/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.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 nullptr;
  std::string Filename(FilenameBegin, Begin - FilenameBegin);

  if (!llvm::sys::fs::exists(Filename))
    Filename = std::string(llvm::sys::path::parent_path(ClInputFile)) +
               std::string(llvm::sys::path::filename(Filename));

  ++Begin;
  if (Begin == End)
    return nullptr;

  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 nullptr;
    if (Addr == 0 && Data == 0)
      return Begin;
    if (Begin == End)
      return nullptr;

    // As the instrumentation tracks the return address and not
    // the address of the call to `__sanitizer_stat_report` we
    // remove one from the address to get the correct DI.
    // TODO: it would be neccessary to set proper section index here.
    // object::SectionedAddress::UndefSection works for only absolute addresses.
    if (Expected<DILineInfo> LineInfo = Symbolizer.symbolizeCode(
            Filename, {Addr - 1, object::SectionedAddress::UndefSection})) {
      llvm::outs() << format_hex(Addr - 1, 18) << ' ' << LineInfo->FileName
                   << ':' << LineInfo->Line << ' ' << LineInfo->FunctionName
                   << ' ';
    } else {
      logAllUnhandledErrors(LineInfo.takeError(), 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 == nullptr) {
      errs() << argv[0] << ": " << ClInputFile << ": short read\n";
      return 1;
    }
    assert(Begin <= End);
  }
}