mirror of
https://github.com/holub/mame
synced 2025-04-25 17:56:43 +03:00
Make loop collation optional for debugger trace and traceover commands
This commit is contained in:
parent
d3dd9f8f95
commit
c643372753
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user