From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22424 invoked by alias); 14 Nov 2005 20:14:35 -0000 Received: (qmail 22389 invoked by uid 22791); 14 Nov 2005 20:14:30 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Mon, 14 Nov 2005 20:14:30 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id jAEKETef004946 for ; Mon, 14 Nov 2005 15:14:29 -0500 Received: from pobox.toronto.redhat.com (pobox.toronto.redhat.com [172.16.14.4]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id jAEKEOV17798 for ; Mon, 14 Nov 2005 15:14:24 -0500 Received: from [172.16.14.227] (IDENT:2+Vg54uh77zu7K20Wk355nZUYTiWku2o@topaz.toronto.redhat.com [172.16.14.227]) by pobox.toronto.redhat.com (8.12.8/8.12.8) with ESMTP id jAEKENQm004990 for ; Mon, 14 Nov 2005 15:14:23 -0500 Message-ID: <4378F01F.3090506@redhat.com> Date: Mon, 14 Nov 2005 20:14:00 -0000 From: Dave Brolley User-Agent: Mozilla Thunderbird 1.0.2 (X11/20050317) MIME-Version: 1.0 To: sid@sources.redhat.com Subject: [patch][commit] Hardware Watchpoint Support Content-Type: multipart/mixed; boundary="------------040408090900030001040704" Mailing-List: contact sid-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: sid-owner@sourceware.org X-SW-Source: 2005-q4/txt/msg00009.txt.bz2 This is a multi-part message in MIME format. --------------040408090900030001040704 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 217 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 --------------040408090900030001040704 Content-Type: text/plain; name="sid-hw-watchpoint.ChangeLog" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sid-hw-watchpoint.ChangeLog" Content-length: 884 sid/component/gdb/ChangeLog: 2005-11-14 Dave Brolley * 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 * 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. --------------040408090900030001040704 Content-Type: text/plain; name="sid-hw-watchpoint.patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sid-hw-watchpoint.patch.txt" Content-length: 12768 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 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 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%xx:change ! std::vector tokens = sidutil::tokenize (name, ":"); ! if (tokens.size () != 3 || tokens[0] != "watch" || tokens[2] != "change") ! return s; ! ! // gdb%xxwatchpoint%xx%xx ! 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 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 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 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 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 ---- --------------040408090900030001040704--