//===- subzero/src/IceASanInstrumentation.h - AddressSanitizer --*- C++ -*-===//
//
//                        The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Declares the AddressSanitizer instrumentation class.
///
/// This class is responsible for inserting redzones around global and stack
/// variables, inserting code responsible for poisoning those redzones, and
/// performing any other instrumentation necessary to implement
/// AddressSanitizer.
///
//===----------------------------------------------------------------------===//

#ifndef SUBZERO_SRC_ICEASANINSTRUMENTATION_H
#define SUBZERO_SRC_ICEASANINSTRUMENTATION_H

#include "IceGlobalInits.h"
#include "IceInstrumentation.h"

namespace Ice {

using VarSizeMap = std::unordered_map<Operand *, SizeT>;
using GlobalSizeMap = std::unordered_map<GlobalString, SizeT>;

class ASanInstrumentation : public Instrumentation {
  ASanInstrumentation() = delete;
  ASanInstrumentation(const ASanInstrumentation &) = delete;
  ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;

public:
  ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {
    ICE_TLS_INIT_FIELD(LocalVars);
    ICE_TLS_INIT_FIELD(LocalDtors);
    ICE_TLS_INIT_FIELD(CurNode);
    ICE_TLS_INIT_FIELD(CheckedVars);
  }
  void instrumentGlobals(VariableDeclarationList &Globals) override;

private:
  std::string nextRzName();
  bool isOkGlobalAccess(Operand *Op, SizeT Size);
  ConstantRelocatable *instrumentReloc(ConstantRelocatable *Reloc);
  bool isInstrumentable(Cfg *Func) override;
  void instrumentFuncStart(LoweringContext &Context) override;
  void instrumentCall(LoweringContext &Context, InstCall *Instr) override;
  void instrumentRet(LoweringContext &Context, InstRet *Instr) override;
  void instrumentLoad(LoweringContext &Context, InstLoad *Instr) override;
  void instrumentStore(LoweringContext &Context, InstStore *Instr) override;
  void instrumentAccess(LoweringContext &Context, Operand *Op, SizeT Size,
                        Constant *AccessFunc);
  void instrumentStart(Cfg *Func) override;
  void finishFunc(Cfg *Func) override;
  ICE_TLS_DECLARE_FIELD(VarSizeMap *, LocalVars);
  ICE_TLS_DECLARE_FIELD(std::vector<InstStore *> *, LocalDtors);
  ICE_TLS_DECLARE_FIELD(CfgNode *, CurNode);
  ICE_TLS_DECLARE_FIELD(VarSizeMap *, CheckedVars);
  GlobalSizeMap GlobalSizes;
  std::atomic<uint32_t> RzNum;
  bool DidProcessGlobals = false;
  SizeT RzGlobalsNum = 0;
  std::mutex GlobalsMutex;
};
} // end of namespace Ice

#endif // SUBZERO_SRC_ICEASANINSTRUMENTATION_H