/* Traditional frame unwind support, for GDB the GNU Debugger.
- Copyright (C) 2003-2019 Free Software Foundation, Inc.
+ Copyright (C) 2003-2021 Free Software Foundation, Inc.
This file is part of GDB.
void trad_frame_set_reg_value (struct trad_frame_cache *this_cache,
int regnum, LONGEST val);
+/* Given the cache in THIS_TRAD_CACHE, set the value of REGNUM to the bytes
+ contained in BYTES with size SIZE. */
+void trad_frame_set_reg_value_bytes (struct trad_frame_cache *this_trad_cache,
+ int regnum,
+ gdb::array_view<const gdb_byte> bytes);
+
struct value *trad_frame_get_register (struct trad_frame_cache *this_trad_cache,
struct frame_info *this_frame,
int regnum);
-/* A traditional saved regs table, indexed by REGNUM, encoding where
- the value of REGNUM for the previous frame can be found in this
- frame.
-
- The table is initialized with an identity encoding (ADDR == -1,
- REALREG == REGNUM) indicating that the value of REGNUM in the
- previous frame can be found in register REGNUM (== REALREG) in this
- frame.
-
- The initial encoding can then be changed:
-
- Modify ADDR (REALREG >= 0, ADDR != -1) to indicate that the value
- of register REGNUM in the previous frame can be found in memory at
- ADDR in this frame (addr_p, !realreg_p, !value_p).
-
- Modify REALREG (REALREG >= 0, ADDR == -1) to indicate that the
- value of register REGNUM in the previous frame is found in register
- REALREG in this frame (!addr_p, realreg_p, !value_p).
-
- Call trad_frame_set_value (REALREG == -1) to indicate that the
- value of register REGNUM in the previous frame is found in ADDR
- (!addr_p, !realreg_p, value_p).
+/* Describes the kind of encoding a stored register has. */
+enum class trad_frame_saved_reg_kind
+{
+ /* Register value is unknown. */
+ UNKNOWN = 0,
+ /* Register value is a constant. */
+ VALUE,
+ /* Register value is in another register. */
+ REALREG,
+ /* Register value is at an address. */
+ ADDR,
+ /* Register value is a sequence of bytes. */
+ VALUE_BYTES
+};
- Call trad_frame_set_unknown (REALREG == -2) to indicate that the
- register's value is not known. */
+/* A struct that describes a saved register in a frame. */
struct trad_frame_saved_reg
{
- LONGEST addr; /* A CORE_ADDR fits in a longest. */
- int realreg;
+ /* Setters */
+
+ /* Encode that the saved register's value is constant VAL in the
+ trad-frame. */
+ void set_value (LONGEST val)
+ {
+ m_kind = trad_frame_saved_reg_kind::VALUE;
+ m_reg.value = val;
+ }
+
+ /* Encode that the saved register's value is stored in register REALREG. */
+ void set_realreg (int realreg)
+ {
+ m_kind = trad_frame_saved_reg_kind::REALREG;
+ m_reg.realreg = realreg;
+ }
+
+ /* Encode that the saved register's value is stored in memory at ADDR. */
+ void set_addr (LONGEST addr)
+ {
+ m_kind = trad_frame_saved_reg_kind::ADDR;
+ m_reg.addr = addr;
+ }
+
+ /* Encode that the saved register's value is unknown. */
+ void set_unknown ()
+ {
+ m_kind = trad_frame_saved_reg_kind::UNKNOWN;
+ }
+
+ /* Encode that the saved register's value is stored as a sequence of bytes.
+ This is useful when the value is larger than what primitive types
+ can hold. */
+ void set_value_bytes (gdb::array_view<const gdb_byte> bytes)
+ {
+ /* Allocate the space and copy the data bytes. */
+ gdb_byte *data = FRAME_OBSTACK_CALLOC (bytes.size (), gdb_byte);
+ memcpy (data, bytes.data (), bytes.size ());
+
+ m_kind = trad_frame_saved_reg_kind::VALUE_BYTES;
+ m_reg.value_bytes = data;
+ }
+
+ /* Getters */
+
+ LONGEST value () const
+ {
+ gdb_assert (m_kind == trad_frame_saved_reg_kind::VALUE);
+ return m_reg.value;
+ }
+
+ int realreg () const
+ {
+ gdb_assert (m_kind == trad_frame_saved_reg_kind::REALREG);
+ return m_reg.realreg;
+ }
+
+ LONGEST addr () const
+ {
+ gdb_assert (m_kind == trad_frame_saved_reg_kind::ADDR);
+ return m_reg.addr;
+ }
+
+ const gdb_byte *value_bytes () const
+ {
+ gdb_assert (m_kind == trad_frame_saved_reg_kind::VALUE_BYTES);
+ return m_reg.value_bytes;
+ }
+
+ /* Convenience functions, return true if the register has been
+ encoded as specified. Return false otherwise. */
+ bool is_value () const
+ {
+ return m_kind == trad_frame_saved_reg_kind::VALUE;
+ }
+
+ bool is_realreg () const
+ {
+ return m_kind == trad_frame_saved_reg_kind::REALREG;
+ }
+
+ bool is_addr () const
+ {
+ return m_kind == trad_frame_saved_reg_kind::ADDR;
+ }
+
+ bool is_unknown () const
+ {
+ return m_kind == trad_frame_saved_reg_kind::UNKNOWN;
+ }
+
+ bool is_value_bytes () const
+ {
+ return m_kind == trad_frame_saved_reg_kind::VALUE_BYTES;
+ }
+
+private:
+
+ trad_frame_saved_reg_kind m_kind;
+
+ union {
+ LONGEST value;
+ int realreg;
+ LONGEST addr;
+ const gdb_byte *value_bytes;
+ } m_reg;
};
-/* Encode REGNUM value in the trad-frame. */
-void trad_frame_set_value (struct trad_frame_saved_reg this_saved_regs[],
- int regnum, LONGEST val);
-
-/* Encode REGNUM is in REALREG in the trad-frame. */
-void trad_frame_set_realreg (struct trad_frame_saved_reg this_saved_regs[],
- int regnum, int realreg);
-
-/* Encode REGNUM is at address ADDR in the trad-frame. */
-void trad_frame_set_addr (struct trad_frame_saved_reg this_trad_cache[],
- int regnum, CORE_ADDR addr);
-
-/* Mark REGNUM as unknown. */
-void trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[],
- int regnum);
-
-/* Convenience functions, return non-zero if the register has been
- encoded as specified. */
-int trad_frame_value_p (struct trad_frame_saved_reg this_saved_regs[],
- int regnum);
-int trad_frame_addr_p (struct trad_frame_saved_reg this_saved_regs[],
- int regnum);
-int trad_frame_realreg_p (struct trad_frame_saved_reg this_saved_regs[],
- int regnum);
-
+/* Reset the saved regs cache, setting register values to REALREG. */
+void trad_frame_reset_saved_regs (struct gdbarch *gdbarch,
+ trad_frame_saved_reg *regs);
/* Return a freshly allocated (and initialized) trad_frame array. */
-struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct frame_info *);
-struct trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct gdbarch *);
+trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct frame_info *);
+trad_frame_saved_reg *trad_frame_alloc_saved_regs (struct gdbarch *);
/* Given the trad_frame info, return the location of the specified
register. */
struct value *trad_frame_get_prev_register (struct frame_info *this_frame,
- struct trad_frame_saved_reg this_saved_regs[],
+ trad_frame_saved_reg this_saved_regs[],
int regnum);
#endif