//===-- NativeRegisterContext.h ---------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_NativeRegisterContext_h_
#define liblldb_NativeRegisterContext_h_

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Host/common/NativeWatchpointList.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

class NativeThreadProtocol;

class NativeRegisterContext
    : public std::enable_shared_from_this<NativeRegisterContext> {
public:
  //------------------------------------------------------------------
  // Constructors and Destructors
  //------------------------------------------------------------------
  NativeRegisterContext(NativeThreadProtocol &thread,
                        uint32_t concrete_frame_idx);

  virtual ~NativeRegisterContext();

  // void
  // InvalidateIfNeeded (bool force);

  //------------------------------------------------------------------
  // Subclasses must override these functions
  //------------------------------------------------------------------
  // virtual void
  // InvalidateAllRegisters () = 0;

  virtual uint32_t GetRegisterCount() const = 0;

  virtual uint32_t GetUserRegisterCount() const = 0;

  virtual const RegisterInfo *GetRegisterInfoAtIndex(uint32_t reg) const = 0;

  const char *GetRegisterSetNameForRegisterAtIndex(uint32_t reg_index) const;

  virtual uint32_t GetRegisterSetCount() const = 0;

  virtual const RegisterSet *GetRegisterSet(uint32_t set_index) const = 0;

  virtual Status ReadRegister(const RegisterInfo *reg_info,
                              RegisterValue &reg_value) = 0;

  virtual Status WriteRegister(const RegisterInfo *reg_info,
                               const RegisterValue &reg_value) = 0;

  virtual Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) = 0;

  virtual Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) = 0;

  uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind,
                                               uint32_t num) const;

  //------------------------------------------------------------------
  // Subclasses can override these functions if desired
  //------------------------------------------------------------------
  virtual uint32_t NumSupportedHardwareBreakpoints();

  virtual uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size);

  virtual bool ClearHardwareBreakpoint(uint32_t hw_idx);

  virtual Status ClearAllHardwareBreakpoints();

  virtual Status GetHardwareBreakHitIndex(uint32_t &bp_index,
                                          lldb::addr_t trap_addr);

  virtual uint32_t NumSupportedHardwareWatchpoints();

  virtual uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
                                         uint32_t watch_flags);

  virtual bool ClearHardwareWatchpoint(uint32_t hw_index);

  virtual Status ClearAllHardwareWatchpoints();

  virtual Status IsWatchpointHit(uint32_t wp_index, bool &is_hit);

  virtual Status GetWatchpointHitIndex(uint32_t &wp_index,
                                       lldb::addr_t trap_addr);

  virtual Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant);

  virtual lldb::addr_t GetWatchpointAddress(uint32_t wp_index);

  // MIPS Linux kernel returns a masked address (last 3bits are masked)
  // when a HW watchpoint is hit. However user may not have set a watchpoint
  // on this address. This function emulates the instruction at PC and
  // finds the base address used in the load/store instruction. This gives the
  // exact address used to read/write the variable being watched.
  // For example:
  // 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at
  // 'm',
  // then watch exception is generated even when 'n' is read/written. This
  // function
  // returns address of 'n' so that client can check whether a watchpoint is set
  // on this address or not.
  virtual lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index);

  virtual bool HardwareSingleStep(bool enable);

  virtual Status
  ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
                              lldb::addr_t src_addr, size_t src_len,
                              RegisterValue &reg_value);

  virtual Status
  WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
                             lldb::addr_t dst_addr, size_t dst_len,
                             const RegisterValue &reg_value);

  //------------------------------------------------------------------
  // Subclasses should not override these
  //------------------------------------------------------------------
  virtual lldb::tid_t GetThreadID() const;

  virtual NativeThreadProtocol &GetThread() { return m_thread; }

  const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name,
                                            uint32_t start_idx = 0);

  const RegisterInfo *GetRegisterInfo(uint32_t reg_kind, uint32_t reg_num);

  lldb::addr_t GetPC(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);

  virtual lldb::addr_t
  GetPCfromBreakpointLocation(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);

  Status SetPC(lldb::addr_t pc);

  lldb::addr_t GetSP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);

  Status SetSP(lldb::addr_t sp);

  lldb::addr_t GetFP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);

  Status SetFP(lldb::addr_t fp);

  const char *GetRegisterName(uint32_t reg);

  lldb::addr_t GetReturnAddress(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);

  lldb::addr_t GetFlags(lldb::addr_t fail_value = 0);

  lldb::addr_t ReadRegisterAsUnsigned(uint32_t reg, lldb::addr_t fail_value);

  lldb::addr_t ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
                                      lldb::addr_t fail_value);

  Status WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval);

  Status WriteRegisterFromUnsigned(const RegisterInfo *reg_info, uint64_t uval);

  // uint32_t
  // GetStopID () const
  // {
  //     return m_stop_id;
  // }

  // void
  // SetStopID (uint32_t stop_id)
  // {
  //     m_stop_id = stop_id;
  // }

protected:
  //------------------------------------------------------------------
  // Classes that inherit from RegisterContext can see and modify these
  //------------------------------------------------------------------
  NativeThreadProtocol
      &m_thread; // The thread that this register context belongs to.
  uint32_t m_concrete_frame_idx; // The concrete frame index for this register
                                 // context
  // uint32_t m_stop_id;             // The stop ID that any data in this
  // context is valid for

private:
  //------------------------------------------------------------------
  // For RegisterContext only
  //------------------------------------------------------------------
  DISALLOW_COPY_AND_ASSIGN(NativeRegisterContext);
};

} // namespace lldb_private

#endif // liblldb_NativeRegisterContext_h_
