Make loop collation optional for debugger trace and traceover commands

This commit is contained in:
therealmogminer@gmail.com 2016-07-14 16:13:52 +02:00
parent d3dd9f8f95
commit c643372753
5 changed files with 94 additions and 48 deletions

View File

@ -379,6 +379,30 @@ bool debugger_commands::validate_number_parameter(const char *param, UINT64 *res
} }
/*-------------------------------------------------
validate_boolean_parameter - validates a
boolean parameter
-------------------------------------------------*/
bool debugger_commands::validate_boolean_parameter(const char *param, bool *result)
{
/* nullptr parameter does nothing and returns no error */
if (param == nullptr)
return true;
/* evaluate the expression; success if no error */
bool is_true = (strcmp(param, "true") == 0 || strcmp(param, "TRUE") == 0 || strcmp(param, "1") == 0);
bool is_false = (strcmp(param, "false") == 0 || strcmp(param, "FALSE") == 0 || strcmp(param, "0") == 0);
if (!is_true && !is_false)
return false;
*result = is_true;
return true;
}
/*------------------------------------------------- /*-------------------------------------------------
validate_cpu_parameter - validates a validate_cpu_parameter - validates a
parameter as a cpu parameter as a cpu
@ -2444,6 +2468,7 @@ void debugger_commands::execute_dasm(int ref, int params, const char *param[])
void debugger_commands::execute_trace_internal(int ref, int params, const char *param[], bool trace_over) void debugger_commands::execute_trace_internal(int ref, int params, const char *param[], bool trace_over)
{ {
const char *action = nullptr; const char *action = nullptr;
bool detect_loops = true;
device_t *cpu; device_t *cpu;
FILE *f = nullptr; FILE *f = nullptr;
const char *mode; const char *mode;
@ -2455,7 +2480,9 @@ void debugger_commands::execute_trace_internal(int ref, int params, const char *
/* validate parameters */ /* validate parameters */
if (!validate_cpu_parameter((params > 1) ? param[1] : nullptr, &cpu)) if (!validate_cpu_parameter((params > 1) ? param[1] : nullptr, &cpu))
return; return;
if (!debug_command_parameter_command(action = param[2])) if (!validate_boolean_parameter((params > 2) ? param[2] : nullptr, &detect_loops))
return;
if (!debug_command_parameter_command(action = param[3]))
return; return;
/* open the file */ /* open the file */
@ -2479,7 +2506,7 @@ void debugger_commands::execute_trace_internal(int ref, int params, const char *
} }
/* do it */ /* do it */
cpu->debug()->trace(f, trace_over, action); cpu->debug()->trace(f, trace_over, detect_loops, action);
if (f) if (f)
m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename.c_str()); m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename.c_str());
else else

View File

@ -25,6 +25,9 @@ class debugger_commands
public: public:
debugger_commands(running_machine& machine, debugger_cpu& cpu, debugger_console& console); debugger_commands(running_machine& machine, debugger_cpu& cpu, debugger_console& console);
/* validates a parameter as a boolean value */
bool validate_boolean_parameter(const char *param, bool *result);
/* validates a parameter as a numeric value */ /* validates a parameter as a numeric value */
bool validate_number_parameter(const char *param, UINT64 *result); bool validate_number_parameter(const char *param, UINT64 *result);

View File

@ -2637,14 +2637,14 @@ UINT32 device_debug::compute_opcode_crc32(offs_t pc) const
// trace - trace execution of a given device // trace - trace execution of a given device
//------------------------------------------------- //-------------------------------------------------
void device_debug::trace(FILE *file, bool trace_over, const char *action) void device_debug::trace(FILE *file, bool trace_over, bool detect_loops, const char *action)
{ {
// delete any existing tracers // delete any existing tracers
m_trace = nullptr; m_trace = nullptr;
// if we have a new file, make a new tracer // if we have a new file, make a new tracer
if (file != nullptr) if (file != nullptr)
m_trace = std::make_unique<tracer>(*this, *file, trace_over, action); m_trace = std::make_unique<tracer>(*this, *file, trace_over, detect_loops, action);
} }
@ -3305,14 +3305,15 @@ bool device_debug::registerpoint::hit()
// tracer - constructor // tracer - constructor
//------------------------------------------------- //-------------------------------------------------
device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, const char *action) device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, const char *action)
: m_debug(debug), : m_debug(debug)
m_file(file), , m_file(file)
m_action((action != nullptr) ? action : ""), , m_action((action != nullptr) ? action : "")
m_loops(0), , m_detect_loops(detect_loops)
m_nextdex(0), , m_loops(0)
m_trace_over(trace_over), , m_nextdex(0)
m_trace_over_target(~0) , m_trace_over(trace_over)
, m_trace_over_target(~0)
{ {
memset(m_history, 0, sizeof(m_history)); memset(m_history, 0, sizeof(m_history));
} }
@ -3344,23 +3345,26 @@ void device_debug::tracer::update(offs_t pc)
m_trace_over_target = ~0; m_trace_over_target = ~0;
} }
// check for a loop condition if (m_detect_loops)
int count = 0;
for (auto & elem : m_history)
if (elem == pc)
count++;
// if more than 1 hit, just up the loop count and get out
if (count > 1)
{ {
m_loops++; // check for a loop condition
return; int count = 0;
} for (auto & elem : m_history)
if (elem == pc)
count++;
// if we just finished looping, indicate as much // if more than 1 hit, just up the loop count and get out
if (m_loops != 0) if (count > 1)
fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops); {
m_loops = 0; m_loops++;
return;
}
// if we just finished looping, indicate as much
if (m_loops != 0)
fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops);
m_loops = 0;
}
// execute any trace actions first // execute any trace actions first
if (!m_action.empty()) if (!m_action.empty())

View File

@ -263,7 +263,7 @@ public:
void track_mem_data_clear() { m_track_mem_set.clear(); } void track_mem_data_clear() { m_track_mem_set.clear(); }
// tracing // tracing
void trace(FILE *file, bool trace_over, const char *action); void trace(FILE *file, bool trace_over, bool detect_loops, const char *action);
void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3); void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3);
void trace_flush() { if (m_trace != nullptr) m_trace->flush(); } void trace_flush() { if (m_trace != nullptr) m_trace->flush(); }
@ -336,7 +336,7 @@ private:
class tracer class tracer
{ {
public: public:
tracer(device_debug &debug, FILE &file, bool trace_over, const char *action); tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, const char *action);
~tracer(); ~tracer();
void update(offs_t pc); void update(offs_t pc);
@ -350,6 +350,7 @@ private:
FILE & m_file; // tracing file for this CPU FILE & m_file; // tracing file for this CPU
std::string m_action; // action to perform during a trace std::string m_action; // action to perform during a trace
offs_t m_history[TRACE_LOOPS]; // history of recent PCs offs_t m_history[TRACE_LOOPS]; // history of recent PCs
bool m_detect_loops; // whether or not we should detect loops
int m_loops; // number of instructions in a loop int m_loops; // number of instructions in a loop
int m_nextdex; // next index int m_nextdex; // next index
bool m_trace_over; // true if we're tracing over bool m_trace_over; // true if we're tracing over

View File

@ -140,8 +140,8 @@ static const help_item static_help_list[] =
" focus <cpu> -- focuses debugger only on <cpu>\n" " focus <cpu> -- focuses debugger only on <cpu>\n"
" ignore [<cpu>[,<cpu>[,...]]] -- stops debugging on <cpu>\n" " ignore [<cpu>[,<cpu>[,...]]] -- stops debugging on <cpu>\n"
" observe [<cpu>[,<cpu>[,...]]] -- resumes debugging on <cpu>\n" " observe [<cpu>[,<cpu>[,...]]] -- resumes debugging on <cpu>\n"
" trace {<filename>|OFF}[,<cpu>[,<action>]] -- trace the given CPU to a file (defaults to active CPU)\n" " trace {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]] -- trace the given CPU to a file (defaults to active CPU)\n"
" traceover {<filename>|OFF}[,<cpu>[,<action>]] -- trace the given CPU to a file, but skip subroutines (defaults to active CPU)\n" " traceover {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]] -- trace the given CPU to a file, but skip subroutines (defaults to active CPU)\n"
" traceflush -- flushes all open trace files\n" " traceflush -- flushes all open trace files\n"
}, },
{ {
@ -818,11 +818,14 @@ static const help_item static_help_list[] =
{ {
"trace", "trace",
"\n" "\n"
" trace {<filename>|OFF}[,<cpu>[,<action>]]\n" " trace {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]]\n"
"\n" "\n"
"Starts or stops tracing of the execution of the specified <cpu>. If <cpu> is omitted, " "Starts or stops tracing of the execution of the specified <cpu>. If <cpu> is omitted, "
"the currently active CPU is specified. When enabling tracing, specify the filename in the " "the currently active CPU is specified. When enabling tracing, specify the filename in the "
"<filename> parameter. To disable tracing, substitute the keyword 'off' for <filename>. If you " "<filename> parameter. To disable tracing, substitute the keyword 'off' for <filename>. "
"<detectloops> should be either true or false. If <detectloops> is true or omitted, the trace "
"will have loops detected and condensed to a single line. If it is false, the trace will contain "
"every opcode as it is executed. If you "
"wish to log additional information on each trace, you can append an <action> parameter which " "wish to log additional information on each trace, you can append an <action> parameter which "
"is a command that is executed before each trace is logged. Generally, this is used to include " "is a command that is executed before each trace is logged. Generally, this is used to include "
"a 'tracelog' command. Note that you may need to embed the action within braces { } in order " "a 'tracelog' command. Note that you may need to embed the action within braces { } in order "
@ -831,11 +834,14 @@ static const help_item static_help_list[] =
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"trace joust.tr\n"
" Begin tracing the currently active CPU, logging output to joust.tr.\n"
"\n"
"trace dribling.tr,0\n" "trace dribling.tr,0\n"
" Begin tracing the execution of CPU #0, logging output to dribling.tr.\n" " Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
"\n" "\n"
"trace joust.tr\n" "trace starswep.tr,0,false\n"
" Begin tracing the currently active CPU, logging output to joust.tr.\n" " Begin tracing the execution of CPU #0, logging output to starswep.tr, with loop detection disabled.\n"
"\n" "\n"
"trace >>pigskin.tr\n" "trace >>pigskin.tr\n"
" Begin tracing the currently active CPU, appending log output to pigskin.tr.\n" " Begin tracing the currently active CPU, appending log output to pigskin.tr.\n"
@ -843,39 +849,44 @@ static const help_item static_help_list[] =
"trace off,0\n" "trace off,0\n"
" Turn off tracing on CPU #0.\n" " Turn off tracing on CPU #0.\n"
"\n" "\n"
"trace asteroid.tr,0,{tracelog \"A=%02X \",a}\n" "trace asteroid.tr,0,true,{tracelog \"A=%02X \",a}\n"
" Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, " " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
"output A=<aval> to the tracelog.\n" "output A=<aval> to the tracelog.\n"
}, },
{ {
"traceover", "traceover",
"\n" "\n"
" traceover {<filename>|OFF}[,<cpu>[,<action>]]\n" " traceover {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]]\n"
"\n" "\n"
"Starts or stops tracing of the execution of the specified <cpu>. When tracing reaches " "Starts or stops tracing of the execution of the specified <cpu>. When tracing reaches "
"a subroutine or call, tracing will skip over the subroutine. The same algorithm is used as is " "a subroutine or call, tracing will skip over the subroutine. The same algorithm is used as is "
"used in the step over command. This means that traceover will not work properly when calls " "used in the step over command. This means that traceover will not work properly when calls "
"are recusive or the return address is not immediately following the call instruction. If " "are recusive or the return address is not immediately following the call instruction. If "
"<cpu> is omitted, the currently active CPU is specified. When enabling tracing, specify the " "<detectloops> should be either true or false. If <detectloops> is true or omitted, the trace "
"filename in the <filename> parameter. To disable tracing, substitute the keyword 'off' for " "will have loops detected and condensed to a single line. If it is false, the trace will contain "
"<filename>. If you wish to log additional information on each trace, you can append an <action> " "every opcode as it is executed. If <cpu> is omitted, the currently active CPU is specified. When "
"parameter which is a command that is executed before each trace is logged. Generally, this is " "enabling tracing, specify the filename in the <filename> parameter. To disable tracing, substitute "
"used to include a 'tracelog' command. Note that you may need to embed the action within braces " "the keyword 'off' for <filename>. If you wish to log additional information on each trace, you can "
"{ } in order to prevent commas and semicolons from being interpreted as applying to the trace " "append an <action> parameter which is a command that is executed before each trace is logged. "
"command itself.\n" "Generally, this is used to include a 'tracelog' command. 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 trace command itself.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
"traceover dribling.tr,0\n"
" Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
"\n"
"traceover joust.tr\n" "traceover joust.tr\n"
" Begin tracing the currently active CPU, logging output to joust.tr.\n" " Begin tracing the currently active CPU, logging output to joust.tr.\n"
"\n" "\n"
"traceover dribling.tr,0\n"
" Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
"\n"
"traceover starswep.tr,0,false\n"
" Begin tracing the execution of CPU #0, logging output to starswep.tr, with loop detection disabled.\n"
"\n"
"traceover off,0\n" "traceover off,0\n"
" Turn off tracing on CPU #0.\n" " Turn off tracing on CPU #0.\n"
"\n" "\n"
"traceover asteroid.tr,0,{tracelog \"A=%02X \",a}\n" "traceover asteroid.tr,0,true,{tracelog \"A=%02X \",a}\n"
" Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, " " Begin tracing the execution of CPU #0, logging output to asteroid.tr. Before each line, "
"output A=<aval> to the tracelog.\n" "output A=<aval> to the tracelog.\n"
}, },