DavidSpickett created this revision.
Herald added subscribers: atanasyan, jrtc27.
Herald added a project: All.
DavidSpickett requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

In future I want to extend RegisterInfo and that will likely be non trivial
types like string and vector. RegisterInfo gets stored in Context, so Context
must be changed to a discriminated enum that properly calls destructors.

(which would be std::variant but although llvm is using -std=c++17 I don't
think we can expect c++17 library features just yet)

As so much existing code does this:
Context ctx;
// Lots of code that interacts with ctx...
ctx.Set<...>

I wasn't able to switch to factory functions for the Set<...> methods without a 
lot
more changes. Instead I've made the default constructor construct to the NoArgs 
type
and then Set<...> will change the type later.

Whenever you call a Set<...> it will destroy whatever is currently in the union
before setting the new data. Potentially non trivial types like RegisterInfos 
here are
placement newed because otherwise operator= would try to destroy the existing 
data
which is in fact uninitialised memory as far as we're concerned.

For the destructor we switch on the current info_type to know what to destruct.
(info_type that was made private in a previous change, so we know we have 
control of it)

Some places in lldb were using memset to initalise RegisterInfos. I tracked 
these
down with GCC's -Wclass-memaccess.
https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html#index-Wclass-memaccess

To replace these I've added sensible default values for each member in 
RegisterInfo
and filled kinds with LLDB_INVALID_REGNUM in the default constructor.

Depends on D134039 <https://reviews.llvm.org/D134039>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D134041

Files:
  lldb/include/lldb/Core/EmulateInstruction.h
  lldb/include/lldb/lldb-private-types.h
  lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
  lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
  lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
  lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
  lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
  lldb/source/Target/DynamicRegisterInfo.cpp

Index: lldb/source/Target/DynamicRegisterInfo.cpp
===================================================================
--- lldb/source/Target/DynamicRegisterInfo.cpp
+++ lldb/source/Target/DynamicRegisterInfo.cpp
@@ -236,7 +236,6 @@
     RegisterInfo reg_info;
     std::vector<uint32_t> value_regs;
     std::vector<uint32_t> invalidate_regs;
-    memset(&reg_info, 0, sizeof(reg_info));
 
     ConstString name_val;
     ConstString alt_name_val;
Index: lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
===================================================================
--- lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
+++ lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
@@ -12,6 +12,7 @@
 #include "lldb/Core/EmulateInstruction.h"
 #include "lldb/Interpreter/OptionValue.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/ADT/Optional.h"
 
 namespace llvm {
 class MCDisassembler;
@@ -168,6 +169,9 @@
 
   const char *GetRegisterName(unsigned reg_num, bool alternate_name);
 
+  llvm::Optional<lldb_private::RegisterInfo>
+  GetMIPS64DWARFRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num);
+
 private:
   std::unique_ptr<llvm::MCDisassembler> m_disasm;
   std::unique_ptr<llvm::MCSubtargetInfo> m_subtype_info;
Index: lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
===================================================================
--- lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
+++ lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
@@ -572,6 +572,58 @@
   return nullptr;
 }
 
+llvm::Optional<lldb_private::RegisterInfo>
+EmulateInstructionMIPS64::GetMIPS64DWARFRegisterInfo(RegisterKind reg_kind,
+                                                     uint32_t reg_num) {
+  RegisterInfo reg_info;
+
+  if (reg_num == dwarf_sr_mips64 || reg_num == dwarf_fcsr_mips64 ||
+      reg_num == dwarf_fir_mips64 || reg_num == dwarf_mcsr_mips64 ||
+      reg_num == dwarf_mir_mips64 || reg_num == dwarf_config5_mips64) {
+    reg_info.byte_size = 4;
+    reg_info.format = eFormatHex;
+    reg_info.encoding = eEncodingUint;
+  } else if ((int)reg_num >= dwarf_zero_mips64 &&
+             (int)reg_num <= dwarf_f31_mips64) {
+    reg_info.byte_size = 8;
+    reg_info.format = eFormatHex;
+    reg_info.encoding = eEncodingUint;
+  } else if ((int)reg_num >= dwarf_w0_mips64 &&
+             (int)reg_num <= dwarf_w31_mips64) {
+    reg_info.byte_size = 16;
+    reg_info.format = eFormatVectorOfUInt8;
+    reg_info.encoding = eEncodingVector;
+  } else {
+    return llvm::None;
+  }
+
+  reg_info.name = GetRegisterName(reg_num, false);
+  reg_info.alt_name = GetRegisterName(reg_num, true);
+  reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+  switch (reg_num) {
+  case dwarf_r30_mips64:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+    break;
+  case dwarf_ra_mips64:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+    break;
+  case dwarf_sp_mips64:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+    break;
+  case dwarf_pc_mips64:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+    break;
+  case dwarf_sr_mips64:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+    break;
+  default:
+    break;
+  }
+
+  return reg_info;
+}
+
 bool EmulateInstructionMIPS64::GetRegisterInfo(RegisterKind reg_kind,
                                                uint32_t reg_num,
                                                RegisterInfo &reg_info) {
@@ -603,53 +655,11 @@
   }
 
   if (reg_kind == eRegisterKindDWARF) {
-    ::memset(&reg_info, 0, sizeof(RegisterInfo));
-    ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
-    if (reg_num == dwarf_sr_mips64 || reg_num == dwarf_fcsr_mips64 ||
-        reg_num == dwarf_fir_mips64 || reg_num == dwarf_mcsr_mips64 ||
-        reg_num == dwarf_mir_mips64 || reg_num == dwarf_config5_mips64) {
-      reg_info.byte_size = 4;
-      reg_info.format = eFormatHex;
-      reg_info.encoding = eEncodingUint;
-    } else if ((int)reg_num >= dwarf_zero_mips64 &&
-               (int)reg_num <= dwarf_f31_mips64) {
-      reg_info.byte_size = 8;
-      reg_info.format = eFormatHex;
-      reg_info.encoding = eEncodingUint;
-    } else if ((int)reg_num >= dwarf_w0_mips64 &&
-               (int)reg_num <= dwarf_w31_mips64) {
-      reg_info.byte_size = 16;
-      reg_info.format = eFormatVectorOfUInt8;
-      reg_info.encoding = eEncodingVector;
-    } else {
-      return false;
-    }
-
-    reg_info.name = GetRegisterName(reg_num, false);
-    reg_info.alt_name = GetRegisterName(reg_num, true);
-    reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
-    switch (reg_num) {
-    case dwarf_r30_mips64:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
-      break;
-    case dwarf_ra_mips64:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
-      break;
-    case dwarf_sp_mips64:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
-      break;
-    case dwarf_pc_mips64:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
-      break;
-    case dwarf_sr_mips64:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
-      break;
-    default:
-      break;
-    }
-    return true;
+    llvm::Optional<RegisterInfo> info =
+        GetMIPS64DWARFRegisterInfo(reg_kind, reg_num);
+    if (info)
+      reg_info = *info;
+    return info.has_value();
   }
   return false;
 }
Index: lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
===================================================================
--- lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
+++ lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
@@ -26,6 +26,7 @@
 
 #include "lldb/Core/EmulateInstruction.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/ADT/Optional.h"
 
 class EmulateInstructionMIPS : public lldb_private::EmulateInstruction {
 public:
@@ -203,6 +204,9 @@
 
   const char *GetRegisterName(unsigned reg_num, bool alternate_name);
 
+  llvm::Optional<lldb_private::RegisterInfo>
+  GetMIPSDWARFRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num);
+
 private:
   std::unique_ptr<llvm::MCDisassembler> m_disasm;
   std::unique_ptr<llvm::MCDisassembler> m_alt_disasm;
Index: lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
===================================================================
--- lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
+++ lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
@@ -585,6 +585,56 @@
   return nullptr;
 }
 
+llvm::Optional<lldb_private::RegisterInfo>
+EmulateInstructionMIPS::GetMIPSDWARFRegisterInfo(RegisterKind reg_kind,
+                                                 uint32_t reg_num) {
+  RegisterInfo reg_info;
+
+  if (reg_num == dwarf_sr_mips || reg_num == dwarf_fcsr_mips ||
+      reg_num == dwarf_fir_mips || reg_num == dwarf_mcsr_mips ||
+      reg_num == dwarf_mir_mips || reg_num == dwarf_config5_mips) {
+    reg_info.byte_size = 4;
+    reg_info.format = eFormatHex;
+    reg_info.encoding = eEncodingUint;
+  } else if ((int)reg_num >= dwarf_zero_mips &&
+             (int)reg_num <= dwarf_f31_mips) {
+    reg_info.byte_size = 4;
+    reg_info.format = eFormatHex;
+    reg_info.encoding = eEncodingUint;
+  } else if ((int)reg_num >= dwarf_w0_mips && (int)reg_num <= dwarf_w31_mips) {
+    reg_info.byte_size = 16;
+    reg_info.format = eFormatVectorOfUInt8;
+    reg_info.encoding = eEncodingVector;
+  } else {
+    return llvm::None;
+  }
+
+  reg_info.name = GetRegisterName(reg_num, false);
+  reg_info.alt_name = GetRegisterName(reg_num, true);
+  reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+  switch (reg_num) {
+  case dwarf_r30_mips:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+    break;
+  case dwarf_ra_mips:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+    break;
+  case dwarf_sp_mips:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+    break;
+  case dwarf_pc_mips:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+    break;
+  case dwarf_sr_mips:
+    reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+    break;
+  default:
+    break;
+  }
+  return reg_info;
+}
+
 bool EmulateInstructionMIPS::GetRegisterInfo(RegisterKind reg_kind,
                                              uint32_t reg_num,
                                              RegisterInfo &reg_info) {
@@ -616,53 +666,11 @@
   }
 
   if (reg_kind == eRegisterKindDWARF) {
-    ::memset(&reg_info, 0, sizeof(RegisterInfo));
-    ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
-    if (reg_num == dwarf_sr_mips || reg_num == dwarf_fcsr_mips ||
-        reg_num == dwarf_fir_mips || reg_num == dwarf_mcsr_mips ||
-        reg_num == dwarf_mir_mips || reg_num == dwarf_config5_mips) {
-      reg_info.byte_size = 4;
-      reg_info.format = eFormatHex;
-      reg_info.encoding = eEncodingUint;
-    } else if ((int)reg_num >= dwarf_zero_mips &&
-               (int)reg_num <= dwarf_f31_mips) {
-      reg_info.byte_size = 4;
-      reg_info.format = eFormatHex;
-      reg_info.encoding = eEncodingUint;
-    } else if ((int)reg_num >= dwarf_w0_mips &&
-               (int)reg_num <= dwarf_w31_mips) {
-      reg_info.byte_size = 16;
-      reg_info.format = eFormatVectorOfUInt8;
-      reg_info.encoding = eEncodingVector;
-    } else {
-      return false;
-    }
-
-    reg_info.name = GetRegisterName(reg_num, false);
-    reg_info.alt_name = GetRegisterName(reg_num, true);
-    reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
-    switch (reg_num) {
-    case dwarf_r30_mips:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
-      break;
-    case dwarf_ra_mips:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
-      break;
-    case dwarf_sp_mips:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
-      break;
-    case dwarf_pc_mips:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
-      break;
-    case dwarf_sr_mips:
-      reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
-      break;
-    default:
-      break;
-    }
-    return true;
+    llvm::Optional<RegisterInfo> info =
+        GetMIPSDWARFRegisterInfo(reg_kind, reg_num);
+    if (info)
+      reg_info = *info;
+    return info.has_value();
   }
   return false;
 }
Index: lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
===================================================================
--- lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -24,6 +24,7 @@
 #include "Plugins/Process/Utility/ARMUtils.h"
 #include "Utility/ARM_DWARF_Registers.h"
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/MathExtras.h"
 
@@ -42,9 +43,8 @@
 // ITSession implementation
 //
 
-static bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
-  ::memset(&reg_info, 0, sizeof(RegisterInfo));
-  ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+static llvm::Optional<RegisterInfo> GetARMDWARFRegisterInfo(unsigned reg_num) {
+  RegisterInfo reg_info;
 
   if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
     reg_info.byte_size = 16;
@@ -594,9 +594,9 @@
     break;
 
   default:
-    return false;
+    return llvm::None;
   }
-  return true;
+  return reg_info;
 }
 
 // A8.6.50
@@ -812,8 +812,13 @@
     }
   }
 
-  if (reg_kind == eRegisterKindDWARF)
-    return GetARMDWARFRegisterInfo(reg_num, reg_info);
+  if (reg_kind == eRegisterKindDWARF) {
+    llvm::Optional<RegisterInfo> info = GetARMDWARFRegisterInfo(reg_num);
+    if (info)
+      reg_info = *info;
+    return info.has_value();
+  }
+
   return false;
 }
 
@@ -14101,7 +14106,7 @@
   if (ArchVersion() >= ARMv5T)
     return BXWritePC(context, addr);
   else
-    return BranchWritePC((const Context)context, addr);
+    return BranchWritePC(context, addr);
 }
 
 // Dispatches to either BXWritePC or BranchWritePC based on architecture
@@ -14110,7 +14115,7 @@
   if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
     return BXWritePC(context, addr);
   else
-    return BranchWritePC((const Context)context, addr);
+    return BranchWritePC(context, addr);
 }
 
 EmulateInstructionARM::Mode EmulateInstructionARM::CurrentInstrSet() {
Index: lldb/include/lldb/lldb-private-types.h
===================================================================
--- lldb/include/lldb/lldb-private-types.h
+++ lldb/include/lldb/lldb-private-types.h
@@ -11,10 +11,13 @@
 
 #if defined(__cplusplus)
 
+#include "lldb/lldb-defines.h"
 #include "lldb/lldb-private.h"
 
 #include "llvm/ADT/ArrayRef.h"
 
+#include <array>
+
 namespace llvm {
 namespace sys {
 class DynamicLibrary;
@@ -32,34 +35,46 @@
 /// (optional), encoding, size in bytes and the default display format.
 struct RegisterInfo {
   /// Name of this register, can't be NULL.
-  const char *name;
+  const char *name = nullptr;
   /// Alternate name of this register, can be NULL.
-  const char *alt_name;
+  const char *alt_name = nullptr;
   /// Size in bytes of the register.
-  uint32_t byte_size;
+  uint32_t byte_size = 0;
   /// The byte offset in the register context data where this register's
   /// value is found.
   /// This is optional, and can be 0 if a particular RegisterContext does not
   /// need to address its registers by byte offset.
-  uint32_t byte_offset;
+  uint32_t byte_offset = 0;
   /// Encoding of the register bits.
-  lldb::Encoding encoding;
+  lldb::Encoding encoding = lldb::eEncodingInvalid;
   /// Default display format.
-  lldb::Format format;
+  lldb::Format format = lldb::eFormatInvalid;
   /// Holds all of the various register numbers for all register kinds.
-  uint32_t kinds[lldb::kNumRegisterKinds]; //
+  std::array<uint32_t, lldb::kNumRegisterKinds> kinds;
   /// List of registers (terminated with LLDB_INVALID_REGNUM). If this value is
   /// not null, all registers in this list will be read first, at which point
   /// the value for this register will be valid. For example, the value list
   /// for ah would be eax (x86) or rax (x64). Register numbers are
   /// of eRegisterKindLLDB. If multiple registers are listed, the final
   /// value will be the concatenation of them.
-  uint32_t *value_regs;
+  uint32_t *value_regs = nullptr;
   /// List of registers (terminated with LLDB_INVALID_REGNUM). If this value is
   /// not null, all registers in this list will be invalidated when the value of
   /// this register changes. For example, the invalidate list for eax would be
   /// rax ax, ah, and al.
-  uint32_t *invalidate_regs;
+  uint32_t *invalidate_regs = nullptr;
+
+  RegisterInfo() { kinds.fill(LLDB_INVALID_REGNUM); }
+
+  RegisterInfo(const char *name, const char *alt_name, uint32_t byte_size,
+               uint32_t byte_offset, lldb::Encoding encoding,
+               lldb::Format format,
+               std::array<uint32_t, lldb::kNumRegisterKinds> kinds,
+               uint32_t *value_regs, uint32_t *invalidate_regs)
+      : name(name), alt_name(alt_name), byte_size(byte_size),
+        byte_offset(byte_offset), encoding(encoding), format(format),
+        kinds(kinds), value_regs(value_regs), invalidate_regs(invalidate_regs) {
+  }
 
   llvm::ArrayRef<uint8_t> data(const uint8_t *context_base) const {
     return llvm::ArrayRef<uint8_t>(context_base + byte_offset, byte_size);
Index: lldb/include/lldb/Core/EmulateInstruction.h
===================================================================
--- lldb/include/lldb/Core/EmulateInstruction.h
+++ lldb/include/lldb/Core/EmulateInstruction.h
@@ -183,147 +183,222 @@
 
   struct Context {
     ContextType type = eContextInvalid;
+    InfoType GetInfoType() const { return info.info_type; }
 
-  private:
-    enum InfoType info_type = eInfoTypeNoArgs;
+    struct ContextUnion {
+    private:
+      InfoType info_type;
 
-  public:
-    enum InfoType GetInfoType() const { return info_type; }
-    union {
-      struct RegisterPlusOffset {
+    public:
+      ContextUnion() : info_type(eInfoTypeNoArgs) {}
+
+      struct RegisterPlusOffsetStruct {
         RegisterInfo reg;      // base register
         int64_t signed_offset; // signed offset added to base register
-      } RegisterPlusOffset;
+      };
 
-      struct RegisterPlusIndirectOffset {
+      struct RegisterPlusIndirectOffsetStruct {
         RegisterInfo base_reg;   // base register number
         RegisterInfo offset_reg; // offset register kind
-      } RegisterPlusIndirectOffset;
+      };
 
-      struct RegisterToRegisterPlusOffset {
+      struct RegisterToRegisterPlusOffsetStruct {
         RegisterInfo data_reg; // source/target register for data
         RegisterInfo base_reg; // base register for address calculation
         int64_t offset;        // offset for address calculation
-      } RegisterToRegisterPlusOffset;
+      };
 
-      struct RegisterToRegisterPlusIndirectOffset {
+      struct RegisterToRegisterPlusIndirectOffsetStruct {
         RegisterInfo base_reg;   // base register for address calculation
         RegisterInfo offset_reg; // offset register for address calculation
         RegisterInfo data_reg;   // source/target register for data
-      } RegisterToRegisterPlusIndirectOffset;
+      };
 
-      struct RegisterRegisterOperands {
+      struct RegisterRegisterOperandsStruct {
         RegisterInfo
             operand1; // register containing first operand for binary op
         RegisterInfo
             operand2; // register containing second operand for binary op
-      } RegisterRegisterOperands;
-
-      int64_t signed_offset; // signed offset by which to adjust self (for
-                             // registers only)
-
-      RegisterInfo reg; // plain register
-
-      uint64_t unsigned_immediate; // unsigned immediate value
-      int64_t signed_immediate;    // signed immediate value
-
-      lldb::addr_t address; // direct address
+      };
 
-      struct ISAAndImmediate {
+      struct ISAAndImmediateStruct {
         uint32_t isa;
         uint32_t unsigned_data32; // immediate data
-      } ISAAndImmediate;
+      };
 
-      struct ISAAndImmediateSigned {
+      struct ISAAndImmediateSignedStruct {
         uint32_t isa;
         int32_t signed_data32; // signed immediate data
-      } ISAAndImmediateSigned;
+      };
+
+      ~ContextUnion() {
+        switch (info_type) {
+        case eInfoTypeRegisterPlusOffset:
+          RegisterPlusOffset.~RegisterPlusOffsetStruct();
+          break;
+        case eInfoTypeRegisterPlusIndirectOffset:
+          RegisterPlusIndirectOffset.~RegisterPlusIndirectOffsetStruct();
+          break;
+        case eInfoTypeRegisterToRegisterPlusOffset:
+          RegisterToRegisterPlusOffset.~RegisterToRegisterPlusOffsetStruct();
+          break;
+        case eInfoTypeRegisterToRegisterPlusIndirectOffset:
+          RegisterToRegisterPlusIndirectOffset
+              .~RegisterToRegisterPlusIndirectOffsetStruct();
+          break;
+        case eInfoTypeRegisterRegisterOperands:
+          RegisterRegisterOperands.~RegisterRegisterOperandsStruct();
+          break;
+        case eInfoTypeRegister:
+          reg.~RegisterInfo();
+          break;
+        case eInfoTypeISAAndImmediate:
+          ISAAndImmediate.~ISAAndImmediateStruct();
+          break;
+        case eInfoTypeISAAndImmediateSigned:
+          ISAAndImmediateSigned.~ISAAndImmediateSignedStruct();
+          break;
+        // The following are PODs.
+        case eInfoTypeAddress:
+        case eInfoTypeImmediate:
+        case eInfoTypeImmediateSigned:
+        case eInfoTypeOffset:
+        case eInfoTypeISA:
+        case eInfoTypeNoArgs:
+          break;
+        }
+      }
+
+      union {
+        RegisterPlusOffsetStruct RegisterPlusOffset;
+        RegisterPlusIndirectOffsetStruct RegisterPlusIndirectOffset;
+        RegisterToRegisterPlusOffsetStruct RegisterToRegisterPlusOffset;
+        RegisterToRegisterPlusIndirectOffsetStruct
+            RegisterToRegisterPlusIndirectOffset;
+        RegisterRegisterOperandsStruct RegisterRegisterOperands;
+        int64_t signed_offset; // signed offset by which to adjust self (for
+                               // registers only)
+        RegisterInfo reg;      // plain register
+        uint64_t unsigned_immediate; // unsigned immediate value
+        int64_t signed_immediate;    // signed immediate value
+        lldb::addr_t address;        // direct address
+        ISAAndImmediateStruct ISAAndImmediate;
+        ISAAndImmediateSignedStruct ISAAndImmediateSigned;
+        uint32_t isa;
+      };
 
-      uint32_t isa;
+      // So that Context can access info_type.
+      friend Context;
     } info;
 
     Context() = default;
 
+    // In these Set<type> functions, anything that is non-trivial must use
+    // placement new. This is because operator= will interpret whatever
+    // uninitialised memory is in the union as the content of the object and try
+    // to destroy it.
+
     void SetRegisterPlusOffset(RegisterInfo base_reg, int64_t signed_offset) {
-      info_type = eInfoTypeRegisterPlusOffset;
-      info.RegisterPlusOffset.reg = base_reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegisterPlusOffset;
+      new (&info.RegisterPlusOffset.reg) RegisterInfo(base_reg);
       info.RegisterPlusOffset.signed_offset = signed_offset;
     }
 
     void SetRegisterPlusIndirectOffset(RegisterInfo base_reg,
                                        RegisterInfo offset_reg) {
-      info_type = eInfoTypeRegisterPlusIndirectOffset;
-      info.RegisterPlusIndirectOffset.base_reg = base_reg;
-      info.RegisterPlusIndirectOffset.offset_reg = offset_reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegisterPlusIndirectOffset;
+      new (&info.RegisterPlusIndirectOffset.base_reg) RegisterInfo(base_reg);
+      new (&info.RegisterPlusIndirectOffset.offset_reg)
+          RegisterInfo(offset_reg);
     }
 
     void SetRegisterToRegisterPlusOffset(RegisterInfo data_reg,
                                          RegisterInfo base_reg,
                                          int64_t offset) {
-      info_type = eInfoTypeRegisterToRegisterPlusOffset;
-      info.RegisterToRegisterPlusOffset.data_reg = data_reg;
-      info.RegisterToRegisterPlusOffset.base_reg = base_reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegisterToRegisterPlusOffset;
+      new (&info.RegisterToRegisterPlusOffset.data_reg) RegisterInfo(data_reg);
+      new (&info.RegisterToRegisterPlusOffset.base_reg) RegisterInfo(base_reg);
       info.RegisterToRegisterPlusOffset.offset = offset;
     }
 
     void SetRegisterToRegisterPlusIndirectOffset(RegisterInfo base_reg,
                                                  RegisterInfo offset_reg,
                                                  RegisterInfo data_reg) {
-      info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset;
-      info.RegisterToRegisterPlusIndirectOffset.base_reg = base_reg;
-      info.RegisterToRegisterPlusIndirectOffset.offset_reg = offset_reg;
-      info.RegisterToRegisterPlusIndirectOffset.data_reg = data_reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset;
+      new (&info.RegisterToRegisterPlusIndirectOffset.base_reg)
+          RegisterInfo(base_reg);
+      new (&info.RegisterToRegisterPlusIndirectOffset.offset_reg)
+          RegisterInfo(offset_reg);
+      new (&info.RegisterToRegisterPlusIndirectOffset.data_reg)
+          RegisterInfo(data_reg);
     }
 
     void SetRegisterRegisterOperands(RegisterInfo op1_reg,
                                      RegisterInfo op2_reg) {
-      info_type = eInfoTypeRegisterRegisterOperands;
-      info.RegisterRegisterOperands.operand1 = op1_reg;
-      info.RegisterRegisterOperands.operand2 = op2_reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegisterRegisterOperands;
+      new (&info.RegisterRegisterOperands.operand1) RegisterInfo(op1_reg);
+      new (&info.RegisterRegisterOperands.operand2) RegisterInfo(op2_reg);
     }
 
     void SetOffset(int64_t signed_offset) {
-      info_type = eInfoTypeOffset;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeOffset;
       info.signed_offset = signed_offset;
     }
 
     void SetRegister(RegisterInfo reg) {
-      info_type = eInfoTypeRegister;
-      info.reg = reg;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeRegister;
+      new (&info.reg) RegisterInfo(reg);
     }
 
     void SetImmediate(uint64_t immediate) {
-      info_type = eInfoTypeImmediate;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeImmediate;
       info.unsigned_immediate = immediate;
     }
 
     void SetImmediateSigned(int64_t signed_immediate) {
-      info_type = eInfoTypeImmediateSigned;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeImmediateSigned;
       info.signed_immediate = signed_immediate;
     }
 
     void SetAddress(lldb::addr_t address) {
-      info_type = eInfoTypeAddress;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeAddress;
       info.address = address;
     }
+
     void SetISAAndImmediate(uint32_t isa, uint32_t data) {
-      info_type = eInfoTypeISAAndImmediate;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeISAAndImmediate;
       info.ISAAndImmediate.isa = isa;
       info.ISAAndImmediate.unsigned_data32 = data;
     }
 
     void SetISAAndImmediateSigned(uint32_t isa, int32_t data) {
-      info_type = eInfoTypeISAAndImmediateSigned;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeISAAndImmediateSigned;
       info.ISAAndImmediateSigned.isa = isa;
       info.ISAAndImmediateSigned.signed_data32 = data;
     }
 
     void SetISA(uint32_t isa) {
-      info_type = eInfoTypeISA;
+      info.~ContextUnion();
+      info.info_type = eInfoTypeISA;
       info.isa = isa;
     }
 
-    void SetNoArgs() { info_type = eInfoTypeNoArgs; }
+    void SetNoArgs() {
+      info.~ContextUnion();
+      info.info_type = eInfoTypeNoArgs;
+    }
 
     void Dump(Stream &s, EmulateInstruction *instruction) const;
   };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to