debugger: add 'gp' command

gp 'go privilege' starts execution until the privilege mode
changes. This can be used to break on task switches. I.e on m68k,
one could do:

gp { ~sr & 0x2000 && crp_aptr == 0x1234567 }

which would execute until the privilege mode changes to user mode and
the CPU root pointer is 0x1234567.

for cpu code, all that is needed to make this work is calling
debugger_privilege_hook() when the execution level changes.
This commit is contained in:
Sven Schnelle 2018-11-06 14:57:00 +01:00
parent 25987a5fdc
commit 12f43029dc
6 changed files with 89 additions and 2 deletions

View File

@ -1009,12 +1009,17 @@ inline void m68ki_branch_32(uint32_t offset)
*/
inline void m68ki_set_s_flag(uint32_t value)
{
uint32_t old_s_flag = m_s_flag;
/* Backup the old stack pointer */
REG_SP_BASE()[m_s_flag | ((m_s_flag>>1) & m_m_flag)] = REG_SP();
/* Set the S flag */
m_s_flag = value;
/* Set the new stack pointer */
REG_SP() = REG_SP_BASE()[m_s_flag | ((m_s_flag>>1) & m_m_flag)];
if ((old_s_flag ^ m_s_flag) & SFLAG_SET)
{
debugger_privilege_hook();
}
}
/* Set the S and M flags and change the active stack pointer.
@ -1022,6 +1027,7 @@ inline void m68ki_set_s_flag(uint32_t value)
*/
inline void m68ki_set_sm_flag(uint32_t value)
{
uint32_t old_s_flag = m_s_flag;
/* Backup the old stack pointer */
REG_SP_BASE()[m_s_flag | ((m_s_flag >> 1) & m_m_flag)] = REG_SP();
/* Set the S and M flags */
@ -1029,14 +1035,23 @@ inline void m68ki_set_sm_flag(uint32_t value)
m_m_flag = value & MFLAG_SET;
/* Set the new stack pointer */
REG_SP() = REG_SP_BASE()[m_s_flag | ((m_s_flag>>1) & m_m_flag)];
if ((old_s_flag ^ m_s_flag) & SFLAG_SET)
{
debugger_privilege_hook();
}
}
/* Set the S and M flags. Don't touch the stack pointer. */
inline void m68ki_set_sm_flag_nosp(uint32_t value)
{
uint32_t old_s_flag = m_s_flag;
/* Set the S and M flags */
m_s_flag = value & SFLAG_SET;
m_m_flag = value & MFLAG_SET;
if ((old_s_flag ^ m_s_flag) & SFLAG_SET)
{
debugger_privilege_hook();
}
}

View File

@ -160,6 +160,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("ge", CMDFLAG_NONE, 0, 0, 1, std::bind(&debugger_commands::execute_go_exception, this, _1, _2));
m_console.register_command("gtime", CMDFLAG_NONE, 0, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1, _2));
m_console.register_command("gt", CMDFLAG_NONE, 0, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1, _2));
m_console.register_command("gp", CMDFLAG_NONE, 0, 0, 1, std::bind(&debugger_commands::execute_go_privilege, this, _1, _2));
m_console.register_command("next", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_next, this, _1, _2));
m_console.register_command("n", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_next, this, _1, _2));
m_console.register_command("focus", CMDFLAG_NONE, 0, 1, 1, std::bind(&debugger_commands::execute_focus, this, _1, _2));
@ -899,6 +900,19 @@ void debugger_commands::execute_go_time(int ref, const std::vector<std::string>
}
/*-------------------------------------------------
execute_go_privilege - execute the gp command
-------------------------------------------------*/
void debugger_commands::execute_go_privilege(int ref, const std::vector<std::string> &params)
{
parsed_expression condition(&m_cpu.get_visible_cpu()->debug()->symtable());
if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
return;
m_cpu.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string());
}
/*-------------------------------------------------
execute_next - execute the next command
-------------------------------------------------*/

View File

@ -108,6 +108,7 @@ private:
void execute_go_interrupt(int ref, const std::vector<std::string> &params);
void execute_go_exception(int ref, const std::vector<std::string> &params);
void execute_go_time(int ref, const std::vector<std::string> &params);
void execute_go_privilege(int ref, const std::vector<std::string> &params);
void execute_focus(int ref, const std::vector<std::string> &params);
void execute_ignore(int ref, const std::vector<std::string> &params);
void execute_observe(int ref, const std::vector<std::string> &params);

View File

@ -1513,7 +1513,7 @@ void device_debug::interrupt_hook(int irqline)
void device_debug::exception_hook(int exception)
{
// see if this matches a pending interrupt request
// see if this matches an exception breakpoint
if ((m_flags & DEBUG_FLAG_STOP_EXCEPTION) != 0 && (m_stopexception == -1 || m_stopexception == exception))
{
m_device.machine().debugger().cpu().set_execution_stopped();
@ -1523,6 +1523,37 @@ void device_debug::exception_hook(int exception)
}
//-------------------------------------------------
// privilege_hook - called when privilege level is
// changed
//-------------------------------------------------
void device_debug::privilege_hook()
{
bool matched = 1;
if ((m_flags & DEBUG_FLAG_STOP_PRIVILEGE) != 0)
{
if (m_privilege_condition && !m_privilege_condition->is_empty())
{
try
{
matched = m_privilege_condition->execute();
}
catch (...)
{
}
}
if (matched)
{
m_device.machine().debugger().cpu().set_execution_stopped();
m_device.machine().debugger().console().printf("Stopped due to privilege change\n", m_device.tag());
compute_debug_flags();
}
}
}
//-------------------------------------------------
// instruction_hook - called by the CPU cores
// before executing each instruction
@ -1860,6 +1891,21 @@ void device_debug::go_milliseconds(u64 milliseconds)
}
//-------------------------------------------------
// go_privilege - execute until execution
// level changes
//-------------------------------------------------
void device_debug::go_privilege(const char *condition)
{
assert(m_exec != nullptr);
m_device.machine().rewind_invalidate();
m_privilege_condition = std::make_unique<parsed_expression>(&m_symtable, condition);
m_flags |= DEBUG_FLAG_STOP_PRIVILEGE;
m_device.machine().debugger().cpu().set_execution_running();
}
//-------------------------------------------------
// halt_on_next_instruction_impl - halt in the
// debugger on the next instruction, internal

View File

@ -181,6 +181,7 @@ public:
void stop_hook();
void interrupt_hook(int irqline);
void exception_hook(int exception);
void privilege_hook();
void instruction_hook(offs_t curpc);
// hooks into our operations
@ -205,6 +206,7 @@ public:
void go_interrupt(int irqline = -1);
void go_exception(int exception);
void go_milliseconds(u64 milliseconds);
void go_privilege(const char *condition);
void go_next_device();
template <typename Format, typename... Params>
@ -324,6 +326,7 @@ private:
attotime m_stoptime; // stop time for DEBUG_FLAG_STOP_TIME
int m_stopirq; // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT
int m_stopexception; // stop exception number for DEBUG_FLAG_STOP_EXCEPTION
std::unique_ptr<parsed_expression> m_privilege_condition; // expression to evaluate on privilege change
attotime m_endexectime; // ending time of the current execution
u64 m_total_cycles; // current total cycles
u64 m_last_total_cycles; // last total cycles
@ -459,11 +462,13 @@ private:
static constexpr u32 DEBUG_FLAG_STOP_TIME = 0x00002000; // there is a pending stop at cpu->stoptime
static constexpr u32 DEBUG_FLAG_SUSPENDED = 0x00004000; // CPU currently suspended
static constexpr u32 DEBUG_FLAG_LIVE_BP = 0x00010000; // there are live breakpoints for this CPU
static constexpr u32 DEBUG_FLAG_STOP_PRIVILEGE = 0x00020000; // run until execution level changes
static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT;
static constexpr u32 DEBUG_FLAG_TRACING_ANY = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER;
static constexpr u32 DEBUG_FLAG_TRANSIENT = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC |
DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK | DEBUG_FLAG_STOP_TIME;
DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK |
DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE;
};
//**************************************************************************

View File

@ -275,6 +275,12 @@ protected:
device().debug()->exception_hook(exception);
}
void debugger_privilege_hook()
{
if (device().machine().debug_flags & DEBUG_FLAG_ENABLED)
device().debug()->privilege_hook();
}
private:
// internal information about the state of inputs
class device_input