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