summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2022-08-28 13:27:35 -0400
committer AJR <ajrhacker@users.noreply.github.com>2022-08-28 13:31:50 -0400
commitd8d588262de1f11a529b208e470cff9b89a4cba6 (patch)
treefbeff8d28cb8538d527b8e3cc6c3df572d495189 /src/emu
parentf52b402f2416ddfd646afe2d132c16d78c6fe9c3 (diff)
Debugger changes
- Added exception points as a new class of "points" triggering on specific exception numbers, with a similar set of commands to breakpoints and registerpoints. - Removed the per-instruction callback hook from device_debug. Only one driver was using this (rmnimbus.cpp), and what it was doing with it could be done more cleanly with exception points. - Change the type of the action string parameter for "points"-creating methods and make some parameters optional for those. - Change trace file logging to use a std::ostream instead of FILE * to take better advantage of strformat.
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/debug/debugcmd.cpp269
-rw-r--r--src/emu/debug/debugcmd.h4
-rw-r--r--src/emu/debug/debugcpu.cpp211
-rw-r--r--src/emu/debug/debugcpu.h45
-rw-r--r--src/emu/debug/debughlp.cpp99
-rw-r--r--src/emu/debug/dvbpoints.cpp2
-rw-r--r--src/emu/debug/dvrpoints.cpp2
-rw-r--r--src/emu/debug/points.cpp68
-rw-r--r--src/emu/debug/points.h48
-rw-r--r--src/emu/emufwd.h1
10 files changed, 597 insertions, 152 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 7ef0110031e..30ad53d762b 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -282,6 +282,13 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("rpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1));
m_console.register_command("rplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rplist, this, _1));
+ m_console.register_command("epset", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("ep", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("epclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epclear, this, _1));
+ m_console.register_command("epdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, false, _1));
+ m_console.register_command("epenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, true, _1));
+ m_console.register_command("eplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_eplist, this, _1));
+
m_console.register_command("statesave", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("ss", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("stateload", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1));
@@ -471,8 +478,9 @@ bool debugger_commands::validate_boolean_parameter(std::string_view param, bool
return true;
// evaluate the expression; success if no error
- bool const is_true = util::streqlower(param, "true");
- bool const is_false = util::streqlower(param, "false");
+ using namespace std::literals;
+ bool const is_true = util::streqlower(param, "true"sv);
+ bool const is_false = util::streqlower(param, "false"sv);
if (is_true || is_false)
{
@@ -1153,7 +1161,7 @@ void debugger_commands::execute_tracelog(const std::vector<std::string_view> &pa
/* then do a printf */
std::ostringstream buffer;
if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str().c_str());
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1189,7 +1197,7 @@ void debugger_commands::execute_tracesym(const std::vector<std::string_view> &pa
// then do a printf
std::ostringstream buffer;
if (mini_printf(buffer, format.str(), params.size(), values))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str().c_str());
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1819,12 +1827,12 @@ void debugger_commands::execute_bpset(const std::vector<std::string_view> &param
return;
// param 3 is the action
- std::string action;
+ std::string_view action;
if (params.size() > 2 && !debug_command_parameter_command(action = params[2]))
return;
// set the breakpoint
- int const bpnum = debug->breakpoint_set(address, condition.is_empty() ? nullptr : condition.original_string(), action.c_str());
+ int const bpnum = debug->breakpoint_set(address, condition.is_empty() ? nullptr : condition.original_string(), action);
m_console.printf("Breakpoint %X set\n", bpnum);
}
@@ -1966,16 +1974,20 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
// param 3 is the type
read_or_write type;
- if (util::streqlower(params[2], "r"))
- type = read_or_write::READ;
- else if (util::streqlower(params[2], "w"))
- type = read_or_write::WRITE;
- else if (util::streqlower(params[2], "rw") || util::streqlower(params[2], "wr"))
- type = read_or_write::READWRITE;
- else
{
- m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[2], "r"sv))
+ type = read_or_write::READ;
+ else if (streqlower(params[2], "w"sv))
+ type = read_or_write::WRITE;
+ else if (streqlower(params[2], "rw"sv) || streqlower(params[2], "wr"sv))
+ type = read_or_write::READWRITE;
+ else
+ {
+ m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
+ return;
+ }
}
// param 4 is the condition
@@ -1984,12 +1996,12 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
return;
// param 5 is the action
- std::string action;
+ std::string_view action;
if (params.size() > 4 && !debug_command_parameter_command(action = params[4]))
return;
// set the watchpoint
- int const wpnum = debug->watchpoint_set(*space, type, address, length, (condition.is_empty()) ? nullptr : condition.original_string(), action.c_str());
+ int const wpnum = debug->watchpoint_set(*space, type, address, length, (condition.is_empty()) ? nullptr : condition.original_string(), action);
m_console.printf("Watchpoint %X set\n", wpnum);
}
@@ -2133,12 +2145,12 @@ void debugger_commands::execute_rpset(const std::vector<std::string_view> &param
return;
// param 2 is the action
- std::string action;
+ std::string_view action;
if (params.size() > 1 && !debug_command_parameter_command(action = params[1]))
return;
// set the registerpoint
- int const rpnum = cpu->debug()->registerpoint_set(condition.original_string(), action.c_str());
+ int const rpnum = cpu->debug()->registerpoint_set(condition.original_string(), action);
m_console.printf("Registerpoint %X set\n", rpnum);
}
@@ -2201,6 +2213,148 @@ void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::
}
+//-------------------------------------------------
+// execute_epset - execute the exception point
+// set command
+//-------------------------------------------------
+
+void debugger_commands::execute_epset(const std::vector<std::string_view> &params)
+{
+ // CPU is implicit
+ device_t *cpu;
+ if (!validate_cpu_parameter(std::string_view(), cpu))
+ return;
+
+ // param 1 is the exception type
+ u64 type;
+ if (!validate_number_parameter(params[0], type))
+ return;
+
+ // param 2 is the condition
+ parsed_expression condition(cpu->debug()->symtable());
+ if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition))
+ return;
+
+ // param 3 is the action
+ std::string_view action;
+ if (params.size() > 2 && !debug_command_parameter_command(action = params[2]))
+ return;
+
+ // set the exception point
+ int epnum = cpu->debug()->exceptionpoint_set(type, (condition.is_empty()) ? nullptr : condition.original_string(), action);
+ m_console.printf("Exception point %X set\n", epnum);
+}
+
+
+//-------------------------------------------------
+// execute_epclear - execute the exception point
+// clear command
+//-------------------------------------------------
+
+void debugger_commands::execute_epclear(const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, clear all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_clear_all();
+ m_console.printf("Cleared all exception points\n");
+ }
+ else // otherwise, clear the specific ones
+ {
+ execute_index_command(
+ params,
+ [this] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_clear(param))
+ return false;
+ m_console.printf("Exception point %X cleared\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_epdisenable - execute the exception
+// point disable/enable commands
+//-------------------------------------------------
+
+void debugger_commands::execute_epdisenable(bool enable, const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, disable/enable all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_enable_all(enable);
+ m_console.printf(enable ? "Enabled all exception points\n" : "Disabled all exception points\n");
+ }
+ else // otherwise, disable/enable the specific ones
+ {
+ execute_index_command(
+ params,
+ [this, enable] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_enable(param, enable))
+ return false;
+ m_console.printf(enable ? "Exception point %X enabled\n" : "Exception point %X disabled\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_eplist - execute the exception point
+// list command
+//-------------------------------------------------
+
+void debugger_commands::execute_eplist(const std::vector<std::string_view> &params)
+{
+ int printed = 0;
+ std::string buffer;
+ auto const apply =
+ [this, &printed, &buffer] (device_t &device)
+ {
+ if (!device.debug()->exceptionpoint_list().empty())
+ {
+ m_console.printf("Device '%s' exception points:\n", device.tag());
+
+ // loop over the exception points
+ for (const auto &epp : device.debug()->exceptionpoint_list())
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ buffer = string_format("%c%4X : %X", ep.enabled() ? ' ' : 'D', ep.index(), ep.type());
+ if (std::string(ep.condition()).compare("1") != 0)
+ buffer.append(string_format(" if %s", ep.condition()));
+ if (!ep.action().empty())
+ buffer.append(string_format(" do %s", ep.action()));
+ m_console.printf("%s\n", buffer);
+ printed++;
+ }
+ }
+ };
+
+ if (!params.empty())
+ {
+ device_t *cpu;
+ if (!validate_cpu_parameter(params[0], cpu))
+ return;
+ apply(*cpu);
+ if (!printed)
+ m_console.printf("No exception points currently installed for CPU %s\n", cpu->tag());
+ }
+ else
+ {
+ // loop over all CPUs
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ apply(device);
+ if (!printed)
+ m_console.printf("No exception points currently installed\n");
+ }
+}
+
+
/*-------------------------------------------------
execute_rplist - execute the registerpoint list
command
@@ -2221,7 +2375,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string_view> &para
for (const auto &rp : device.debug()->registerpoint_list())
{
buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition());
- if (rp.action() && *rp.action())
+ if (!rp.action().empty())
buffer.append(string_format(" do %s", rp.action()));
m_console.printf("%s\n", buffer);
printed++;
@@ -3129,30 +3283,34 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
// decode condition
u8 condition;
- if (util::streqlower(params[0], "all"))
- condition = CHEAT_ALL;
- else if (util::streqlower(params[0], "equal") || util::streqlower(params[0], "eq"))
- condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
- else if (util::streqlower(params[0], "notequal") || util::streqlower(params[0], "ne"))
- condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
- else if (util::streqlower(params[0], "decrease") || util::streqlower(params[0], "de") || params[0] == "-")
- condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
- else if (util::streqlower(params[0], "increase") || util::streqlower(params[0], "in") || params[0] == "+")
- condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
- else if (util::streqlower(params[0], "decreaseorequal") || util::streqlower(params[0], "deeq"))
- condition = CHEAT_DECREASE_OR_EQUAL;
- else if (util::streqlower(params[0], "increaseorequal") || util::streqlower(params[0], "ineq"))
- condition = CHEAT_INCREASE_OR_EQUAL;
- else if (util::streqlower(params[0], "smallerof") || util::streqlower(params[0], "lt") || params[0] == "<")
- condition = CHEAT_SMALLEROF;
- else if (util::streqlower(params[0], "greaterof") || util::streqlower(params[0], "gt") || params[0] == ">")
- condition = CHEAT_GREATEROF;
- else if (util::streqlower(params[0], "changedby") || util::streqlower(params[0], "ch") || params[0] == "~")
- condition = CHEAT_CHANGEDBY;
- else
{
- m_console.printf("Invalid condition type\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[0], "all"sv))
+ condition = CHEAT_ALL;
+ else if (streqlower(params[0], "equal"sv) || streqlower(params[0], "eq"sv))
+ condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
+ else if (streqlower(params[0], "notequal"sv) || streqlower(params[0], "ne"sv))
+ condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
+ else if (streqlower(params[0], "decrease"sv) || streqlower(params[0], "de"sv) || params[0] == "-"sv)
+ condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
+ else if (streqlower(params[0], "increase"sv) || streqlower(params[0], "in"sv) || params[0] == "+"sv)
+ condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
+ else if (streqlower(params[0], "decreaseorequal"sv) || streqlower(params[0], "deeq"sv))
+ condition = CHEAT_DECREASE_OR_EQUAL;
+ else if (streqlower(params[0], "increaseorequal"sv) || streqlower(params[0], "ineq"sv))
+ condition = CHEAT_INCREASE_OR_EQUAL;
+ else if (streqlower(params[0], "smallerof"sv) || streqlower(params[0], "lt"sv) || params[0] == "<"sv)
+ condition = CHEAT_SMALLEROF;
+ else if (streqlower(params[0], "greaterof"sv) || streqlower(params[0], "gt"sv) || params[0] == ">"sv)
+ condition = CHEAT_GREATEROF;
+ else if (streqlower(params[0], "changedby"sv) || streqlower(params[0], "ch"sv) || params[0] == "~"sv)
+ condition = CHEAT_CHANGEDBY;
+ else
+ {
+ m_console.printf("Invalid condition type\n");
+ return;
+ }
}
m_cheat.undo++;
@@ -3754,17 +3912,16 @@ void debugger_commands::execute_dasm(const std::vector<std::string_view> &params
void debugger_commands::execute_trace(const std::vector<std::string_view> &params, bool trace_over)
{
- std::string action;
+ std::string_view action;
bool detect_loops = true;
bool logerror = false;
- device_t *cpu;
- const char *mode;
std::string filename(params[0]);
// replace macros
strreplace(filename, "{game}", m_machine.basename());
// validate parameters
+ device_t *cpu;
if (!validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu))
return;
if (params.size() > 2)
@@ -3775,9 +3932,10 @@ void debugger_commands::execute_trace(const std::vector<std::string_view> &param
std::string flag;
while (std::getline(stream, flag, '|'))
{
- if (util::streqlower(flag, "noloop"))
+ using namespace std::literals;
+ if (util::streqlower(flag, "noloop"sv))
detect_loops = false;
- else if (util::streqlower(flag, "logerror"))
+ else if (util::streqlower(flag, "logerror"sv))
logerror = true;
else
{
@@ -3790,19 +3948,22 @@ void debugger_commands::execute_trace(const std::vector<std::string_view> &param
return;
// open the file
- FILE *f = nullptr;
- if (!util::streqlower(filename, "off"))
+ std::unique_ptr<std::ofstream> f;
+ using namespace std::literals;
+ if (!util::streqlower(filename, "off"sv))
{
- mode = "w";
+ std::ios_base::openmode mode = std::ios_base::out;
// opening for append?
if ((filename[0] == '>') && (filename[1] == '>'))
{
- mode = "a";
+ mode |= std::ios_base::ate;
filename = filename.substr(2);
}
+ else
+ mode |= std::ios_base::trunc;
- f = fopen(filename.c_str(), mode);
+ f = std::make_unique<std::ofstream>(filename.c_str(), mode);
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -3811,7 +3972,7 @@ void debugger_commands::execute_trace(const std::vector<std::string_view> &param
}
// do it
- cpu->debug()->trace(f, trace_over, detect_loops, logerror, action.c_str());
+ cpu->debug()->trace(std::move(f), trace_over, detect_loops, logerror, action);
if (f)
m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename);
else
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index 9ede662511a..8c5e29fecae 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -148,6 +148,10 @@ private:
void execute_rpclear(const std::vector<std::string_view> &params);
void execute_rpdisenable(bool enable, const std::vector<std::string_view> &params);
void execute_rplist(const std::vector<std::string_view> &params);
+ void execute_epset(const std::vector<std::string_view> &params);
+ void execute_epclear(const std::vector<std::string_view> &params);
+ void execute_epdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_eplist(const std::vector<std::string_view> &params);
void execute_statesave(const std::vector<std::string_view> &params);
void execute_stateload(const std::vector<std::string_view> &params);
void execute_rewind(const std::vector<std::string_view> &params);
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 820d9e72688..aba79d74036 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -47,6 +47,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
, m_bpindex(1)
, m_wpindex(1)
, m_rpindex(1)
+ , m_epindex(1)
, m_wpdata(0)
, m_wpaddr(0)
, m_wpsize(0)
@@ -424,7 +425,6 @@ device_debug::device_debug(device_t &device)
, m_disasm(nullptr)
, m_flags(0)
, m_symtable(std::make_unique<symbol_table>(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device))
- , m_instrhook(nullptr)
, m_stepaddr(0)
, m_stepsleft(0)
, m_delay_steps(0)
@@ -438,7 +438,8 @@ device_debug::device_debug(device_t &device)
, m_pc_history_index(0)
, m_pc_history_valid(0)
, m_bplist()
- , m_rplist(std::make_unique<std::forward_list<debug_registerpoint>>())
+ , m_rplist()
+ , m_eplist()
, m_triggered_breakpoint(nullptr)
, m_triggered_watchpoint(nullptr)
, m_trace(nullptr)
@@ -549,6 +550,7 @@ device_debug::~device_debug()
breakpoint_clear_all();
watchpoint_clear_all();
registerpoint_clear_all();
+ exceptionpoint_clear_all();
}
void device_debug::write_tracking(address_space &space, offs_t address, u64 data)
@@ -672,10 +674,39 @@ void device_debug::exception_hook(int exception)
if (matched)
{
m_device.machine().debugger().cpu().set_execution_stopped();
- m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %d, PC=%X)\n", m_device.tag(), exception, m_state->pcbase());
+ m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %X, PC=%X)\n", m_device.tag(), exception, m_state->pcbase());
compute_debug_flags();
}
}
+
+ // see if any exception points match
+ if (!m_eplist.empty())
+ {
+ auto epitp = m_eplist.equal_range(exception);
+ for (auto epit = epitp.first; epit != epitp.second; ++epit)
+ {
+ debug_exceptionpoint &ep = *epit->second;
+ if (ep.hit(exception))
+ {
+ // halt in the debugger by default
+ debugger_cpu &debugcpu = m_device.machine().debugger().cpu();
+ debugcpu.set_execution_stopped();
+
+ // if we hit, evaluate the action
+ if (!ep.m_action.empty())
+ m_device.machine().debugger().console().execute_command(ep.m_action, false);
+
+ // print a notification, unless the action made us go again
+ if (debugcpu.is_stopped())
+ {
+ debugcpu.set_execution_stopped();
+ m_device.machine().debugger().console().printf("Stopped at exception point %X (CPU '%s', PC=%X)\n", ep.m_index, m_device.tag(), exception, m_state->pcbase());
+ compute_debug_flags();
+ }
+ break;
+ }
+ }
+ }
}
@@ -744,10 +775,6 @@ void device_debug::instruction_hook(offs_t curpc)
if (m_trace != nullptr)
m_trace->update(curpc);
- // per-instruction hook?
- if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_HOOKED) != 0 && (*m_instrhook)(m_device, curpc))
- debugcpu.set_execution_stopped();
-
// handle single stepping
if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_STEPPING_ANY) != 0)
{
@@ -893,22 +920,6 @@ void device_debug::instruction_hook(offs_t curpc)
//-------------------------------------------------
-// set_instruction_hook - set a hook to be
-// called on each instruction for a given device
-//-------------------------------------------------
-
-void device_debug::set_instruction_hook(debug_instruction_hook_func hook)
-{
- // set the hook and also the CPU's flag for fast knowledge of the hook
- m_instrhook = hook;
- if (hook != nullptr)
- m_flags |= DEBUG_FLAG_HOOKED;
- else
- m_flags &= ~DEBUG_FLAG_HOOKED;
-}
-
-
-//-------------------------------------------------
// ignore - ignore/observe a given device
//-------------------------------------------------
@@ -1151,7 +1162,7 @@ const debug_breakpoint *device_debug::breakpoint_find(offs_t address) const
// returning its index
//-------------------------------------------------
-int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action)
+int device_debug::breakpoint_set(offs_t address, const char *condition, std::string_view action)
{
// allocate a new one and hook it into our list
u32 id = m_device.machine().debugger().cpu().get_breakpoint_index();
@@ -1238,7 +1249,7 @@ void device_debug::breakpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action)
+int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, std::string_view action)
{
if (space.spacenum() >= int(m_wplist.size()))
m_wplist.resize(space.spacenum()+1);
@@ -1325,15 +1336,15 @@ void device_debug::watchpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::registerpoint_set(const char *condition, const char *action)
+int device_debug::registerpoint_set(const char *condition, std::string_view action)
{
// allocate a new one
u32 id = m_device.machine().debugger().cpu().get_registerpoint_index();
- m_rplist->emplace_front(*m_symtable, id, condition, action);
+ m_rplist.emplace_front(*m_symtable, id, condition, action);
// update the flags and return the index
breakpoint_update_flags();
- return m_rplist->front().m_index;
+ return m_rplist.front().m_index;
}
@@ -1345,10 +1356,10 @@ int device_debug::registerpoint_set(const char *condition, const char *action)
bool device_debug::registerpoint_clear(int index)
{
// scan the list to see if we own this registerpoint
- for (auto brp = m_rplist->before_begin(); std::next(brp) != m_rplist->end(); ++brp)
+ for (auto brp = m_rplist.before_begin(); std::next(brp) != m_rplist.end(); ++brp)
if (std::next(brp)->m_index == index)
{
- m_rplist->erase_after(brp);
+ m_rplist.erase_after(brp);
breakpoint_update_flags();
return true;
}
@@ -1365,7 +1376,7 @@ bool device_debug::registerpoint_clear(int index)
void device_debug::registerpoint_clear_all()
{
// clear the list
- m_rplist->clear();
+ m_rplist.clear();
breakpoint_update_flags();
}
@@ -1378,7 +1389,7 @@ void device_debug::registerpoint_clear_all()
bool device_debug::registerpoint_enable(int index, bool enable)
{
// scan the list to see if we own this conditionpoint
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
if (rp.m_index == index)
{
rp.m_enabled = enable;
@@ -1399,12 +1410,97 @@ bool device_debug::registerpoint_enable(int index, bool enable)
void device_debug::registerpoint_enable_all(bool enable)
{
// apply the enable to all registerpoints we own
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
registerpoint_enable(rp.index(), enable);
}
//-------------------------------------------------
+// exceptionpoint_set - set a new exception
+// point, returning its index
+//-------------------------------------------------
+
+int device_debug::exceptionpoint_set(int exception, const char *condition, std::string_view action)
+{
+ // allocate a new one and hook it into our list
+ u32 id = m_device.machine().debugger().cpu().get_exceptionpoint_index();
+ m_eplist.emplace(exception, std::make_unique<debug_exceptionpoint>(this, *m_symtable, id, exception, condition, action));
+
+ // return the index
+ return id;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear - clear an exception
+// point by index, returning true if we found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_clear(int index)
+{
+ // scan the list to see if we own this breakpoint
+ for (auto epit = m_eplist.begin(); epit != m_eplist.end(); ++epit)
+ if (epit->second->m_index == index)
+ {
+ m_eplist.erase(epit);
+ return true;
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear_all - clear all exception
+// points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_clear_all()
+{
+ // clear the list
+ m_eplist.clear();
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable - enable/disable an
+// exception point by index, returning true if we
+// found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_enable(int index, bool enable)
+{
+ // scan the list to see if we own this exception point
+ for (auto &epp : m_eplist)
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ if (ep.m_index == index)
+ {
+ ep.m_enabled = enable;
+ return true;
+ }
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable_all - enable/disable all
+// exception points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_enable_all(bool enable)
+{
+ // apply the enable to all exception points we own
+ for (auto &epp : m_eplist)
+ exceptionpoint_enable(epp.second->index(), enable);
+}
+
+
+//-------------------------------------------------
// history_pc - return an entry from the PC
// history
//-------------------------------------------------
@@ -1600,31 +1696,14 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const
// trace - trace execution of a given device
//-------------------------------------------------
-void device_debug::trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+void device_debug::trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
{
// delete any existing tracers
m_trace = nullptr;
// if we have a new file, make a new tracer
if (file != nullptr)
- m_trace = std::make_unique<tracer>(*this, *file, trace_over, detect_loops, logerror, action);
-}
-
-
-//-------------------------------------------------
-// trace_printf - output data into the given
-// device's tracefile, if tracing
-//-------------------------------------------------
-
-void device_debug::trace_printf(const char *fmt, ...)
-{
- if (m_trace != nullptr)
- {
- va_list va;
- va_start(va, fmt);
- m_trace->vprintf(fmt, va);
- va_end(va);
- }
+ m_trace = std::make_unique<tracer>(*this, std::move(file), trace_over, detect_loops, logerror, action);
}
@@ -1652,7 +1731,7 @@ void device_debug::compute_debug_flags()
// if we're tracking history, or we're hooked, or stepping, or stopping at a breakpoint
// make sure we call the hook
- if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_HOOKED | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
+ if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
// also call if we are tracing
@@ -1753,7 +1832,7 @@ void device_debug::breakpoint_update_flags()
if (!(m_flags & DEBUG_FLAG_LIVE_BP))
{
// see if there are any enabled registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.m_enabled)
{
@@ -1803,7 +1882,7 @@ void device_debug::breakpoint_check(offs_t pc)
}
// see if we have any matching registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.hit())
{
@@ -1836,10 +1915,10 @@ void device_debug::breakpoint_check(offs_t pc)
// tracer - constructor
//-------------------------------------------------
-device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+device_debug::tracer::tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
: m_debug(debug)
- , m_file(file)
- , m_action((action != nullptr) ? action : "")
+ , m_file(std::move(file))
+ , m_action(action)
, m_detect_loops(detect_loops)
, m_logerror(logerror)
, m_loops(0)
@@ -1858,7 +1937,7 @@ device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, b
device_debug::tracer::~tracer()
{
// make sure we close the file if we can
- fclose(&m_file);
+ m_file.reset();
}
@@ -1894,7 +1973,7 @@ void device_debug::tracer::update(offs_t pc)
// if we just finished looping, indicate as much
if (m_loops != 0)
- fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops);
+ util::stream_format(*m_file, "\n (loops for %d instructions)\n\n", m_loops);
m_loops = 0;
}
@@ -1909,7 +1988,7 @@ void device_debug::tracer::update(offs_t pc)
buffer.disassemble(pc, instruction, next_pc, size, dasmresult);
// output the result
- fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str());
+ util::stream_format(*m_file, "%s: %s\n", buffer.pc_to_string(pc), instruction);
// do we need to step the trace over this instruction?
if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
@@ -1927,7 +2006,7 @@ void device_debug::tracer::update(offs_t pc)
// log this PC
m_nextdex = (m_nextdex + 1) % TRACE_LOOPS;
m_history[m_nextdex] = pc;
- fflush(&m_file);
+ m_file->flush();
}
@@ -1935,11 +2014,11 @@ void device_debug::tracer::update(offs_t pc)
// vprintf - generic print to the trace file
//-------------------------------------------------
-void device_debug::tracer::vprintf(const char *format, va_list va)
+void device_debug::tracer::vprintf(util::format_argument_pack<std::ostream> const &args)
{
// pass through to the file
- vfprintf(&m_file, format, va);
- fflush(&m_file);
+ util::stream_format(*m_file, args);
+ m_file->flush();
}
@@ -1950,7 +2029,7 @@ void device_debug::tracer::vprintf(const char *format, va_list va)
void device_debug::tracer::flush()
{
- fflush(&m_file);
+ m_file->flush();
}
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index d9fc3f64eae..416581071a7 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -29,9 +29,6 @@ constexpr int COMMENT_VERSION = 1;
// TYPE DEFINITIONS
//**************************************************************************
-typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc);
-
-
// ======================> device_debug
// [TODO] This whole thing is terrible.
@@ -59,9 +56,6 @@ public:
void privilege_hook();
void instruction_hook(offs_t curpc);
- // hooks into our operations
- void set_instruction_hook(debug_instruction_hook_func hook);
-
// debugger focus
void ignore(bool ignore = true);
bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); }
@@ -94,7 +88,7 @@ public:
// breakpoints
const auto &breakpoint_list() const { return m_bplist; }
const debug_breakpoint *breakpoint_find(offs_t address) const;
- int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr);
+ int breakpoint_set(offs_t address, const char *condition = nullptr, std::string_view action = {});
bool breakpoint_clear(int index);
void breakpoint_clear_all();
bool breakpoint_enable(int index, bool enable = true);
@@ -104,7 +98,7 @@ public:
// watchpoints
int watchpoint_space_count() const { return m_wplist.size(); }
const std::vector<std::unique_ptr<debug_watchpoint>> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; }
- int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action);
+ int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition = nullptr, std::string_view action = {});
bool watchpoint_clear(int wpnum);
void watchpoint_clear_all();
bool watchpoint_enable(int index, bool enable = true);
@@ -113,12 +107,20 @@ public:
debug_watchpoint *triggered_watchpoint() { debug_watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; }
// registerpoints
- const std::forward_list<debug_registerpoint> &registerpoint_list() const { return *m_rplist; }
- int registerpoint_set(const char *condition, const char *action = nullptr);
+ const std::forward_list<debug_registerpoint> &registerpoint_list() const { return m_rplist; }
+ int registerpoint_set(const char *condition, std::string_view action = {});
bool registerpoint_clear(int index);
void registerpoint_clear_all();
bool registerpoint_enable(int index, bool enable = true);
- void registerpoint_enable_all(bool enable = true );
+ void registerpoint_enable_all(bool enable = true);
+
+ // exception points
+ const auto &exceptionpoint_list() const { return m_eplist; }
+ int exceptionpoint_set(int exception, const char *condition = nullptr, std::string_view action = {});
+ bool exceptionpoint_clear(int index);
+ void exceptionpoint_clear_all();
+ bool exceptionpoint_enable(int index, bool enable = true);
+ void exceptionpoint_enable_all(bool enable = true);
// comments
void comment_add(offs_t address, const char *comment, rgb_t color);
@@ -147,8 +149,12 @@ public:
void track_mem_data_clear() { m_track_mem_set.clear(); }
// tracing
- void trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action);
- void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3);
+ void trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
+ template <typename Format, typename... Params> void trace_printf(Format &&fmt, Params &&...args)
+ {
+ if (m_trace != nullptr)
+ m_trace->vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
void trace_flush() { if (m_trace != nullptr) m_trace->flush(); }
void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; }
@@ -182,7 +188,6 @@ private:
// global state
u32 m_flags; // debugging flags for this CPU
std::unique_ptr<symbol_table> m_symtable; // symbol table for expression evaluation
- debug_instruction_hook_func m_instrhook; // per-instruction callback hook
// stepping information
offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER or DEBUG_FLAG_STEPPING_BRANCH
@@ -208,7 +213,8 @@ private:
// breakpoints and watchpoints
std::multimap<offs_t, std::unique_ptr<debug_breakpoint>> m_bplist; // list of breakpoints
std::vector<std::vector<std::unique_ptr<debug_watchpoint>>> m_wplist; // watchpoint lists for each address space
- std::unique_ptr<std::forward_list<debug_registerpoint>> m_rplist; // list of registerpoints
+ std::forward_list<debug_registerpoint> m_rplist; // list of registerpoints
+ std::multimap<offs_t, std::unique_ptr<debug_exceptionpoint>> m_eplist; // list of exception points
debug_breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered
debug_watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered
@@ -217,11 +223,11 @@ private:
class tracer
{
public:
- tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action);
+ tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
~tracer();
void update(offs_t pc);
- void vprintf(const char *format, va_list va);
+ void vprintf(util::format_argument_pack<std::ostream> const &args);
void flush();
bool logerror() const { return m_logerror; }
@@ -229,7 +235,7 @@ private:
static const int TRACE_LOOPS = 64;
device_debug & m_debug; // reference to our owner
- FILE & m_file; // tracing file for this CPU
+ std::unique_ptr<std::ostream> m_file; // tracing file for this CPU
std::string m_action; // action to perform during a trace
offs_t m_history[TRACE_LOOPS]; // history of recent PCs
bool m_detect_loops; // whether or not we should detect loops
@@ -312,7 +318,6 @@ private:
static constexpr u32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history
static constexpr u32 DEBUG_FLAG_TRACING = 0x00000004; // tracing this CPU
static constexpr u32 DEBUG_FLAG_TRACING_OVER = 0x00000008; // tracing this CPU with step over behavior
- static constexpr u32 DEBUG_FLAG_HOOKED = 0x00000010; // per-instruction callback hook
static constexpr u32 DEBUG_FLAG_STEPPING = 0x00000020; // CPU is single stepping
static constexpr u32 DEBUG_FLAG_STEPPING_OVER = 0x00000040; // CPU is stepping over a function
static constexpr u32 DEBUG_FLAG_STEPPING_OUT = 0x00000080; // CPU is stepping out of a function
@@ -384,6 +389,7 @@ public:
u32 get_breakpoint_index() { return m_bpindex++; }
u32 get_watchpoint_index() { return m_wpindex++; }
u32 get_registerpoint_index() { return m_rpindex++; }
+ u32 get_exceptionpoint_index() { return m_epindex++; }
// setters
void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; }
@@ -426,6 +432,7 @@ private:
u32 m_bpindex;
u32 m_wpindex;
u32 m_rpindex;
+ u32 m_epindex;
u64 m_wpdata;
u64 m_wpaddr;
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index a62704c5472..85de3984020 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -46,6 +46,7 @@ const help_item f_static_help_list[] =
" Breakpoints\n"
" Watchpoints\n"
" Registerpoints\n"
+ " Exception Points\n"
" Expressions\n"
" Comments\n"
" Cheats\n"
@@ -191,6 +192,18 @@ const help_item f_static_help_list[] =
" rplist [<CPU>] -- lists all the registerpoints\n"
},
{
+ "exceptionpoints",
+ "\n"
+ "Exception Point Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]] -- sets exception point on <type>\n"
+ " epclear [<epnum>] -- clears a given exception point or all if no <epnum> specified\n"
+ " epdisable [<epnum>] -- disabled a given exception point or all if no <epnum> specified\n"
+ " epenable [<epnum>] -- enables a given exception point or all if no <epnum> specified\n"
+ " eplist -- lists all the registerpoints\n"
+ },
+ {
"expressions",
"\n"
"Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is "
@@ -1555,6 +1568,92 @@ const help_item f_static_help_list[] =
"actions attached to them.\n"
},
{
+ "epset",
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]]\n"
+ "\n"
+ "Sets a new exception point for exceptions of type <type> on the currently visible CPU. "
+ "The optional <condition> parameter lets you specify an expression that will be evaluated "
+ "each time the exception point is hit. If the result of the expression is true (non-zero), "
+ "the exception point will actually halt execution at the start of the exception handler; "
+ "otherwise, execution will continue with no notification. The optional <action> parameter "
+ "provides a command that is executed whenever the exception point is hit and the "
+ "<condition> is true. Note that you may need to embed the action within braces { } in order "
+ "to prevent commas and semicolons from being interpreted as applying to the epset command "
+ "itself.\n"
+ "\n"
+ "The numbering of exceptions depends upon the CPU type. Causes of exceptions may include "
+ "internally or externally vectored interrupts, errors occurring within instructions and "
+ "system calls.\n"
+ "\n"
+ "Each exception point that is set is assigned an index which can be used in other "
+ "exception point commands to reference this exception point.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "ep 2\n"
+ " Set an exception that will halt execution whenever the visible CPU raises exception "
+ "number 2.\n"
+ },
+ {
+ "epclear",
+ "\n"
+ " epclear [<epnum>[,...]]\n"
+ "\n"
+ "The epclear command clears exception points. If <epnum> is specified, only the requested "
+ "exception points are cleared, otherwise all exception points are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epclear 3\n"
+ " Clear exception point index 3.\n"
+ "\n"
+ "epclear\n"
+ " Clear all exception points.\n"
+ },
+ {
+ "epdisable",
+ "\n"
+ " epdisable [<epnum>[,...]]\n"
+ "\n"
+ "The epdisable command disables exception points. If <epnum> is specified, only the requested "
+ "exception points are disabled, otherwise all exception points are disabled. Note that "
+ "disabling an exception point does not delete it, it just temporarily marks the exception "
+ "point as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epdisable 3\n"
+ " Disable exception point index 3.\n"
+ "\n"
+ "epdisable\n"
+ " Disable all exception points.\n"
+ },
+ {
+ "epenable",
+ "\n"
+ " epenable [<epnum>[,...]]\n"
+ "\n"
+ "The epenable command enables exception points. If <epnum> is specified, only the "
+ "requested exception points are enabled, otherwise all exception points are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epenable 3\n"
+ " Enable exception point index 3.\n"
+ "\n"
+ "epenable\n"
+ " Enable all exception points.\n"
+ },
+ {
+ "eplist",
+ "\n"
+ " eplist\n"
+ "\n"
+ "The eplist command lists all the current exception points, along with their index and "
+ "any conditions or actions attached to them.\n"
+ },
+ {
"map",
"\n"
" map[{d|i|o}] <address>[:<space>]\n"
diff --git a/src/emu/debug/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp
index b42b86a0e90..d7be62c1eaa 100644
--- a/src/emu/debug/dvbpoints.cpp
+++ b/src/emu/debug/dvbpoints.cpp
@@ -71,7 +71,7 @@ static bool cConditionDescending(const debug_breakpoint *a, const debug_breakpoi
static bool cActionAscending(const debug_breakpoint *a, const debug_breakpoint *b)
{
- return strcmp(a->action(), b->action()) < 0;
+ return a->action() < b->action();
}
static bool cActionDescending(const debug_breakpoint *a, const debug_breakpoint *b)
diff --git a/src/emu/debug/dvrpoints.cpp b/src/emu/debug/dvrpoints.cpp
index 3ecadaec8e5..7295a1b2170 100644
--- a/src/emu/debug/dvrpoints.cpp
+++ b/src/emu/debug/dvrpoints.cpp
@@ -62,7 +62,7 @@ bool cConditionDescending(std::pair<device_t *, debug_registerpoint const *> con
bool cActionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
- return strcmp(a.second->action(), b.second->action()) < 0;
+ return a.second->action() < b.second->action();
}
bool cActionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
diff --git a/src/emu/debug/points.cpp b/src/emu/debug/points.cpp
index a19f0ab5619..961488eebb2 100644
--- a/src/emu/debug/points.cpp
+++ b/src/emu/debug/points.cpp
@@ -28,13 +28,13 @@ debug_breakpoint::debug_breakpoint(
int index,
offs_t address,
const char *condition,
- const char *action) :
+ std::string_view action) :
m_debugInterface(debugInterface),
m_index(index),
m_enabled(true),
m_address(address),
m_condition(symbols, condition ? condition : "1"),
- m_action(action ? action : "")
+ m_action(action)
{
}
@@ -88,7 +88,7 @@ debug_watchpoint::debug_watchpoint(
offs_t address,
offs_t length,
const char *condition,
- const char *action) :
+ std::string_view action) :
m_debugInterface(debugInterface),
m_phr(nullptr),
m_phw(nullptr),
@@ -99,7 +99,7 @@ debug_watchpoint::debug_watchpoint(
m_address(address & space.addrmask()),
m_length(length),
m_condition(symbols, condition ? condition : "1"),
- m_action(action ? action : ""),
+ m_action(action),
m_installing(false)
{
std::fill(std::begin(m_start_address), std::end(m_start_address), 0);
@@ -431,11 +431,11 @@ void debug_watchpoint::triggered(read_or_write type, offs_t address, u64 data, u
// debug_registerpoint - constructor
//-------------------------------------------------
-debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action)
+debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action)
: m_index(index),
m_enabled(true),
m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : "")
+ m_action(action)
{
}
@@ -465,3 +465,59 @@ bool debug_registerpoint::hit()
return true;
}
+
+
+//**************************************************************************
+// DEBUG EXCEPTION POINT
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_exceptionpoint - constructor
+//-------------------------------------------------
+
+debug_exceptionpoint::debug_exceptionpoint(
+ device_debug *debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition,
+ std::string_view action)
+ : m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_type(type),
+ m_condition(symbols, (condition != nullptr) ? condition : "1"),
+ m_action(action)
+{
+}
+
+
+//-------------------------------------------------
+// hit - detect a hit
+//-------------------------------------------------
+
+bool debug_exceptionpoint::hit(int exception)
+{
+ // don't hit if disabled
+ if (!m_enabled)
+ return false;
+
+ // must match our type
+ if (m_type != exception)
+ return false;
+
+ // must satisfy the condition
+ if (!m_condition.is_empty())
+ {
+ try
+ {
+ return (m_condition.execute() != 0);
+ }
+ catch (expression_error &)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h
index 62ad953626c..42abd46398f 100644
--- a/src/emu/debug/points.h
+++ b/src/emu/debug/points.h
@@ -36,7 +36,7 @@ public:
int index,
offs_t address,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
// getters
const device_debug *debugInterface() const { return m_debugInterface; }
@@ -44,7 +44,7 @@ public:
bool enabled() const { return m_enabled; }
offs_t address() const { return m_address; }
const char *condition() const { return m_condition.original_string(); }
- const char *action() const { return m_action.c_str(); }
+ const std::string &action() const { return m_action; }
// setters
void setEnabled(bool value) { m_enabled = value; } // FIXME: need to update breakpoint flags but it's a private method
@@ -77,7 +77,7 @@ public:
offs_t address,
offs_t length,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
~debug_watchpoint();
// getters
@@ -128,13 +128,13 @@ class debug_registerpoint
public:
// construction/destruction
- debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr);
+ debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action = {});
// getters
int index() const { return m_index; }
bool enabled() const { return m_enabled; }
const char *condition() const { return m_condition.original_string(); }
- const char *action() const { return m_action.c_str(); }
+ const std::string &action() const { return m_action; }
private:
// internals
@@ -146,4 +146,42 @@ private:
std::string m_action; // action
};
+// ======================> debug_exceptionpoint
+
+class debug_exceptionpoint
+{
+ friend class device_debug;
+
+public:
+ // construction/destruction
+ debug_exceptionpoint(
+ device_debug* debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition = nullptr,
+ std::string_view action = {});
+
+ // getters
+ const device_debug *debugInterface() const { return m_debugInterface; }
+ int index() const { return m_index; }
+ bool enabled() const { return m_enabled; }
+ int type() const { return m_type; }
+ const char *condition() const { return m_condition.original_string(); }
+ const std::string &action() const { return m_action; }
+
+ // setters
+ void setEnabled(bool value) { m_enabled = value; }
+
+private:
+ // internals
+ bool hit(int exception);
+ const device_debug * m_debugInterface; // the interface we were created from
+ int m_index; // user reported index
+ bool m_enabled; // enabled?
+ int m_type; // exception type
+ parsed_expression m_condition; // condition
+ std::string m_action; // action
+};
+
#endif // MAME_EMU_DEBUG_POINTS_H
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index 48146615bce..323a0f14898 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -99,6 +99,7 @@ class symbol_table;
class debug_breakpoint;
class debug_watchpoint;
class debug_registerpoint;
+class debug_exceptionpoint;
// declared in debugger.h
class debugger_manager;