[patch][commit] Hardware Watchpoint Support

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[patch][commit] Hardware Watchpoint Support

Dave Brolley-2
Hi,

I've committed the attached patch which adds support for hardware
watchpoints to SID's GDB component. The Z2 and z2 packets are now supported.

Tested on xstormy16-elf, but the work is target independent.

Dave

sid/component/gdb/ChangeLog:
2005-11-14  Dave Brolley  <[hidden email]>

        * sidcpuutil.h (basic_cpu::pin_factory): Parse, recognize and add
        watchable register and virtual pin for names representing hardware
        watchpoints.
        (read_data_memory_*): Make accessible as virtual methods from basic_cpu.
        (read_watchpoint_memory): New method of basic_cpu.

sid/include/ChangeLog:
2005-11-14  Dave Brolley  <[hidden email]>

        * gdb.h (hw_watchpoints_t): New typedef in gdb.
        (hw_watchpoints): New member of gdb.
        (remove_all_hw_watchpoints, remove_hw_watchpoint): New methods
        of gdb.
        (add_hw_watchpoint): New method of gdb.
        * gdb.cxx (remove_breakpoint): Handle GDBSERV_TARGET_BP_WRITE.
        (set_breakpoint): Likewise.
        (remove_all_hw_watchpoints, remove_hw_watchpoint): New methods
        of gdb.
        (add_hw_watchpoint): New method of gdb.
        (process_detach): Call remove_all_hw_watchpoints.


Index: sid/component/gdb/gdb.cxx
===================================================================
RCS file: /cvs/src/src/sid/component/gdb/gdb.cxx,v
retrieving revision 1.15
diff -c -p -r1.15 gdb.cxx
*** sid/component/gdb/gdb.cxx 19 Aug 2005 19:43:50 -0000 1.15
--- sid/component/gdb/gdb.cxx 14 Nov 2005 19:56:57 -0000
*************** gdb::remove_breakpoint (unsigned long ty
*** 1007,1023 ****
    if (! enable_Z_packet) return 1;
    if (this->cpu == 0) return -1;
 
!   bool ok = false;
 
    if ((type == GDBSERV_TARGET_BP_HARDWARE) ||
        (type == GDBSERV_TARGET_BP_SOFTWARE && force_Z_sw_to_hw))
!     ok = this->remove_hw_breakpoint (watch_pc, bp_length);
    else if ((type == GDBSERV_TARGET_BP_SOFTWARE) ||
    (type == GDBSERV_TARGET_BP_HARDWARE && force_Z_hw_to_sw))
!     ok = this->remove_sw_breakpoint (watch_pc, bp_length);
    // Fail on uses of other breakpoint types (WRITE, READ, ACCESS, UNKNOWN)
 
!   return ok ? 0 : -1;
  }
 
 
--- 1007,1025 ----
    if (! enable_Z_packet) return 1;
    if (this->cpu == 0) return -1;
 
!   int rc = 1; // Not supported
 
    if ((type == GDBSERV_TARGET_BP_HARDWARE) ||
        (type == GDBSERV_TARGET_BP_SOFTWARE && force_Z_sw_to_hw))
!     rc = this->remove_hw_breakpoint (watch_pc, bp_length) ? 0 : -1;
    else if ((type == GDBSERV_TARGET_BP_SOFTWARE) ||
    (type == GDBSERV_TARGET_BP_HARDWARE && force_Z_hw_to_sw))
!     rc = this->remove_sw_breakpoint (watch_pc, bp_length) ? 0 : -1;
!   else if (type == GDBSERV_TARGET_BP_WRITE)
!     rc = this->remove_hw_watchpoint (watch_pc, bp_length) ? 0 : -1;
    // Fail on uses of other breakpoint types (WRITE, READ, ACCESS, UNKNOWN)
 
!   return rc;
  }
 
 
*************** gdb::remove_sw_breakpoint (host_int_8 ad
*** 1146,1151 ****
--- 1148,1211 ----
  }
 
 
+ bool
+ gdb::remove_all_hw_watchpoints ()
+ {
+   while (true)
+     {
+       hw_watchpoints_t::iterator it = this->hw_watchpoints.begin();
+       if (it == this->hw_watchpoints.end()) break;
+
+       // clean up carcass with refcount=0
+       if (it->second == 0)
+ {
+  this->hw_watchpoints.erase(it);
+  continue;
+ }
+
+       // decrement refcount
+       string watcher_name = it->first;
+       bool ok = this->remove_hw_watchpoint (watcher_name);
+       if (!ok) return ok;
+     }
+   return true;
+ }
+
+
+ bool
+ gdb::remove_hw_watchpoint (const string &watcher_name)
+ {  
+   if (this->hw_watchpoints[watcher_name] <= 0)
+     {
+       cerr << "sw-debug-gdb: duplicate watchpoint count underflow!" << endl;
+       return false;
+     }
+
+   this->hw_watchpoints[watcher_name] --;
+   if (this->hw_watchpoints[watcher_name] == 0)
+     {
+       component::status s = this->cpu->disconnect_pin (watcher_name, & this->trapstop_pin);
+       return (s == component::ok);
+     }
+   else
+     return true;
+ }
+
+
+ bool
+ gdb::remove_hw_watchpoint (host_int_8 address, host_int_4 length)
+ {  
+   string watcher_name = string ("watch:")
+     + map_watchable_name ("gdb-watchpoint-"
+  + make_numeric_attribute (address)
+  + "-"
+  + make_numeric_attribute (length))
+     + ":change";
+
+   return remove_hw_watchpoint (watcher_name);
+ }
+
+
  int
  gdb::set_breakpoint (unsigned long type, struct gdbserv_reg *addr, struct gdbserv_reg *len)
  {
*************** gdb::set_breakpoint (unsigned long type,
*** 1165,1181 ****
 
    if (! enable_Z_packet) return 1;
    if (this->cpu == 0) return -1;
!   bool ok = false;
 
    if ((type == GDBSERV_TARGET_BP_HARDWARE) ||
        (type == GDBSERV_TARGET_BP_SOFTWARE && force_Z_sw_to_hw))
!     ok = this->add_hw_breakpoint (watch_pc, bp_length);
    else if ((type == GDBSERV_TARGET_BP_SOFTWARE) ||
    (type == GDBSERV_TARGET_BP_HARDWARE && force_Z_hw_to_sw))
!     ok = this->add_sw_breakpoint (watch_pc, bp_length);
!   // Fail on uses of other breakpoint types (WRITE, READ, ACCESS, UNKNOWN)
 
!   return ok ? 0 : -1;
  }
 
 
--- 1225,1244 ----
 
    if (! enable_Z_packet) return 1;
    if (this->cpu == 0) return -1;
!
!   int rc = 1; // Not supported
 
    if ((type == GDBSERV_TARGET_BP_HARDWARE) ||
        (type == GDBSERV_TARGET_BP_SOFTWARE && force_Z_sw_to_hw))
!     rc = this->add_hw_breakpoint (watch_pc, bp_length) ? 0 : -1;
    else if ((type == GDBSERV_TARGET_BP_SOFTWARE) ||
    (type == GDBSERV_TARGET_BP_HARDWARE && force_Z_hw_to_sw))
!     rc = this->add_sw_breakpoint (watch_pc, bp_length) ? 0 : -1;
!   else if (type == GDBSERV_TARGET_BP_WRITE)
!     rc = this->add_hw_watchpoint (watch_pc, bp_length) ? 0 : -1;
!   // Fail on uses of other breakpoint types (READ, ACCESS, UNKNOWN)
 
!   return rc;
  }
 
 
*************** gdb::add_sw_breakpoint (host_int_8 addre
*** 1266,1271 ****
--- 1329,1359 ----
  }
 
 
+ bool
+ gdb::add_hw_watchpoint (host_int_8 address, host_int_4 length)
+ {
+   // XXX: be sensitive to length
+
+   string watcher_name = string ("watch:")
+     + map_watchable_name ("gdb-watchpoint-"
+  + make_numeric_attribute (address)
+  + "-"
+  + make_numeric_attribute (length))
+     + ":change";
+
+   // see also ::remove_hw_watchpoint()
+
+   this->hw_watchpoints[watcher_name] ++;
+   if (this->hw_watchpoints[watcher_name] == 1)
+     {
+       component::status s = this->cpu->connect_pin (watcher_name, & this->trapstop_pin);
+       return (s == component::ok);
+     }
+   else
+     return true;
+ }
+
+
  void
  gdb::process_detach ()
  {
*************** gdb::process_detach ()
*** 1274,1280 ****
 
    bool ok =
      this->remove_all_hw_breakpoints () &&
!     this->remove_all_sw_breakpoints ();
    if (!ok)
      {
        cerr << "sw-debug-gdb: cannot clean up breakpoints" << endl;
--- 1362,1369 ----
 
    bool ok =
      this->remove_all_hw_breakpoints () &&
!     this->remove_all_sw_breakpoints () &&
!     this->remove_all_hw_watchpoints ();
    if (!ok)
      {
        cerr << "sw-debug-gdb: cannot clean up breakpoints" << endl;
Index: sid/component/gdb/gdb.h
===================================================================
RCS file: /cvs/src/src/sid/component/gdb/gdb.h,v
retrieving revision 1.10
diff -c -p -r1.10 gdb.h
*** sid/component/gdb/gdb.h 19 Aug 2005 19:43:50 -0000 1.10
--- sid/component/gdb/gdb.h 14 Nov 2005 19:56:57 -0000
*************** private:
*** 143,148 ****
--- 143,156 ----
    bool remove_sw_breakpoint (host_int_8, host_int_4);
    bool remove_all_sw_breakpoints ();
 
+   // hw watchpoint tracking
+   typedef map<string,int> hw_watchpoints_t;
+   hw_watchpoints_t hw_watchpoints; // watcher name -> insertion-count
+   bool add_hw_watchpoint (host_int_8, host_int_4);
+   bool remove_hw_watchpoint (host_int_8, host_int_4);
+   bool remove_hw_watchpoint (const string &);
+   bool remove_all_hw_watchpoints ();
+
    // pending signal tracking
    typedef map<int,int> pending_signal_counts_t;
    pending_signal_counts_t pending_signal_counts;
Index: sid/include/sidcpuutil.h
===================================================================
RCS file: /cvs/src/src/sid/include/sidcpuutil.h,v
retrieving revision 1.32
diff -c -p -r1.32 sidcpuutil.h
*** sid/include/sidcpuutil.h 23 Aug 2005 21:09:24 -0000 1.32
--- sid/include/sidcpuutil.h 14 Nov 2005 19:56:57 -0000
*************** namespace sidutil
*** 141,147 ****
      // Virtual pin interfaces between self_watcher and fixed_pin_map_component
      sid::component::status pin_factory (const std::string& name)
        {
! return this->triggerpoint_manager.create_virtual_pin (name);
        }
      void pin_junkyard (const std::string& name)
        {
--- 141,187 ----
      // Virtual pin interfaces between self_watcher and fixed_pin_map_component
      sid::component::status pin_factory (const std::string& name)
        {
! sid::component::status s = this->triggerpoint_manager.create_virtual_pin (name);
! if (s == sid::component::not_found)
!  {
!    // If this is not a watchpoint, then return now.
!    // N.B. The name has been mapped by map_watchable_name and is of the form
!    //   watch:gdb%xxwatchpoint%xx<addr>%xx<len>:change
!    std::vector<std::string> tokens = sidutil::tokenize (name, ":");
!    if (tokens.size () != 3 || tokens[0] != "watch" || tokens[2] != "change")
!      return s;
!
!    // gdb%xxwatchpoint%xx<addr>%xx<len>
!    if (tokens[1].size () < 3 + 3 + 10 + 3 + 1 + 3 + 1)
!      return s;
!
!    std::string watchable_prefix = map_watchable_name ("gdb-watchpoint-");
!    unsigned watchable_prefix_length = watchable_prefix.size ();
!    if (tokens[1].substr (0, watchable_prefix_length) != watchable_prefix)
!      return s;
!
!    tokens = sidutil::tokenize (tokens[1].substr (watchable_prefix_length), tokens[1].substr (3, 1));
!    if (tokens.size () != 2)
!      return s;
!
!    // This is a watch point, add the necessary watchable now.
!    std::pair<sid::host_int_4,sid::host_int_4> addr_and_len;
!    s = sidutil::parse_attribute (tokens[0], addr_and_len.first);
!    assert (s == sid::component::ok);
!
!    tokens[1] = tokens[1].substr (2); // get past hex digits xx
!    s = sidutil::parse_attribute (tokens[1], addr_and_len.second);
!    assert (s == sid::component::ok);
!
!    add_watchable_register ("gdb-watchpoint-" + tokens[0] + "-" + tokens[1], addr_and_len, this,
!    & basic_cpu::read_watchpoint_memory,
!    & basic_cpu::write_watchpoint_memory);
!
!    // Now try to create the virtual pin again. It should succeed.
!    s = this->triggerpoint_manager.create_virtual_pin (name);
!    assert (s == sid::component::ok);
!  }
! return s;
        }
      void pin_junkyard (const std::string& name)
        {
*************** namespace sidutil
*** 720,725 ****
--- 760,770 ----
      template <typename BigOrLittleInt>
      BigOrLittleInt write_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value);
 
+     virtual sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) = 0;
+     virtual sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) = 0;
+     virtual sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) = 0;
+     virtual sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) = 0;
+
      virtual bool handle_insn_memory_read_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
      virtual bool handle_insn_memory_write_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
      virtual bool handle_data_memory_read_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
*************** namespace sidutil
*** 730,735 ****
--- 775,826 ----
      virtual void record_data_memory_read_latency (sid::bus::status s) { total_latency += s.latency; }
      virtual void record_data_memory_write_latency (sid::bus::status s) { total_latency += s.latency; }
 
+     virtual std::string basic_cpu::read_watchpoint_memory (std::pair<sid::host_int_4,sid::host_int_4> addr_and_length)
+       {
+ // Extract the address and length from the argument.
+ sid::host_int_4 address = addr_and_length.first;
+ sid::host_int_4 length  = addr_and_length.second;
+
+ // We'll need the current pc.
+ std::string pc_str = this->attribute_value ("pc");
+ sid::host_int_4 pc;
+ sid::component::status rc = sidutil::parse_attribute (pc_str, pc);
+ assert (rc == sid::component::ok);
+
+ // Just read from insn memory by default
+ switch (length)
+  {
+  case 1:
+    {
+      sid::host_int_1 r1 = read_data_memory_1 (pc, address);
+      return sidutil::make_attribute (r1);
+    }
+  case 2:
+    {
+      sid::host_int_2 r2 = read_data_memory_2 (pc, address);
+      return sidutil::make_attribute (r2);
+    }
+  case 4:
+    {
+      sid::host_int_4 r4 = read_data_memory_4 (pc, address);
+      return sidutil::make_attribute (r4);
+    }
+  case 8:
+    {
+      sid::host_int_8 r8 = read_data_memory_8 (pc, address);
+      return sidutil::make_attribute (r8);
+    }
+  }
+
+ throw cpu_memory_fault (pc, address, sid::bus::unmapped, "watchpoint read");
+ return "";
+       }
+
+     virtual sid::component::status basic_cpu::write_watchpoint_memory (std::pair<sid::host_int_4,sid::host_int_4> addr_and_length, const std::string &value)
+       {
+ return sid::component::bad_value;
+       }
+
      // ------------------------------------------------------------------------
     
  public:
*************** public:
*** 947,954 ****
  throw cpu_memory_fault (pc, address, s, "data write");
        }
 
-
-
    // ------------------------------------------------------------------------
    // Derived classes for memory access functions of various endianness
 
--- 1038,1043 ----