[patch][commit] Hardware Watchpoint Support

Dave Brolley <[email protected]>
Newsgroups gmane.comp.emulators.sid.devel
Message-ID <[email protected]>
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-hw-watchpoint.ChangeLog (text/plain, 884 B)
sid/component/gdb/ChangeLog:
2005-11-14  Dave Brolley  <[email protected]>

	* 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  <[email protected]>

	* 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.
sid-hw-watchpoint.patch.txt (text/plain, 12.5 KB)
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 ----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.