From 0747f93602e155ab411deaf8d35c88ea18cbffa2 Mon Sep 17 00:00:00 2001 From: AJR Date: Sat, 29 Oct 2022 19:23:51 -0400 Subject: Move debugger command parameter validation helpers into debugger_console --- src/devices/cpu/arm7/arm7.cpp | 3 +- src/devices/machine/acorn_memc.cpp | 3 +- src/devices/machine/sun4c_mmu.cpp | 3 +- src/emu/debug/debugcmd.cpp | 680 ++++++------------------------------- src/emu/debug/debugcmd.h | 26 -- src/emu/debug/debugcon.cpp | 492 ++++++++++++++++++++++++++- src/emu/debug/debugcon.h | 34 +- src/mame/konami/konamim2.cpp | 3 +- src/mame/microsoft/xbox.cpp | 3 - src/mame/midway/midtunit_v.cpp | 5 +- src/mame/rm/rmnimbus_v.cpp | 3 +- src/mame/sega/chihiro.cpp | 5 +- src/mame/sega/model2_m.cpp | 1 - src/mame/shared/xbox.cpp | 34 +- src/mame/sun/sun4.cpp | 1 - 15 files changed, 645 insertions(+), 651 deletions(-) diff --git a/src/devices/cpu/arm7/arm7.cpp b/src/devices/cpu/arm7/arm7.cpp index abdf3d98b58..d2c40209dd1 100644 --- a/src/devices/cpu/arm7/arm7.cpp +++ b/src/devices/cpu/arm7/arm7.cpp @@ -32,7 +32,6 @@ TODO: #include "emu.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include "arm7.h" #include "arm7core.h" //include arm7 core @@ -876,7 +875,7 @@ void arm7_cpu_device::translate_command(const std::vector &par { uint64_t vaddr; - if (!machine().debugger().commands().validate_number_parameter(params[0], vaddr)) return; + if (!machine().debugger().console().validate_number_parameter(params[0], vaddr)) return; vaddr &= 0xffffffff; diff --git a/src/devices/machine/acorn_memc.cpp b/src/devices/machine/acorn_memc.cpp index 5b05df7254f..c8b12050478 100644 --- a/src/devices/machine/acorn_memc.cpp +++ b/src/devices/machine/acorn_memc.cpp @@ -14,7 +14,6 @@ #include "acorn_memc.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include @@ -54,7 +53,7 @@ device_memory_interface::space_config_vector acorn_memc_device::memory_space_con void acorn_memc_device::memc_map_debug_commands(const std::vector ¶ms) { uint64_t offset; - if (params.size() != 1 || !machine().debugger().commands().validate_number_parameter(params[0], offset)) + if (params.size() != 1 || !machine().debugger().console().validate_number_parameter(params[0], offset)) return; // figure out the page number and offset in the page diff --git a/src/devices/machine/sun4c_mmu.cpp b/src/devices/machine/sun4c_mmu.cpp index f5dfe643f4f..91686a42fdf 100644 --- a/src/devices/machine/sun4c_mmu.cpp +++ b/src/devices/machine/sun4c_mmu.cpp @@ -12,7 +12,6 @@ #include "cpu/sparc/sparc.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" DEFINE_DEVICE_TYPE(SUN4_MMU, sun4_mmu_device, "sun4_mmu", "Sun 4 MMU") @@ -986,7 +985,7 @@ void sun4_mmu_base_device::l2p_command(const std::vector ¶ { uint64_t addr, offset; - if (!machine().debugger().commands().validate_number_parameter(params[0], addr)) return; + if (!machine().debugger().console().validate_number_parameter(params[0], addr)) return; addr &= 0xffffffff; offset = addr >> 2; diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 1e14db5b6df..4ccb88fbe20 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -36,35 +36,6 @@ -namespace { - -template -inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim) -{ - unsigned parens = 0; - for (std::string_view::size_type i = 0; str.length() > i; ++i) - { - if (str[i] == '(') - { - ++parens; - } - else if (parens) - { - if (str[i] == ')') - --parens; - } - else if (is_delim(str[i])) - { - return i; - } - } - return std::string_view::npos; -} - -} // anonymous namespace - - - /*************************************************************************** CONSTANTS ***************************************************************************/ @@ -456,466 +427,9 @@ void debugger_commands::global_set(global_entry *global, u64 value) -/*************************************************************************** - PARAMETER VALIDATION HELPERS -***************************************************************************/ - -/// \brief Validate parameter as a Boolean value -/// -/// Validates a parameter as a Boolean value. Fixed strings and -/// expressions evaluating to numeric values are recognised. The result -/// is unchanged for an empty string. -/// \param [in] param The parameter string. -/// \param [in,out] result The default value on entry, and the value of -/// the parameter interpreted as a Boolean on success. Unchanged if -/// the parameter is an empty string. -/// \return true if the parameter is a valid Boolean value or an empty -/// string, or false otherwise. -bool debugger_commands::validate_boolean_parameter(std::string_view param, bool &result) -{ - // nullptr parameter does nothing and returns no error - if (param.empty()) - return true; - - // evaluate the expression; success if no error - 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) - { - result = is_true; - return true; - } - - // try to evaluate as a number - u64 val; - if (!validate_number_parameter(param, val)) - return false; - - result = val != 0; - return true; -} - - -/// \brief Validate parameter as a numeric value -/// -/// Parses the parameter as an expression and evaluates it as a number. -/// \param [in] param The parameter string. -/// \param [out] result The numeric value of the expression on success. -/// Unchanged on failure. -/// \return true if the parameter is a valid expression that evaluates -/// to a numeric value, or false otherwise. -bool debugger_commands::validate_number_parameter(std::string_view param, u64 &result) -{ - // evaluate the expression; success if no error - try - { - result = parsed_expression(m_console.visible_symtable(), param).execute(); - return true; - } - catch (expression_error const &error) - { - // print an error pointing to the character that caused it - m_console.printf("Error in expression: %s\n", param); - m_console.printf(" %*s^", error.offset(), ""); - m_console.printf("%s\n", error.code_string()); - return false; - } -} - - -/// \brief Validate parameter as a device -/// -/// Validates a parameter as a device identifier and retrieves the -/// device on success. A string corresponding to the tag of a device -/// refers to that device; an empty string refers to the current CPU -/// with debugger focus; any other string is parsed as an expression -/// and treated as an index of a device implementing -/// #device_execute_interface and #device_state_interface, and exposing -/// a generic PC base value. -/// \param [in] param The parameter string. -/// \param [out] result A pointer to the device on success, or unchanged -/// on failure. -/// \return true if the parameter refers to a device in the current -/// system, or false otherwise. -bool debugger_commands::validate_device_parameter(std::string_view param, device_t *&result) -{ - // if no parameter, use the visible CPU - if (param.empty()) - { - device_t *const current = m_console.get_visible_cpu(); - if (current) - { - result = current; - return true; - } - else - { - m_console.printf("No valid CPU is currently selected\n"); - return false; - } - } - - // next look for a tag match - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - device_t *device = base.subdevice(strmakelower(relative)); - if (device) - { - result = device; - return true; - } - - // then evaluate as an expression; on an error assume it was a tag - u64 cpunum; - try - { - cpunum = parsed_expression(m_console.visible_symtable(), param).execute(); - } - catch (expression_error &) - { - m_console.printf("Unable to find device '%s'\n", param); - return false; - } - - // attempt to find by numerical index - device = get_cpu_by_index(cpunum); - if (device) - { - result = device; - return true; - } - else - { - // if out of range, complain - m_console.printf("Invalid CPU index %u\n", cpunum); - return false; - } -} - - -/// \brief Validate a parameter as a CPU -/// -/// Validates a parameter as a CPU identifier. Uses the same rules as -/// #validate_device_parameter to identify devices, but additionally -/// checks that the device is a "CPU" for the debugger's purposes. -/// \param [in] The parameter string. -/// \param [out] result The device on success, or unchanged on failure. -/// \return true if the parameter refers to a CPU-like device in the -/// current system, or false otherwise. -bool debugger_commands::validate_cpu_parameter(std::string_view param, device_t *&result) -{ - // first do the standard device thing - device_t *device; - if (!validate_device_parameter(param, device)) - return false; - - // check that it's a "CPU" for the debugger's purposes - device_execute_interface const *execute; - if (device->interface(execute)) - { - result = device; - return true; - } - - m_console.printf("Device %s is not a CPU\n", device->name()); - return false; -} - - -/// \brief Validate a parameter as an address space identifier -/// -/// Validates a parameter as an address space identifier. Uses the same -/// rules as #validate_device_parameter to identify devices. If the -/// default address space number is negative, the first address space -/// exposed by the device will be used as the default. -/// \param [in] The parameter string. -/// \param [in] spacenum The default address space index. If negative, -/// the first address space exposed by the device (i.e. the address -/// space with the lowest index) will be used as the default. -/// \param [out] result The address space on success, or unchanged on -/// failure. -/// \return true if the parameter refers to an address space in the -/// current system, or false otherwise. -bool debugger_commands::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result) -{ - device_t *device; - std::string spacename; - if (param.empty()) - { - // if no parameter, use the visible CPU - device = m_console.get_visible_cpu(); - if (!device) - { - m_console.printf("No valid CPU is currently selected\n"); - return false; - } - } - else - { - // look for a tag match on the whole parameter value - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - device = base.subdevice(strmakelower(relative)); - - // if that failed, treat the last component as an address space - if (!device) - { - auto const delimiter = relative.find_last_of(":^"); - bool const found = std::string_view::npos != delimiter; - if (!found || (':' == relative[delimiter])) - { - spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0)); - relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter); - if (!relative.empty()) - device = base.subdevice(strmakelower(relative)); - else if (m_console.get_visible_cpu()) - device = m_console.get_visible_cpu(); - else - device = &m_machine.root_device(); - } - } - } - - // if still no device found, evaluate as an expression - if (!device) - { - u64 cpunum; - try - { - cpunum = parsed_expression(m_console.visible_symtable(), param).execute(); - } - catch (expression_error const &) - { - // parsing failed - assume it was a tag - m_console.printf("Unable to find device '%s'\n", param); - return false; - } - - // attempt to find by numerical index - device = get_cpu_by_index(cpunum); - if (!device) - { - // if out of range, complain - m_console.printf("Invalid CPU index %u\n", cpunum); - return false; - } - } - - // ensure the device implements the memory interface - device_memory_interface *memory; - if (!device->interface(memory)) - { - m_console.printf("No memory interface found for device %s\n", device->name()); - return false; - } - - // fall back to supplied default space if appropriate - if (spacename.empty() && (0 <= spacenum)) - { - if (memory->has_space(spacenum)) - { - result = &memory->space(spacenum); - return true; - } - else - { - m_console.printf("No matching memory space found for device '%s'\n", device->tag()); - return false; - } - } - - // otherwise find the specified space or fall back to the first populated space - for (int i = 0; memory->max_space_count() > i; ++i) - { - if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename))) - { - result = &memory->space(i); - return true; - } - } - - // report appropriate error message - if (spacename.empty()) - m_console.printf("No memory spaces found for device '%s'\n", device->tag()); - else - m_console.printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag()); - return false; -} - - -/// \brief Validate a parameter as a target address -/// -/// Validates a parameter as an numeric expression to use as an address -/// optionally followed by a colon and a device identifier. If the -/// device identifier is not presnt, the current CPU with debugger focus -/// is assumed. See #validate_device_parameter for information on how -/// device parametersare interpreted. -/// \param [in] The parameter string. -/// \param [in] spacenum The default address space index. If negative, -/// the first address space exposed by the device (i.e. the address -/// space with the lowest index) will be used as the default. -/// \param [out] space The address space on success, or unchanged on -/// failure. -/// \param [out] addr The address on success, or unchanged on failure. -/// \return true if the address is a valid expression evaluating to a -/// number and the address space is found, or false otherwise. -bool debugger_commands::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr) -{ - // check for the device delimiter - std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; }); - std::string_view device; - if (devdelim != std::string::npos) - device = param.substr(devdelim + 1); - - // parse the address first - u64 addrval; - if (!validate_number_parameter(param.substr(0, devdelim), addrval)) - return false; - - // find the address space - if (!validate_device_space_parameter(device, spacenum, space)) - return false; - - // set the address now that we have the space - addr = addrval; - return true; -} - - -/// \brief Validate a parameter as a memory region -/// -/// Validates a parameter as a memory region tag and retrieves the -/// specified memory region. -/// \param [in] The parameter string. -/// \param [out] result The memory region on success, or unchanged on -/// failure. -/// \return true if the parameter refers to a memory region in the -/// current system, or false otherwise. -bool debugger_commands::validate_memory_region_parameter(std::string_view param, memory_region *&result) -{ - auto const ®ions = m_machine.memory().regions(); - std::string_view relative = param; - device_t &base = get_device_search_base(relative); - auto const iter = regions.find(base.subtag(strmakelower(relative))); - if (regions.end() != iter) - { - result = iter->second.get(); - return true; - } - else - { - m_console.printf("No matching memory region found for '%s'\n", param); - return false; - } -} - - -/// \brief Get search base for device or address space parameter -/// -/// Handles prefix prefixes used to indicate that a device tag should be -/// interpreted relative to the selected CPU. Removes the recognised -/// prefixes from the parameter value. -/// \param [in,out] param The parameter string. Recognised prefixes -/// affecting the search base are removed, leaving a tag relative to -/// the base device. -/// \return A reference to the base device that the tag should be -/// interpreted relative to. -device_t &debugger_commands::get_device_search_base(std::string_view ¶m) -{ - if (!param.empty()) - { - // handle ".:" or ".^" prefix for tag relative to current CPU if any - if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1]))) - { - param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1); - device_t *const current = m_console.get_visible_cpu(); - return current ? *current : m_machine.root_device(); - } - - // a sibling path makes most sense relative to current CPU - if ('^' == param[0]) - { - device_t *const current = m_console.get_visible_cpu(); - return current ? *current : m_machine.root_device(); - } - } - - - // default to root device - return m_machine.root_device(); -} - - -/// \brief Get CPU by index -/// -/// Looks up a CPU by the number the debugger assigns it based on its -/// position in the device tree relative to other CPUs. -/// \param [in] cpunum Zero-based index of the CPU to find. -/// \return A pointer to the CPU if found, or \c nullptr if no CPU has -/// the specified index. -device_t *debugger_commands::get_cpu_by_index(u64 cpunum) -{ - unsigned index = 0; - for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device())) - { - // real CPUs should have pcbase - device_state_interface const *state; - if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE)) - { - if (index++ == cpunum) - { - return &exec.device(); - } - } - } - return nullptr; -} - - -/*------------------------------------------------- - debug_command_parameter_expression - validates - an expression parameter --------------------------------------------------*/ - -bool debugger_commands::debug_command_parameter_expression(std::string_view param, parsed_expression &result) -{ - try - { - // parse the expression; success if no error - result.parse(param); - return true; - } - catch (expression_error const &err) - { - // output an error - m_console.printf("Error in expression: %s\n", param); - m_console.printf(" %*s^", err.offset(), ""); - m_console.printf("%s\n", err.code_string()); - return false; - } -} - - -/*------------------------------------------------- - debug_command_parameter_command - validates a - command parameter --------------------------------------------------*/ - -bool debugger_commands::debug_command_parameter_command(std::string_view param) -{ - /* validate the comment; success if no error */ - CMDERR err = m_console.validate_command(param); - if (err.error_class() == CMDERR::NONE) - return true; - - /* output an error */ - m_console.printf("Error in command: %s\n", param); - m_console.printf(" %*s^", err.error_offset(), ""); - m_console.printf("%s\n", debugger_console::cmderr_to_string(err)); - return 0; -} +//************************************************************************** +// COMMAND IMPLEMENTATIONS +//************************************************************************** /*------------------------------------------------- execute_help - execute the help command @@ -939,7 +453,7 @@ void debugger_commands::execute_print(const std::vector ¶m /* validate the other parameters */ u64 values[MAX_COMMAND_PARAMS]; for (int i = 0; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; /* then print each one */ @@ -1088,7 +602,7 @@ void debugger_commands::execute_index_command(std::vector cons std::vector index(params.size()); for (int paramnum = 0; paramnum < params.size(); paramnum++) { - if (!validate_number_parameter(params[paramnum], index[paramnum])) + if (!m_console.validate_number_parameter(params[paramnum], index[paramnum])) return; } @@ -1117,7 +631,7 @@ void debugger_commands::execute_printf(const std::vector ¶ /* validate the other parameters */ u64 values[MAX_COMMAND_PARAMS]; for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; /* then do a printf */ @@ -1136,7 +650,7 @@ void debugger_commands::execute_logerror(const std::vector &pa /* validate the other parameters */ u64 values[MAX_COMMAND_PARAMS]; for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; /* then do a printf */ @@ -1155,7 +669,7 @@ void debugger_commands::execute_tracelog(const std::vector &pa /* validate the other parameters */ u64 values[MAX_COMMAND_PARAMS]; for (int i = 1; i < params.size(); i++) - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; /* then do a printf */ @@ -1190,7 +704,7 @@ void debugger_commands::execute_tracesym(const std::vector &pa sym->format().empty() ? "%16X" : sym->format()); // validate the parameter - if (!validate_number_parameter(params[i], values[i])) + if (!m_console.validate_number_parameter(params[i], values[i])) return; } @@ -1229,7 +743,7 @@ void debugger_commands::execute_quit(const std::vector ¶ms void debugger_commands::execute_do(const std::vector ¶ms) { u64 dummy; - validate_number_parameter(params[0], dummy); + m_console.validate_number_parameter(params[0], dummy); } @@ -1241,7 +755,7 @@ void debugger_commands::execute_step(const std::vector ¶ms { /* if we have a parameter, use it */ u64 steps = 1; - if (params.size() > 0 && !validate_number_parameter(params[0], steps)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps)) return; m_console.get_visible_cpu()->debug()->single_step(steps); @@ -1256,7 +770,7 @@ void debugger_commands::execute_over(const std::vector ¶ms { /* if we have a parameter, use it */ u64 steps = 1; - if (params.size() > 0 && !validate_number_parameter(params[0], steps)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps)) return; m_console.get_visible_cpu()->debug()->single_step_over(steps); @@ -1282,7 +796,7 @@ void debugger_commands::execute_go(const std::vector ¶ms) u64 addr = ~0; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], addr)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], addr)) return; m_console.get_visible_cpu()->debug()->go(addr); @@ -1309,7 +823,7 @@ void debugger_commands::execute_go_interrupt(const std::vector u64 irqline = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], irqline)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], irqline)) return; m_console.get_visible_cpu()->debug()->go_interrupt(irqline); @@ -1324,11 +838,11 @@ void debugger_commands::execute_go_exception(const std::vector u64 exception = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], exception)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], exception)) return; parsed_expression condition(m_console.visible_symtable()); - if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition)) + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) return; m_console.get_visible_cpu()->debug()->go_exception(exception, condition.is_empty() ? "1" : condition.original_string()); @@ -1344,7 +858,7 @@ void debugger_commands::execute_go_time(const std::vector &par u64 milliseconds = -1; /* if we have a parameter, use it instead */ - if (params.size() > 0 && !validate_number_parameter(params[0], milliseconds)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], milliseconds)) return; m_console.get_visible_cpu()->debug()->go_milliseconds(milliseconds); @@ -1358,7 +872,7 @@ void debugger_commands::execute_go_time(const std::vector &par void debugger_commands::execute_go_privilege(const std::vector ¶ms) { parsed_expression condition(m_console.visible_symtable()); - if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) return; m_console.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string()); @@ -1372,7 +886,7 @@ void debugger_commands::execute_go_privilege(const std::vector void debugger_commands::execute_go_branch(bool sense, const std::vector ¶ms) { parsed_expression condition(m_console.visible_symtable()); - if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) return; m_console.get_visible_cpu()->debug()->go_branch(sense, (condition.is_empty()) ? "1" : condition.original_string()); @@ -1389,7 +903,7 @@ void debugger_commands::execute_go_next_instruction(const std::vector 0 && !validate_number_parameter(params[0], count)) + if (params.size() > 0 && !m_console.validate_number_parameter(params[0], count)) return; if (count == 0) return; @@ -1400,7 +914,7 @@ void debugger_commands::execute_go_next_instruction(const std::vectorinterface(stateintf)) { m_console.printf("No state interface available for %s\n", cpu->name()); @@ -1438,7 +952,7 @@ void debugger_commands::execute_focus(const std::vector ¶m { // validate params device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; // first clear the ignore flag on the focused CPU @@ -1488,7 +1002,7 @@ void debugger_commands::execute_ignore(const std::vector ¶ // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; // set the ignore flags @@ -1551,7 +1065,7 @@ void debugger_commands::execute_observe(const std::vector &par // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; // clear the ignore flags @@ -1597,7 +1111,7 @@ void debugger_commands::execute_suspend(const std::vector &par // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; for (int paramnum = 0; paramnum < params.size(); paramnum++) @@ -1656,7 +1170,7 @@ void debugger_commands::execute_resume(const std::vector ¶ // validate parameters for (int paramnum = 0; paramnum < params.size(); paramnum++) - if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum])) + if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum])) return; for (int paramnum = 0; paramnum < params.size(); paramnum++) @@ -1699,12 +1213,12 @@ void debugger_commands::execute_comment_add(const std::vector { // param 1 is the address for the comment u64 address; - if (!validate_number_parameter(params[0], address)) + if (!m_console.validate_number_parameter(params[0], address)) return; // CPU parameter is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // make sure param 2 exists @@ -1729,12 +1243,12 @@ void debugger_commands::execute_comment_del(const std::vector { // param 1 can either be a command or the address for the comment u64 address; - if (!validate_number_parameter(params[0], address)) + if (!m_console.validate_number_parameter(params[0], address)) return; // CPU parameter is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // If it's a number, it must be an address @@ -1804,7 +1318,7 @@ void debugger_commands::execute_bpset(const std::vector ¶m // param 1 is the address/CPU u64 address; address_space *space; - if (!validate_target_address_parameter(params[0], AS_PROGRAM, space, address)) + if (!m_console.validate_target_address_parameter(params[0], AS_PROGRAM, space, address)) return; device_execute_interface const *execute; @@ -1823,12 +1337,12 @@ void debugger_commands::execute_bpset(const std::vector ¶m // param 2 is the condition parsed_expression condition(debug->symtable()); - if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition)) + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) return; // param 3 is the action std::string_view action; - if (params.size() > 2 && !debug_command_parameter_command(action = params[2])) + if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2])) return; // set the breakpoint @@ -1929,7 +1443,7 @@ void debugger_commands::execute_bplist(const std::vector ¶ if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -1957,7 +1471,7 @@ void debugger_commands::execute_wpset(int spacenum, const std::vectordevice().debug(); // param 2 is the length - if (!validate_number_parameter(params[1], length)) + if (!m_console.validate_number_parameter(params[1], length)) return; // param 3 is the type @@ -1992,12 +1506,12 @@ void debugger_commands::execute_wpset(int spacenum, const std::vectorsymtable()); - if (params.size() > 3 && !debug_command_parameter_expression(params[3], condition)) + if (params.size() > 3 && !m_console.validate_expression_parameter(params[3], condition)) return; // param 5 is the action std::string_view action; - if (params.size() > 4 && !debug_command_parameter_command(action = params[4])) + if (params.size() > 4 && !m_console.validate_command_parameter(action = params[4])) return; // set the watchpoint @@ -2110,7 +1624,7 @@ void debugger_commands::execute_wplist(const std::vector ¶ if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -2136,17 +1650,17 @@ void debugger_commands::execute_rpset(const std::vector ¶m { // CPU is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // param 1 is the condition parsed_expression condition(cpu->debug()->symtable()); - if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) + if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition)) return; // param 2 is the action std::string_view action; - if (params.size() > 1 && !debug_command_parameter_command(action = params[1])) + if (params.size() > 1 && !m_console.validate_command_parameter(action = params[1])) return; // set the registerpoint @@ -2222,22 +1736,22 @@ void debugger_commands::execute_epset(const std::vector ¶m { // CPU is implicit device_t *cpu; - if (!validate_cpu_parameter(std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(std::string_view(), cpu)) return; // param 1 is the exception type u64 type; - if (!validate_number_parameter(params[0], type)) + if (!m_console.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)) + if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition)) return; // param 3 is the action std::string_view action; - if (params.size() > 2 && !debug_command_parameter_command(action = params[2])) + if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2])) return; // set the exception point @@ -2338,7 +1852,7 @@ void debugger_commands::execute_eplist(const std::vector ¶ if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -2386,7 +1900,7 @@ void debugger_commands::execute_rplist(const std::vector ¶ if (!params.empty()) { device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; apply(*cpu); if (!printed) @@ -2461,9 +1975,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector & memory_region *region; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (!validate_memory_region_parameter(params[3], region)) + if (!m_console.validate_memory_region_parameter(params[3], region)) return; if (offset >= region->bytes()) @@ -2589,9 +2103,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector 2 && !validate_number_parameter(params[2], length)) + if (params.size() > 2 && !m_console.validate_number_parameter(params[2], length)) return; // open the file @@ -2698,11 +2212,11 @@ void debugger_commands::execute_loadregion(const std::vector & memory_region *region; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (!validate_memory_region_parameter(params[3], region)) + if (!m_console.validate_memory_region_parameter(params[3], region)) return; if (offset >= region->bytes()) @@ -2746,23 +2260,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector 3 && !validate_number_parameter(params[3], width)) + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width)) return; bool ascii = true; - if (params.size() > 4 && !validate_boolean_parameter(params[4], ascii)) + if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii)) return; u64 rowsize = space->byte_to_address(16); - if (params.size() > 5 && !validate_number_parameter(params[5], rowsize)) + if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize)) return; int shift = space->addr_shift(); @@ -2907,19 +2421,19 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector 3 && !validate_number_parameter(params[3], term)) + if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term)) return; address_space *space; - if (!validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space)) + if (!m_console.validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space)) return; // further validation @@ -3150,7 +2664,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector 3) ? params[3] : std::string_view(), -1, space)) + if (!m_console.validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space)) return; } @@ -3160,9 +2674,9 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector 1 && !validate_number_parameter(params[1], comp_value)) + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], comp_value)) return; comp_value = m_cheat.sign_extend(comp_value); @@ -3580,9 +3094,9 @@ void debugger_commands::execute_find(int spacenum, const std::vector ¶ms address_space *space; // validate parameters - if (!validate_number_parameter(params[1], offset)) + if (!m_console.validate_number_parameter(params[1], offset)) return; - if (!validate_number_parameter(params[2], length)) + if (!m_console.validate_number_parameter(params[2], length)) return; - if (params.size() > 3 && !validate_boolean_parameter(params[3], bytes)) + if (params.size() > 3 && !m_console.validate_boolean_parameter(params[3], bytes)) return; - if (!validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space)) + if (!m_console.validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space)) return; // determine the width of the bytes @@ -3922,7 +3436,7 @@ void debugger_commands::execute_trace(const std::vector ¶m // validate parameters device_t *cpu; - if (!validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu)) return; if (params.size() > 2) { @@ -3944,7 +3458,7 @@ void debugger_commands::execute_trace(const std::vector ¶m } } } - if (params.size() > 3 && !debug_command_parameter_command(action = params[3])) + if (params.size() > 3 && !m_console.validate_command_parameter(action = params[3])) return; // open the file @@ -3999,11 +3513,11 @@ void debugger_commands::execute_history(const std::vector &par { // validate parameters device_t *device; - if (!validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device)) + if (!m_console.validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device)) return; u64 count = device_debug::HISTORY_SIZE; - if (params.size() > 1 && !validate_number_parameter(params[1], count)) + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], count)) return; // further validation @@ -4047,12 +3561,12 @@ void debugger_commands::execute_trackpc(const std::vector &par { // Gather the on/off switch (if present) bool turnOn = true; - if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn)) + if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn)) return; // Gather the cpu id (if present) device_t *cpu = nullptr; - if (!validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu)) + if (!m_console.validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu)) return; const device_state_interface *state; @@ -4064,7 +3578,7 @@ void debugger_commands::execute_trackpc(const std::vector &par // Should we clear the existing data? bool clear = false; - if (params.size() > 2 && !validate_boolean_parameter(params[2], clear)) + if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear)) return; cpu->debug()->set_track_pc((bool)turnOn); @@ -4096,7 +3610,7 @@ void debugger_commands::execute_trackmem(const std::vector &pa { // Gather the on/off switch (if present) bool turnOn = true; - if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn)) + if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn)) return; // Gather the cpu id (if present) @@ -4104,17 +3618,17 @@ void debugger_commands::execute_trackmem(const std::vector &pa if (params.size() > 1) cpuparam = params[1]; device_t *cpu = nullptr; - if (!validate_cpu_parameter(cpuparam, cpu)) + if (!m_console.validate_cpu_parameter(cpuparam, cpu)) return; // Should we clear the existing data? bool clear = false; - if (params.size() > 2 && !validate_boolean_parameter(params[2], clear)) + if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear)) return; // Get the address space for the given cpu address_space *space; - if (!validate_device_space_parameter(cpuparam, AS_PROGRAM, space)) + if (!m_console.validate_device_space_parameter(cpuparam, AS_PROGRAM, space)) return; // Inform the CPU it's time to start tracking memory writes @@ -4135,7 +3649,7 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector ¶ms else { u64 scrnum = 0; - if (params.size() > 1 && !validate_number_parameter(params[1], scrnum)) + if (params.size() > 1 && !m_console.validate_number_parameter(params[1], scrnum)) return; screen_device_enumerator iter(m_machine.root_device()); @@ -4244,7 +3758,7 @@ void debugger_commands::execute_map(int spacenum, const std::vector ¶ms) { device_t *root = &m_machine.root_device(); - if ((params.size() >= 2) && !validate_device_parameter(params[1], root)) + if ((params.size() >= 2) && !m_console.validate_device_parameter(params[1], root)) return; using namespace std::literals; @@ -4349,7 +3863,7 @@ void debugger_commands::execute_symlist(const std::vector &par { // validate parameters device_t *cpu; - if (!validate_cpu_parameter(params[0], cpu)) + if (!m_console.validate_cpu_parameter(params[0], cpu)) return; symtable = &cpu->debug()->symtable(); m_console.printf("CPU '%s' symbols:\n", cpu->tag()); diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index 8c5e29fecae..97d1a628ab5 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -24,27 +24,6 @@ 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(std::string_view param, bool &result); - - // validates a parameter as a numeric value - bool validate_number_parameter(std::string_view param, u64 &result); - - // validates a parameter as a device - bool validate_device_parameter(std::string_view param, device_t *&result); - - // validates a parameter as a CPU - bool validate_cpu_parameter(std::string_view param, device_t *&result); - - // validates a parameter as an address space identifier - bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result); - - // validates a parameter as a target address and retrieves the given address space and address - bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); - - // validates a parameter as a memory region name and retrieves the given region - bool validate_memory_region_parameter(std::string_view param, memory_region *&result); - private: struct global_entry { @@ -87,11 +66,6 @@ private: u8 disabled = 0U; }; - device_t &get_device_search_base(std::string_view ¶m); - device_t *get_cpu_by_index(u64 cpunum); - bool debug_command_parameter_expression(std::string_view param, parsed_expression &result); - bool debug_command_parameter_command(std::string_view param); - bool cheat_address_is_valid(address_space &space, offs_t address); u64 get_cpunum(); diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 41e09d748f3..19f52504780 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles, Vas Crabb /********************************************************************* debugcon.cpp @@ -198,7 +198,7 @@ void debugger_console::execute_condump(const std::vector& para // symbol table //------------------------------------------------- -symbol_table &debugger_console::visible_symtable() +symbol_table &debugger_console::visible_symtable() const { return m_visiblecpu->debug()->symtable(); } @@ -559,6 +559,494 @@ std::string debugger_console::cmderr_to_string(CMDERR error) } +//************************************************************************** +// PARAMETER VALIDATION HELPERS +//************************************************************************** + +namespace { + +template +inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim) +{ + unsigned parens = 0; + for (std::string_view::size_type i = 0; str.length() > i; ++i) + { + if (str[i] == '(') + { + ++parens; + } + else if (parens) + { + if (str[i] == ')') + --parens; + } + else if (is_delim(str[i])) + { + return i; + } + } + return std::string_view::npos; +} + +} // anonymous namespace + + +/// \brief Validate parameter as a Boolean value +/// +/// Validates a parameter as a Boolean value. Fixed strings and +/// expressions evaluating to numeric values are recognised. The result +/// is unchanged for an empty string. +/// \param [in] param The parameter string. +/// \param [in,out] result The default value on entry, and the value of +/// the parameter interpreted as a Boolean on success. Unchanged if +/// the parameter is an empty string. +/// \return true if the parameter is a valid Boolean value or an empty +/// string, or false otherwise. +bool debugger_console::validate_boolean_parameter(std::string_view param, bool &result) +{ + // nullptr parameter does nothing and returns no error + if (param.empty()) + return true; + + // evaluate the expression; success if no error + 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) + { + result = is_true; + return true; + } + + // try to evaluate as a number + u64 val; + if (!validate_number_parameter(param, val)) + return false; + + result = val != 0; + return true; +} + + +/// \brief Validate parameter as a numeric value +/// +/// Parses the parameter as an expression and evaluates it as a number. +/// \param [in] param The parameter string. +/// \param [out] result The numeric value of the expression on success. +/// Unchanged on failure. +/// \return true if the parameter is a valid expression that evaluates +/// to a numeric value, or false otherwise. +bool debugger_console::validate_number_parameter(std::string_view param, u64 &result) +{ + // evaluate the expression; success if no error + try + { + result = parsed_expression(visible_symtable(), param).execute(); + return true; + } + catch (expression_error const &error) + { + // print an error pointing to the character that caused it + printf("Error in expression: %s\n", param); + printf(" %*s^", error.offset(), ""); + printf("%s\n", error.code_string()); + return false; + } +} + + +/// \brief Validate parameter as a device +/// +/// Validates a parameter as a device identifier and retrieves the +/// device on success. A string corresponding to the tag of a device +/// refers to that device; an empty string refers to the current CPU +/// with debugger focus; any other string is parsed as an expression +/// and treated as an index of a device implementing +/// #device_execute_interface and #device_state_interface, and exposing +/// a generic PC base value. +/// \param [in] param The parameter string. +/// \param [out] result A pointer to the device on success, or unchanged +/// on failure. +/// \return true if the parameter refers to a device in the current +/// system, or false otherwise. +bool debugger_console::validate_device_parameter(std::string_view param, device_t *&result) +{ + // if no parameter, use the visible CPU + if (param.empty()) + { + device_t *const current = m_visiblecpu; + if (current) + { + result = current; + return true; + } + else + { + printf("No valid CPU is currently selected\n"); + return false; + } + } + + // next look for a tag match + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + device_t *device = base.subdevice(strmakelower(relative)); + if (device) + { + result = device; + return true; + } + + // then evaluate as an expression; on an error assume it was a tag + u64 cpunum; + try + { + cpunum = parsed_expression(visible_symtable(), param).execute(); + } + catch (expression_error &) + { + printf("Unable to find device '%s'\n", param); + return false; + } + + // attempt to find by numerical index + device = get_cpu_by_index(cpunum); + if (device) + { + result = device; + return true; + } + else + { + // if out of range, complain + printf("Invalid CPU index %u\n", cpunum); + return false; + } +} + + +/// \brief Validate a parameter as a CPU +/// +/// Validates a parameter as a CPU identifier. Uses the same rules as +/// #validate_device_parameter to identify devices, but additionally +/// checks that the device is a "CPU" for the debugger's purposes. +/// \param [in] The parameter string. +/// \param [out] result The device on success, or unchanged on failure. +/// \return true if the parameter refers to a CPU-like device in the +/// current system, or false otherwise. +bool debugger_console::validate_cpu_parameter(std::string_view param, device_t *&result) +{ + // first do the standard device thing + device_t *device; + if (!validate_device_parameter(param, device)) + return false; + + // check that it's a "CPU" for the debugger's purposes + device_execute_interface const *execute; + if (device->interface(execute)) + { + result = device; + return true; + } + + printf("Device %s is not a CPU\n", device->name()); + return false; +} + + +/// \brief Validate a parameter as an address space identifier +/// +/// Validates a parameter as an address space identifier. Uses the same +/// rules as #validate_device_parameter to identify devices. If the +/// default address space number is negative, the first address space +/// exposed by the device will be used as the default. +/// \param [in] The parameter string. +/// \param [in] spacenum The default address space index. If negative, +/// the first address space exposed by the device (i.e. the address +/// space with the lowest index) will be used as the default. +/// \param [out] result The addresfs space on success, or unchanged on +/// failure. +/// \return true if the parameter refers to an address space in the +/// current system, or false otherwise. +bool debugger_console::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result) +{ + device_t *device; + std::string spacename; + if (param.empty()) + { + // if no parameter, use the visible CPU + device = m_visiblecpu; + if (!device) + { + printf("No valid CPU is currently selected\n"); + return false; + } + } + else + { + // look for a tag match on the whole parameter value + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + device = base.subdevice(strmakelower(relative)); + + // if that failed, treat the last component as an address space + if (!device) + { + auto const delimiter = relative.find_last_of(":^"); + bool const found = std::string_view::npos != delimiter; + if (!found || (':' == relative[delimiter])) + { + spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0)); + relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter); + if (!relative.empty()) + device = base.subdevice(strmakelower(relative)); + else if (m_visiblecpu) + device = m_visiblecpu; + else + device = &m_machine.root_device(); + } + } + } + + // if still no device found, evaluate as an expression + if (!device) + { + u64 cpunum; + try + { + cpunum = parsed_expression(visible_symtable(), param).execute(); + } + catch (expression_error const &) + { + // parsing failed - assume it was a tag + printf("Unable to find device '%s'\n", param); + return false; + } + + // attempt to find by numerical index + device = get_cpu_by_index(cpunum); + if (!device) + { + // if out of range, complain + printf("Invalid CPU index %u\n", cpunum); + return false; + } + } + + // ensure the device implements the memory interface + device_memory_interface *memory; + if (!device->interface(memory)) + { + printf("No memory interface found for device %s\n", device->name()); + return false; + } + + // fall back to supplied default space if appropriate + if (spacename.empty() && (0 <= spacenum)) + { + if (memory->has_space(spacenum)) + { + result = &memory->space(spacenum); + return true; + } + else + { + printf("No matching memory space found for device '%s'\n", device->tag()); + return false; + } + } + + // otherwise find the specified space or fall back to the first populated space + for (int i = 0; memory->max_space_count() > i; ++i) + { + if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename))) + { + result = &memory->space(i); + return true; + } + } + + // report appropriate error message + if (spacename.empty()) + printf("No memory spaces found for device '%s'\n", device->tag()); + else + printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag()); + return false; +} + + +/// \brief Validate a parameter as a target address +/// +/// Validates a parameter as an numeric expression to use as an address +/// optionally followed by a colon and a device identifier. If the +/// device identifier is not presnt, the current CPU with debugger focus +/// is assumed. See #validate_device_parameter for information on how +/// device parametersare interpreted. +/// \param [in] The parameter string. +/// \param [in] spacenum The default address space index. If negative, +/// the first address space exposed by the device (i.e. the address +/// space with the lowest index) will be used as the default. +/// \param [out] space The address space on success, or unchanged on +/// failure. +/// \param [out] addr The address on success, or unchanged on failure. +/// \return true if the address is a valid expression evaluating to a +/// number and the address space is found, or false otherwise. +bool debugger_console::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr) +{ + // check for the device delimiter + std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; }); + std::string_view device; + if (devdelim != std::string::npos) + device = param.substr(devdelim + 1); + + // parse the address first + u64 addrval; + if (!validate_number_parameter(param.substr(0, devdelim), addrval)) + return false; + + // find the address space + if (!validate_device_space_parameter(device, spacenum, space)) + return false; + + // set the address now that we have the space + addr = addrval; + return true; +} + + +/// \brief Validate a parameter as a memory region +/// +/// Validates a parameter as a memory region tag and retrieves the +/// specified memory region. +/// \param [in] The parameter string. +/// \param [out] result The memory region on success, or unchanged on +/// failure. +/// \return true if the parameter refers to a memory region in the +/// current system, or false otherwise. +bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result) +{ + auto const ®ions = m_machine.memory().regions(); + std::string_view relative = param; + device_t &base = get_device_search_base(relative); + auto const iter = regions.find(base.subtag(strmakelower(relative))); + if (regions.end() != iter) + { + result = iter->second.get(); + return true; + } + else + { + printf("No matching memory region found for '%s'\n", param); + return false; + } +} + + +/// \brief Get search base for device or address space parameter +/// +/// Handles prefix prefixes used to indicate that a device tag should be +/// interpreted relative to the selected CPU. Removes the recognised +/// prefixes from the parameter value. +/// \param [in,out] param The parameter string. Recognised prefixes +/// affecting the search base are removed, leaving a tag relative to +/// the base device. +/// \return A reference to the base device that the tag should be +/// interpreted relative to. +device_t &debugger_console::get_device_search_base(std::string_view ¶m) const +{ + if (!param.empty()) + { + // handle ".:" or ".^" prefix for tag relative to current CPU if any + if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1]))) + { + param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1); + device_t *const current = m_visiblecpu; + return current ? *current : m_machine.root_device(); + } + + // a sibling path makes most sense relative to current CPU + if ('^' == param[0]) + { + device_t *const current = m_visiblecpu; + return current ? *current : m_machine.root_device(); + } + } + + // default to root device + return m_machine.root_device(); +} + + +/// \brief Get CPU by index +/// +/// Looks up a CPU by the number the debugger assigns it based on its +/// position in the device tree relative to other CPUs. +/// \param [in] cpunum Zero-based index of the CPU to find. +/// \return A pointer to the CPU if found, or \c nullptr if no CPU has +/// the specified index. +device_t *debugger_console::get_cpu_by_index(u64 cpunum) const +{ + unsigned index = 0; + for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device())) + { + // real CPUs should have pcbase + device_state_interface const *state; + if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE)) + { + if (index++ == cpunum) + { + return &exec.device(); + } + } + } + return nullptr; +} + + +//------------------------------------------------- +// validate_expression_parameter - validates +// an expression parameter +//-----------------------------------------------*/ + +bool debugger_console::validate_expression_parameter(std::string_view param, parsed_expression &result) +{ + try + { + // parse the expression; success if no error + result.parse(param); + return true; + } + catch (expression_error const &err) + { + // output an error + printf("Error in expression: %s\n", param); + printf(" %*s^", err.offset(), ""); + printf("%s\n", err.code_string()); + return false; + } +} + + +//------------------------------------------------- +// validate_command_parameter - validates a +// command parameter +//------------------------------------------------- + +bool debugger_console::validate_command_parameter(std::string_view param) +{ + // validate the comment; success if no error + CMDERR err = validate_command(param); + if (err.error_class() == CMDERR::NONE) + return true; + + // output an error + printf("Error in command: %s\n", param); + printf(" %*s^", err.error_offset(), ""); + printf("%s\n", cmderr_to_string(err)); + return false; +} + /*************************************************************************** diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index 5c7b521426f..5339ec69e69 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -110,12 +110,39 @@ public: vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward(fmt), std::forward(args)...)); } - device_t *get_visible_cpu() { return m_visiblecpu; } + device_t *get_visible_cpu() const { return m_visiblecpu; } void set_visible_cpu(device_t *visiblecpu) { m_visiblecpu = visiblecpu; } - symbol_table &visible_symtable(); + symbol_table &visible_symtable() const; static std::string cmderr_to_string(CMDERR error); + // validates a parameter as a boolean value + bool validate_boolean_parameter(std::string_view param, bool &result); + + // validates a parameter as a numeric value + bool validate_number_parameter(std::string_view param, u64 &result); + + // validates a parameter as a device + bool validate_device_parameter(std::string_view param, device_t *&result); + + // validates a parameter as a CPU + bool validate_cpu_parameter(std::string_view param, device_t *&result); + + // validates a parameter as an address space identifier + bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result); + + // validates a parameter as a target address and retrieves the given address space and address + bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr); + + // validates a parameter as a memory region name and retrieves the given region + bool validate_memory_region_parameter(std::string_view param, memory_region *&result); + + // validates a parameter as a debugger expression + bool validate_expression_parameter(std::string_view param, parsed_expression &result); + + // validates a parameter as a debugger command + bool validate_command_parameter(std::string_view param); + private: void exit(); @@ -129,6 +156,9 @@ private: void print_core(std::string_view text); // core text output void print_core_wrap(std::string_view text, int wrapcol); // core text output + device_t &get_device_search_base(std::string_view ¶m) const; + device_t *get_cpu_by_index(u64 cpunum) const; + struct debug_command { debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function &)> &&_handler); diff --git a/src/mame/konami/konamim2.cpp b/src/mame/konami/konamim2.cpp index 095f292caf7..817024f33e7 100644 --- a/src/mame/konami/konamim2.cpp +++ b/src/mame/konami/konamim2.cpp @@ -227,7 +227,6 @@ Notes: #include "sound/ymz280b.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include "romload.h" #include "screen.h" @@ -1553,7 +1552,7 @@ void konamim2_state::dump_task_command(const std::vector ¶ if (params.size() < 1) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; address = (offs_t)addr; diff --git a/src/mame/microsoft/xbox.cpp b/src/mame/microsoft/xbox.cpp index e1b5c952832..68bb27b9b50 100644 --- a/src/mame/microsoft/xbox.cpp +++ b/src/mame/microsoft/xbox.cpp @@ -17,9 +17,6 @@ #include "bus/ata/atapicdr.h" #include "bus/ata/idehd.h" -#include "debug/debugcmd.h" -#include "debug/debugcon.h" -#include "debugger.h" #include "speaker.h" #include "bitmap.h" diff --git a/src/mame/midway/midtunit_v.cpp b/src/mame/midway/midtunit_v.cpp index f87332be230..8347c6787dc 100644 --- a/src/mame/midway/midtunit_v.cpp +++ b/src/mame/midway/midtunit_v.cpp @@ -14,7 +14,6 @@ #include "midtview.ipp" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include "emuopts.h" // Used by PNG logging @@ -115,7 +114,7 @@ void midtunit_video_device::debug_png_dma_command(const std::vector @@ -629,7 +628,7 @@ void rmnimbus_state::video_debug(const std::vector ¶ms) if (params.size() > 0) { uint64_t temp; - if (!machine().debugger().commands().validate_number_parameter(params[0], temp)) + if (!machine().debugger().console().validate_number_parameter(params[0], temp)) return; m_debug_video = temp; } diff --git a/src/mame/sega/chihiro.cpp b/src/mame/sega/chihiro.cpp index 7f2016569ee..7061536c62b 100644 --- a/src/mame/sega/chihiro.cpp +++ b/src/mame/sega/chihiro.cpp @@ -442,7 +442,6 @@ Thanks to Alex, Mr Mudkips, and Philip Burke for this info. #include "machine/jvshost.h" #include "naomigd.h" -#include "debug/debugcmd.h" #include "debug/debugcon.h" #include "debugger.h" @@ -787,9 +786,9 @@ void chihiro_state::jamtable_disasm_command(const std::vector if (params.size() < 3) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!machine().debugger().console().validate_number_parameter(params[1], addr)) return; - if (!machine().debugger().commands().validate_number_parameter(params[2], size)) + if (!machine().debugger().console().validate_number_parameter(params[2], size)) return; jamtable_disasm(space, (uint32_t)addr, (uint32_t)size); } diff --git a/src/mame/sega/model2_m.cpp b/src/mame/sega/model2_m.cpp index 09621be1521..f855979634b 100644 --- a/src/mame/sega/model2_m.cpp +++ b/src/mame/sega/model2_m.cpp @@ -10,7 +10,6 @@ #include "model2.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include diff --git a/src/mame/shared/xbox.cpp b/src/mame/shared/xbox.cpp index faf829028bb..4c1bd217039 100644 --- a/src/mame/shared/xbox.cpp +++ b/src/mame/shared/xbox.cpp @@ -10,9 +10,8 @@ #include "machine/idectrl.h" #include "cpu/i386/i386.h" -#include "debug/debugcon.h" -#include "debug/debugcmd.h" +#include "debug/debugcon.h" #include "debugger.h" #include "romload.h" #include "screen.h" @@ -94,7 +93,7 @@ void xbox_base_state::dump_string_command(const std::vector &p if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; address = (offs_t)addr; @@ -136,7 +135,7 @@ void xbox_base_state::dump_process_command(const std::vector & if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; address = (offs_t)addr; @@ -166,14 +165,14 @@ void xbox_base_state::dump_list_command(const std::vector &par if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; uint64_t offs = 0; offs_t offset = 0; if (params.size() >= 3) { - if (!machine().debugger().commands().validate_number_parameter(params[2], offs)) + if (!con.validate_number_parameter(params[2], offs)) return; offset = (offs_t)offs; } @@ -219,7 +218,7 @@ void xbox_base_state::dump_dpc_command(const std::vector ¶ if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; address = (offs_t)addr; @@ -248,7 +247,7 @@ void xbox_base_state::dump_timer_command(const std::vector &pa if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; address = (offs_t)addr; @@ -304,8 +303,8 @@ void xbox_base_state::curthread_command(const std::vector &par void xbox_base_state::threadlist_command(const std::vector ¶ms) { - address_space &space = m_maincpu->space(); debugger_console &con = machine().debugger().console(); + address_space &space = m_maincpu->space(); con.printf("Pri. _KTHREAD Stack Function\n"); con.printf("-------------------------------\n"); @@ -347,7 +346,7 @@ void xbox_base_state::generate_irq_command(const std::vector & if (params.size() < 2) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], irq)) + if (!machine().debugger().console().validate_number_parameter(params[1], irq)) return; if (irq > 15) return; @@ -392,7 +391,7 @@ void xbox_base_state::grab_texture_command(const std::vector & if (params.size() < 3) return; - if (!machine().debugger().commands().validate_number_parameter(params[1], type)) + if (!machine().debugger().console().validate_number_parameter(params[1], type)) return; if (params[2].empty() || params[2].length() > 127) return; @@ -422,22 +421,23 @@ void xbox_base_state::grab_vprog_command(const std::vector &pa void xbox_base_state::vprogdis_command(const std::vector ¶ms) { + debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); if (params.size() < 3) return; uint64_t addr; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; uint64_t length; - if (!machine().debugger().commands().validate_number_parameter(params[2], length)) + if (!con.validate_number_parameter(params[2], length)) return; uint64_t type = 0; if (params.size() > 3) - if (!machine().debugger().commands().validate_number_parameter(params[3], type)) + if (!con.validate_number_parameter(params[3], type)) return; vertex_program_disassembler vd; @@ -461,7 +461,7 @@ void xbox_base_state::vprogdis_command(const std::vector ¶ char line[64]; while (vd.disassemble(instruction, line) != 0) - machine().debugger().console().printf("%s\n", line); + con.printf("%s\n", line); if (type == 1) addr = addr + 4 * 4; @@ -474,16 +474,16 @@ void xbox_base_state::vprogdis_command(const std::vector ¶ void xbox_base_state::vdeclaration_command(const std::vector ¶ms) { + debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); if (params.size() < 1) return; uint64_t addr; - if (!machine().debugger().commands().validate_number_parameter(params[1], addr)) + if (!con.validate_number_parameter(params[1], addr)) return; - debugger_console &con = machine().debugger().console(); for (int n = 128; n > 0; n--) { offs_t address = (offs_t)addr; diff --git a/src/mame/sun/sun4.cpp b/src/mame/sun/sun4.cpp index 2a7efc7fd26..eae540d969c 100644 --- a/src/mame/sun/sun4.cpp +++ b/src/mame/sun/sun4.cpp @@ -432,7 +432,6 @@ #include "machine/z80scc.h" #include "debug/debugcon.h" -#include "debug/debugcmd.h" #include "debugger.h" #include "screen.h" -- cgit v1.2.3