public inbox for sid@sourceware.org
 help / color / mirror / Atom feed
* [patch][commit] Hardware Watchpoint Support
@ 2005-11-14 20:14 Dave Brolley
  0 siblings, 0 replies; only message in thread
From: Dave Brolley @ 2005-11-14 20:14 UTC (permalink / raw)
  To: sid

[-- Attachment #1: Type: text/plain, Size: 217 bytes --]

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

[-- Attachment #2: sid-hw-watchpoint.ChangeLog --]
[-- Type: text/plain, Size: 884 bytes --]

sid/component/gdb/ChangeLog:
2005-11-14  Dave Brolley  <brolley@redhat.com>

	* 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  <brolley@redhat.com>

	* 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.


[-- Attachment #3: sid-hw-watchpoint.patch.txt --]
[-- Type: text/plain, Size: 12768 bytes --]

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 ----

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-11-14 20:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-11-14 20:14 [patch][commit] Hardware Watchpoint Support Dave Brolley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).