mirror of
https://github.com/holub/mame
synced 2025-04-24 17:30:55 +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
|
||||
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)
|
||||
{
|
||||
const char *action = nullptr;
|
||||
bool detect_loops = true;
|
||||
device_t *cpu;
|
||||
FILE *f = nullptr;
|
||||
const char *mode;
|
||||
@ -2455,7 +2480,9 @@ void debugger_commands::execute_trace_internal(int ref, int params, const char *
|
||||
/* validate parameters */
|
||||
if (!validate_cpu_parameter((params > 1) ? param[1] : nullptr, &cpu))
|
||||
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;
|
||||
|
||||
/* open the file */
|
||||
@ -2479,7 +2506,7 @@ void debugger_commands::execute_trace_internal(int ref, int params, const char *
|
||||
}
|
||||
|
||||
/* do it */
|
||||
cpu->debug()->trace(f, trace_over, action);
|
||||
cpu->debug()->trace(f, trace_over, detect_loops, action);
|
||||
if (f)
|
||||
m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename.c_str());
|
||||
else
|
||||
|
@ -25,6 +25,9 @@ class debugger_commands
|
||||
public:
|
||||
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 */
|
||||
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
|
||||
//-------------------------------------------------
|
||||
|
||||
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
|
||||
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, 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
|
||||
//-------------------------------------------------
|
||||
|
||||
device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, const char *action)
|
||||
: m_debug(debug),
|
||||
m_file(file),
|
||||
m_action((action != nullptr) ? action : ""),
|
||||
m_loops(0),
|
||||
m_nextdex(0),
|
||||
m_trace_over(trace_over),
|
||||
m_trace_over_target(~0)
|
||||
device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, const char *action)
|
||||
: m_debug(debug)
|
||||
, m_file(file)
|
||||
, m_action((action != nullptr) ? action : "")
|
||||
, m_detect_loops(detect_loops)
|
||||
, m_loops(0)
|
||||
, m_nextdex(0)
|
||||
, m_trace_over(trace_over)
|
||||
, m_trace_over_target(~0)
|
||||
{
|
||||
memset(m_history, 0, sizeof(m_history));
|
||||
}
|
||||
@ -3344,23 +3345,26 @@ void device_debug::tracer::update(offs_t pc)
|
||||
m_trace_over_target = ~0;
|
||||
}
|
||||
|
||||
// check for a loop condition
|
||||
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)
|
||||
if (m_detect_loops)
|
||||
{
|
||||
m_loops++;
|
||||
return;
|
||||
}
|
||||
// check for a loop condition
|
||||
int count = 0;
|
||||
for (auto & elem : m_history)
|
||||
if (elem == pc)
|
||||
count++;
|
||||
|
||||
// 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;
|
||||
// if more than 1 hit, just up the loop count and get out
|
||||
if (count > 1)
|
||||
{
|
||||
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
|
||||
if (!m_action.empty())
|
||||
|
@ -263,7 +263,7 @@ public:
|
||||
void track_mem_data_clear() { m_track_mem_set.clear(); }
|
||||
|
||||
// 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_flush() { if (m_trace != nullptr) m_trace->flush(); }
|
||||
|
||||
@ -336,7 +336,7 @@ private:
|
||||
class tracer
|
||||
{
|
||||
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();
|
||||
|
||||
void update(offs_t pc);
|
||||
@ -350,6 +350,7 @@ private:
|
||||
FILE & 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
|
||||
int m_loops; // number of instructions in a loop
|
||||
int m_nextdex; // next index
|
||||
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"
|
||||
" ignore [<cpu>[,<cpu>[,...]]] -- stops 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"
|
||||
" traceover {<filename>|OFF}[,<cpu>[,<action>]] -- trace the given CPU to a file, but skip subroutines (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>[,<detectloops>[,<action>]]] -- trace the given CPU to a file, but skip subroutines (defaults to active CPU)\n"
|
||||
" traceflush -- flushes all open trace files\n"
|
||||
},
|
||||
{
|
||||
@ -818,11 +818,14 @@ static const help_item static_help_list[] =
|
||||
{
|
||||
"trace",
|
||||
"\n"
|
||||
" trace {<filename>|OFF}[,<cpu>[,<action>]]\n"
|
||||
" trace {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]]\n"
|
||||
"\n"
|
||||
"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 "
|
||||
"<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 "
|
||||
"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 "
|
||||
@ -831,11 +834,14 @@ static const help_item static_help_list[] =
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"\n"
|
||||
"trace joust.tr\n"
|
||||
" Begin tracing the currently active CPU, logging output to joust.tr.\n"
|
||||
"\n"
|
||||
"trace dribling.tr,0\n"
|
||||
" Begin tracing the execution of CPU #0, logging output to dribling.tr.\n"
|
||||
"\n"
|
||||
"trace joust.tr\n"
|
||||
" Begin tracing the currently active CPU, logging output to joust.tr.\n"
|
||||
"trace starswep.tr,0,false\n"
|
||||
" Begin tracing the execution of CPU #0, logging output to starswep.tr, with loop detection disabled.\n"
|
||||
"\n"
|
||||
"trace >>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"
|
||||
" Turn off tracing on CPU #0.\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, "
|
||||
"output A=<aval> to the tracelog.\n"
|
||||
},
|
||||
{
|
||||
"traceover",
|
||||
"\n"
|
||||
" traceover {<filename>|OFF}[,<cpu>[,<action>]]\n"
|
||||
" traceover {<filename>|OFF}[,<cpu>[,<detectloops>[,<action>]]]\n"
|
||||
"\n"
|
||||
"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 "
|
||||
"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 "
|
||||
"<cpu> is omitted, 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 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 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"
|
||||
"<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 <cpu> is omitted, 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 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 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"
|
||||
"Examples:\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"
|
||||
" Begin tracing the currently active CPU, logging output to joust.tr.\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"
|
||||
" Turn off tracing on CPU #0.\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, "
|
||||
"output A=<aval> to the tracelog.\n"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user