X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fregcache.c;h=bc916f352eb28f6ad4b2fa1ef3ed38a508bceadf;hb=26a57c9256d7ec2b4da2f1d85a9fba830948dbd9;hp=371322d9a1e9c1283ffb7e9b9bc64e95bf4827ba;hpb=4f0420fdabda76f462bd29a02d9be575e0e0cce7;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/regcache.c b/gdb/regcache.c index 371322d9a1..bc916f352e 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -19,6 +19,7 @@ #include "defs.h" #include "inferior.h" +#include "gdbthread.h" #include "target.h" #include "gdbarch.h" #include "gdbcmd.h" @@ -185,14 +186,15 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) if (has_pseudo) { - m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_cooked_registers); - m_register_status = XCNEWVEC (signed char, - m_descr->nr_cooked_registers); + m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers] ()); + m_register_status.reset + (new register_status[m_descr->nr_cooked_registers] ()); } else { - m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_raw_registers); - m_register_status = XCNEWVEC (signed char, gdbarch_num_regs (gdbarch)); + m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers] ()); + m_register_status.reset + (new register_status[gdbarch_num_regs (gdbarch)] ()); } } @@ -204,16 +206,12 @@ regcache::regcache (gdbarch *gdbarch, const address_space *aspace_) m_ptid = minus_one_ptid; } -static enum register_status -do_cooked_read (void *src, int regnum, gdb_byte *buf) -{ - struct regcache *regcache = (struct regcache *) src; - - return regcache->cooked_read (regnum, buf); -} - -readonly_detached_regcache::readonly_detached_regcache (const regcache &src) - : readonly_detached_regcache (src.arch (), do_cooked_read, (void *) &src) +readonly_detached_regcache::readonly_detached_regcache (regcache &src) + : readonly_detached_regcache (src.arch (), + [&src] (int regnum, gdb_byte *buf) + { + return src.cooked_read (regnum, buf); + }) { } @@ -238,7 +236,7 @@ public: ~regcache_invalidator () { if (m_regcache != nullptr) - regcache_invalidate (m_regcache, m_regnum); + m_regcache->invalidate (m_regnum); } DISABLE_COPY_AND_ASSIGN (regcache_invalidator); @@ -259,12 +257,11 @@ private: gdb_byte * reg_buffer::register_buffer (int regnum) const { - return m_registers + m_descr->register_offset[regnum]; + return m_registers.get () + m_descr->register_offset[regnum]; } void -reg_buffer::save (regcache_cooked_read_ftype *cooked_read, - void *src) +reg_buffer::save (register_read_ftype cooked_read) { struct gdbarch *gdbarch = m_descr->gdbarch; int regnum; @@ -272,8 +269,8 @@ reg_buffer::save (regcache_cooked_read_ftype *cooked_read, /* It should have pseudo registers. */ gdb_assert (m_has_pseudo); /* Clear the dest. */ - memset (m_registers, 0, m_descr->sizeof_cooked_registers); - memset (m_register_status, 0, m_descr->nr_cooked_registers); + memset (m_registers.get (), 0, m_descr->sizeof_cooked_registers); + memset (m_register_status.get (), REG_UNKNOWN, m_descr->nr_cooked_registers); /* Copy over any registers (identified by their membership in the save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) range is checked since some architectures need @@ -283,7 +280,7 @@ reg_buffer::save (regcache_cooked_read_ftype *cooked_read, if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) { gdb_byte *dst_buf = register_buffer (regnum); - enum register_status status = cooked_read (src, regnum, dst_buf); + enum register_status status = cooked_read (regnum, dst_buf); gdb_assert (status != REG_UNKNOWN); @@ -320,23 +317,18 @@ regcache::restore (readonly_detached_regcache *src) } } +/* See common/common-regcache.h. */ + enum register_status reg_buffer::get_register_status (int regnum) const { assert_regnum (regnum); - return (enum register_status) m_register_status[regnum]; -} - -void -regcache_invalidate (struct regcache *regcache, int regnum) -{ - gdb_assert (regcache != NULL); - regcache->invalidate (regnum); + return m_register_status[regnum]; } void -detached_regcache::invalidate (int regnum) +reg_buffer::invalidate (int regnum) { assert_regnum (regnum); m_register_status[regnum] = REG_UNKNOWN; @@ -399,10 +391,18 @@ get_thread_regcache (ptid_t ptid) return get_thread_arch_regcache (ptid, current_thread_arch); } +/* See regcache.h. */ + +struct regcache * +get_thread_regcache (thread_info *thread) +{ + return get_thread_regcache (thread->ptid); +} + struct regcache * get_current_regcache (void) { - return get_thread_regcache (inferior_ptid); + return get_thread_regcache (inferior_thread ()); } /* See common/common-regcache.h. */ @@ -452,7 +452,7 @@ registers_changed_ptid (ptid_t ptid) it != regcache::current_regcache.end (); ) { - if (ptid_match ((*it)->ptid (), ptid)) + if ((*it)->ptid ().matches (ptid)) { delete *it; it = regcache::current_regcache.erase_after (oit); @@ -461,13 +461,13 @@ registers_changed_ptid (ptid_t ptid) oit = it++; } - if (ptid_match (current_thread_ptid, ptid)) + if (current_thread_ptid.matches (ptid)) { current_thread_ptid = null_ptid; current_thread_arch = NULL; } - if (ptid_match (inferior_ptid, ptid)) + if (inferior_ptid.matches (ptid)) { /* We just deleted the regcache of the current thread. Need to forget about any frames we have cached, too. */ @@ -475,6 +475,14 @@ registers_changed_ptid (ptid_t ptid) } } +/* See regcache.h. */ + +void +registers_changed_thread (thread_info *thread) +{ + registers_changed_ptid (thread->ptid); +} + void registers_changed (void) { @@ -522,7 +530,7 @@ readable_regcache::raw_read (int regnum, gdb_byte *buf) memcpy (buf, register_buffer (regnum), m_descr->sizeof_register[regnum]); - return (enum register_status) m_register_status[regnum]; + return m_register_status[regnum]; } enum register_status @@ -616,7 +624,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf) else memset (buf, 0, m_descr->sizeof_register[regnum]); - return (enum register_status) m_register_status[regnum]; + return m_register_status[regnum]; } else if (gdbarch_pseudo_register_read_value_p (m_descr->gdbarch)) { @@ -645,12 +653,6 @@ readable_regcache::cooked_read (int regnum, gdb_byte *buf) regnum, buf); } -struct value * -regcache_cooked_read_value (struct regcache *regcache, int regnum) -{ - return regcache->cooked_read_value (regnum); -} - struct value * readable_regcache::cooked_read_value (int regnum) { @@ -778,13 +780,6 @@ regcache::raw_write (int regnum, const gdb_byte *buf) invalidator.release (); } -void -regcache_cooked_write (struct regcache *regcache, int regnum, - const gdb_byte *buf) -{ - regcache->cooked_write (regnum, buf); -} - void regcache::cooked_write (int regnum, const gdb_byte *buf) { @@ -797,77 +792,149 @@ regcache::cooked_write (int regnum, const gdb_byte *buf) regnum, buf); } -/* Perform a partial register transfer using a read, modify, write - operation. */ +/* See regcache.h. */ enum register_status -readable_regcache::read_part (int regnum, int offset, int len, void *in, - bool is_raw) +readable_regcache::read_part (int regnum, int offset, int len, + gdb_byte *out, bool is_raw) { - struct gdbarch *gdbarch = arch (); - gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + int reg_size = register_size (arch (), regnum); + + gdb_assert (out != NULL); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return REG_VALID; + } + + if (offset == 0 && len == reg_size) + { + /* Read the full register. */ + return (is_raw) ? raw_read (regnum, out) : cooked_read (regnum, out); + } - gdb_assert (in != NULL); - gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); - gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); - /* Something to do? */ - if (offset + len == 0) - return REG_VALID; - /* Read (when needed) ... */ enum register_status status; + gdb_byte *reg = (gdb_byte *) alloca (reg_size); - if (is_raw) - status = raw_read (regnum, reg); - else - status = cooked_read (regnum, reg); + /* Read full register to buffer. */ + status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); if (status != REG_VALID) return status; - /* ... modify ... */ - memcpy (in, reg + offset, len); - + /* Copy out. */ + memcpy (out, reg + offset, len); return REG_VALID; } +/* See regcache.h. */ + +void +reg_buffer::raw_collect_part (int regnum, int offset, int len, + gdb_byte *out) const +{ + int reg_size = register_size (arch (), regnum); + + gdb_assert (out != nullptr); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return; + } + + if (offset == 0 && len == reg_size) + { + /* Collect the full register. */ + return raw_collect (regnum, out); + } + + /* Read to buffer, then write out. */ + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + raw_collect (regnum, reg); + memcpy (out, reg + offset, len); +} + +/* See regcache.h. */ + enum register_status regcache::write_part (int regnum, int offset, int len, - const void *out, bool is_raw) + const gdb_byte *in, bool is_raw) { - struct gdbarch *gdbarch = arch (); - gdb_byte *reg = (gdb_byte *) alloca (register_size (gdbarch, regnum)); + int reg_size = register_size (arch (), regnum); - gdb_assert (out != NULL); - gdb_assert (offset >= 0 && offset <= m_descr->sizeof_register[regnum]); - gdb_assert (len >= 0 && offset + len <= m_descr->sizeof_register[regnum]); - /* Something to do? */ - if (offset + len == 0) - return REG_VALID; - /* Read (when needed) ... */ - if (offset > 0 - || offset + len < m_descr->sizeof_register[regnum]) + gdb_assert (in != NULL); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) { - enum register_status status; + /* Nothing to do. */ + return REG_VALID; + } - if (is_raw) - status = raw_read (regnum, reg); - else - status = cooked_read (regnum, reg); - if (status != REG_VALID) - return status; + if (offset == 0 && len == reg_size) + { + /* Write the full register. */ + (is_raw) ? raw_write (regnum, in) : cooked_write (regnum, in); + return REG_VALID; } - memcpy (reg + offset, out, len); - /* ... write (when needed). */ - if (is_raw) - raw_write (regnum, reg); - else - cooked_write (regnum, reg); + enum register_status status; + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + /* Read existing register to buffer. */ + status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); + if (status != REG_VALID) + return status; + + /* Update buffer, then write back to regcache. */ + memcpy (reg + offset, in, len); + is_raw ? raw_write (regnum, reg) : cooked_write (regnum, reg); return REG_VALID; } +/* See regcache.h. */ + +void +reg_buffer::raw_supply_part (int regnum, int offset, int len, + const gdb_byte *in) +{ + int reg_size = register_size (arch (), regnum); + + gdb_assert (in != nullptr); + gdb_assert (offset >= 0 && offset <= reg_size); + gdb_assert (len >= 0 && offset + len <= reg_size); + + if (offset == 0 && len == 0) + { + /* Nothing to do. */ + return; + } + + if (offset == 0 && len == reg_size) + { + /* Supply the full register. */ + return raw_supply (regnum, in); + } + + gdb_byte *reg = (gdb_byte *) alloca (reg_size); + + /* Read existing value to buffer. */ + raw_collect (regnum, reg); + + /* Write to buffer, then write out. */ + memcpy (reg + offset, in, len); + raw_supply (regnum, reg); +} + enum register_status -readable_regcache::raw_read_part (int regnum, int offset, int len, gdb_byte *buf) +readable_regcache::raw_read_part (int regnum, int offset, int len, + gdb_byte *buf) { assert_regnum (regnum); return read_part (regnum, offset, len, buf, true); @@ -883,13 +950,7 @@ regcache::raw_write_part (int regnum, int offset, int len, write_part (regnum, offset, len, buf, true); } -enum register_status -regcache_cooked_read_part (struct regcache *regcache, int regnum, - int offset, int len, gdb_byte *buf) -{ - return regcache->cooked_read_part (regnum, offset, len, buf); -} - +/* See regcache.h. */ enum register_status readable_regcache::cooked_read_part (int regnum, int offset, int len, @@ -899,12 +960,7 @@ readable_regcache::cooked_read_part (int regnum, int offset, int len, return read_part (regnum, offset, len, buf, false); } -void -regcache_cooked_write_part (struct regcache *regcache, int regnum, - int offset, int len, const gdb_byte *buf) -{ - regcache->cooked_write_part (regnum, offset, len, buf); -} +/* See regcache.h. */ void regcache::cooked_write_part (int regnum, int offset, int len, @@ -914,17 +970,10 @@ regcache::cooked_write_part (int regnum, int offset, int len, write_part (regnum, offset, len, buf, false); } -/* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */ - -void -regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf) -{ - gdb_assert (regcache != NULL); - regcache->raw_supply (regnum, buf); -} +/* See common/common-regcache.h. */ void -detached_regcache::raw_supply (int regnum, const void *buf) +reg_buffer::raw_supply (int regnum, const void *buf) { void *regbuf; size_t size; @@ -949,15 +998,11 @@ detached_regcache::raw_supply (int regnum, const void *buf) } } -/* Supply register REGNUM to REGCACHE. Value to supply is an integer stored at - address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED. If - the register size is greater than ADDR_LEN, then the integer will be sign or - zero extended. If the register size is smaller than the integer, then the - most significant bytes of the integer will be truncated. */ +/* See regcache.h. */ void -detached_regcache::raw_supply_integer (int regnum, const gdb_byte *addr, - int addr_len, bool is_signed) +reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, + int addr_len, bool is_signed) { enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); gdb_byte *regbuf; @@ -973,12 +1018,10 @@ detached_regcache::raw_supply_integer (int regnum, const gdb_byte *addr, m_register_status[regnum] = REG_VALID; } -/* Supply register REGNUM with zeroed value to REGCACHE. This is not the same - as calling raw_supply with NULL (which will set the state to - unavailable). */ +/* See regcache.h. */ void -detached_regcache::raw_supply_zeroed (int regnum) +reg_buffer::raw_supply_zeroed (int regnum) { void *regbuf; size_t size; @@ -992,17 +1035,10 @@ detached_regcache::raw_supply_zeroed (int regnum) m_register_status[regnum] = REG_VALID; } -/* Collect register REGNUM from REGCACHE and store its contents in BUF. */ - -void -regcache_raw_collect (const struct regcache *regcache, int regnum, void *buf) -{ - gdb_assert (regcache != NULL && buf != NULL); - regcache->raw_collect (regnum, buf); -} +/* See common/common-regcache.h. */ void -regcache::raw_collect (int regnum, void *buf) const +reg_buffer::raw_collect (int regnum, void *buf) const { const void *regbuf; size_t size; @@ -1015,19 +1051,11 @@ regcache::raw_collect (int regnum, void *buf) const memcpy (buf, regbuf, size); } -/* Transfer a single or all registers belonging to a certain register - set to or from a buffer. This is the main worker function for - regcache_supply_regset and regcache_collect_regset. */ - -/* Collect register REGNUM from REGCACHE. Store collected value as an integer - at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED. - If ADDR_LEN is greater than the register size, then the integer will be sign - or zero extended. If ADDR_LEN is smaller than the register size, then the - most significant bytes of the integer will be truncated. */ +/* See regcache.h. */ void -regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, - bool is_signed) const +reg_buffer::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, + bool is_signed) const { enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); const gdb_byte *regbuf; @@ -1042,11 +1070,43 @@ regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, byte_order); } +/* See regcache.h. */ + +void +regcache::transfer_regset_register (struct regcache *out_regcache, int regnum, + const gdb_byte *in_buf, gdb_byte *out_buf, + int slot_size, int offs) const +{ + struct gdbarch *gdbarch = arch (); + int reg_size = std::min (register_size (gdbarch, regnum), slot_size); + + /* Use part versions and reg_size to prevent possible buffer overflows when + accessing the regcache. */ + + if (out_buf != nullptr) + { + raw_collect_part (regnum, 0, reg_size, out_buf + offs); + + /* Ensure any additional space is cleared. */ + if (slot_size > reg_size) + memset (out_buf + offs + reg_size, 0, slot_size - reg_size); + } + else if (in_buf != nullptr) + out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs); + else + { + /* Invalidate the register. */ + out_regcache->raw_supply (regnum, nullptr); + } +} + +/* See regcache.h. */ + void regcache::transfer_regset (const struct regset *regset, struct regcache *out_regcache, - int regnum, const void *in_buf, - void *out_buf, size_t size) const + int regnum, const gdb_byte *in_buf, + gdb_byte *out_buf, size_t size) const { const struct regcache_map_entry *map; int offs = 0, count; @@ -1072,12 +1132,8 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) break; - if (out_buf) - raw_collect (regno, (gdb_byte *) out_buf + offs); - else - out_regcache->raw_supply (regno, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + transfer_regset_register (out_regcache, regno, in_buf, out_buf, + slot_size, offs); } else { @@ -1086,12 +1142,8 @@ regcache::transfer_regset (const struct regset *regset, if (offs + slot_size > size) return; - if (out_buf) - raw_collect (regnum, (gdb_byte *) out_buf + offs); - else - out_regcache->raw_supply (regnum, in_buf - ? (const gdb_byte *) in_buf + offs - : NULL); + transfer_regset_register (out_regcache, regnum, in_buf, out_buf, + slot_size, offs); return; } } @@ -1106,14 +1158,14 @@ regcache_supply_regset (const struct regset *regset, struct regcache *regcache, int regnum, const void *buf, size_t size) { - regcache->supply_regset (regset, regnum, buf, size); + regcache->supply_regset (regset, regnum, (const gdb_byte *) buf, size); } void regcache::supply_regset (const struct regset *regset, int regnum, const void *buf, size_t size) { - transfer_regset (regset, this, regnum, buf, NULL, size); + transfer_regset (regset, this, regnum, (const gdb_byte *) buf, nullptr, size); } /* Collect register REGNUM from REGCACHE to BUF, using the register @@ -1125,16 +1177,30 @@ regcache_collect_regset (const struct regset *regset, const struct regcache *regcache, int regnum, void *buf, size_t size) { - regcache->collect_regset (regset, regnum, buf, size); + regcache->collect_regset (regset, regnum, (gdb_byte *) buf, size); } void regcache::collect_regset (const struct regset *regset, int regnum, void *buf, size_t size) const { - transfer_regset (regset, NULL, regnum, NULL, buf, size); + transfer_regset (regset, nullptr, regnum, nullptr, (gdb_byte *) buf, size); } +/* See common/common-regcache.h. */ + +bool +reg_buffer::raw_compare (int regnum, const void *buf, int offset) const +{ + gdb_assert (buf != NULL); + assert_regnum (regnum); + + const char *regbuf = (const char *) register_buffer (regnum); + size_t size = m_descr->sizeof_register[regnum]; + gdb_assert (size >= offset); + + return (memcmp (buf, regbuf + offset, size - offset) == 0); +} /* Special handling for register PC. */ @@ -1497,7 +1563,7 @@ cooked_read_test (struct gdbarch *gdbarch) { /* Error out if debugging something, because we're going to push the test target, which would pop any existing target. */ - if (target_stack->to_stratum >= process_stratum) + if (current_top_target ()->to_stratum >= process_stratum) error (_("target already pushed")); /* Create a mock environment. An inferior with a thread, with a @@ -1671,7 +1737,7 @@ cooked_write_test (struct gdbarch *gdbarch) { /* Error out if debugging something, because we're going to push the test target, which would pop any existing target. */ - if (target_stack->to_stratum >= process_stratum) + if (current_top_target ()->to_stratum >= process_stratum) error (_("target already pushed")); /* Create a mock environment. A process_stratum target pushed. */