mirror of
https://github.com/holub/mame
synced 2025-07-05 01:48:29 +03:00
debugger: symlist usability + symbol table extensibility (#13694)
Address issue #6655 (symlist command usability), add a bit of plumbing for future extensibility. symlist with no arguments displays all global *and* :maincpu symbols, with clear header text for each list. At the bottom, prints helper text to make user aware of the cpu form To allow for adding new kinds of symbols in the future, this adds an enum field to symbol table for its 'type', for prettier printing from symlist. Symlist now traverses symbol table chain completely.
This commit is contained in:
parent
efb84a4bb5
commit
b39e684622
@ -3909,58 +3909,80 @@ void debugger_commands::execute_memdump(const std::vector<std::string_view> &par
|
||||
|
||||
void debugger_commands::execute_symlist(const std::vector<std::string_view> ¶ms)
|
||||
{
|
||||
const char *namelist[1000];
|
||||
// Default to CPU "0" if none specified
|
||||
const char * cpuname = (params.empty()) ? "0" : params[0].cbegin();
|
||||
device_t *cpu = nullptr;
|
||||
symbol_table *symtable;
|
||||
int count = 0;
|
||||
|
||||
if (!params.empty())
|
||||
if (!m_console.validate_cpu_parameter(cpuname, cpu))
|
||||
{
|
||||
// validate parameters
|
||||
device_t *cpu;
|
||||
if (!m_console.validate_cpu_parameter(params[0], cpu))
|
||||
return;
|
||||
symtable = &cpu->debug()->symtable();
|
||||
m_console.printf("CPU '%s' symbols:\n", cpu->tag());
|
||||
if (!params.empty())
|
||||
return; // Explicitly specified cpu is invalid
|
||||
|
||||
// Somehow cpu "0" is invalid, so just stick with global symbol table
|
||||
symtable = &m_machine.debugger().cpu().global_symtable();
|
||||
}
|
||||
else
|
||||
{
|
||||
symtable = &m_machine.debugger().cpu().global_symtable();
|
||||
m_console.printf("Global symbols:\n");
|
||||
symtable = &cpu->debug()->symtable();
|
||||
}
|
||||
|
||||
// gather names for all symbols
|
||||
for (auto &entry : symtable->entries())
|
||||
// Traverse symbol_table parent chain, printing each table's symbols in its own block
|
||||
for (; symtable != nullptr; symtable = symtable->parent())
|
||||
{
|
||||
// only display "register" type symbols
|
||||
if (!entry.second->is_function())
|
||||
// Skip globals if user explicitly requested CPU
|
||||
if (symtable->type() == symbol_table::BUILTIN_GLOBALS && !params.empty())
|
||||
continue;
|
||||
|
||||
if (symtable->entries().size() == 0)
|
||||
continue;
|
||||
|
||||
std::vector<const char *> namelist;
|
||||
|
||||
// Print heading for table
|
||||
switch (symtable->type())
|
||||
{
|
||||
namelist[count++] = entry.second->name();
|
||||
if (count >= std::size(namelist))
|
||||
break;
|
||||
case symbol_table::CPU_STATE:
|
||||
m_console.printf("\n**** CPU '%s' symbols ****\n", cpu->tag());
|
||||
break;
|
||||
case symbol_table::BUILTIN_GLOBALS:
|
||||
m_console.printf("\n**** Global symbols ****\n");
|
||||
break;
|
||||
default:
|
||||
assert (!"Unrecognized symbol table type");
|
||||
}
|
||||
|
||||
// gather names for all relevant symbols
|
||||
for (auto &entry : symtable->entries())
|
||||
{
|
||||
// ignore built-in function symbols
|
||||
if (!entry.second->is_function())
|
||||
{
|
||||
namelist.push_back(entry.second->name());
|
||||
}
|
||||
}
|
||||
|
||||
// sort the symbols
|
||||
std::sort(
|
||||
namelist.begin(),
|
||||
namelist.end(),
|
||||
[] (const char *item1, const char *item2) { return strcmp(item1, item2) < 0; });
|
||||
|
||||
// iterate over symbols and print them
|
||||
for (const char * symname : namelist)
|
||||
{
|
||||
symbol_entry const *const entry = symtable->find(symname);
|
||||
assert(entry != nullptr);
|
||||
m_console.printf("%s = %X", symname, entry->value());
|
||||
if (!entry->is_lval())
|
||||
m_console.printf(" (read-only)");
|
||||
m_console.printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// sort the symbols
|
||||
if (count > 1)
|
||||
if (params.empty())
|
||||
{
|
||||
std::sort(
|
||||
&namelist[0],
|
||||
&namelist[count],
|
||||
[] (const char *item1, const char *item2) { return strcmp(item1, item2) < 0; });
|
||||
}
|
||||
|
||||
// iterate over symbols and print out relevant ones
|
||||
for (int symnum = 0; symnum < count; symnum++)
|
||||
{
|
||||
symbol_entry const *const entry = symtable->find(namelist[symnum]);
|
||||
assert(entry != nullptr);
|
||||
u64 value = entry->value();
|
||||
|
||||
// only display "register" type symbols
|
||||
m_console.printf("%s = %X", namelist[symnum], value);
|
||||
if (!entry->is_lval())
|
||||
m_console.printf(" (read-only)");
|
||||
m_console.printf("\n");
|
||||
m_console.printf(
|
||||
"\nTo view the symbols for a particular CPU, try symlist <cpu>,\n"
|
||||
"where <cpu> is the ID number or tag for a CPU.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
|
||||
m_tempvar = make_unique_clear<u64[]>(NUM_TEMP_VARIABLES);
|
||||
|
||||
/* create a global symbol table */
|
||||
m_symtable = std::make_unique<symbol_table>(machine);
|
||||
m_symtable = std::make_unique<symbol_table>(machine, symbol_table::BUILTIN_GLOBALS);
|
||||
m_symtable->set_memory_modified_func([this]() { set_memory_modified(true); });
|
||||
|
||||
/* add "wpaddr", "wpdata", "wpsize" to the global symbol table */
|
||||
@ -488,7 +488,7 @@ device_debug::device_debug(device_t &device)
|
||||
, m_state(nullptr)
|
||||
, m_disasm(nullptr)
|
||||
, m_flags(0)
|
||||
, m_symtable(std::make_unique<symbol_table>(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device))
|
||||
, m_symtable(std::make_unique<symbol_table>(device.machine(), symbol_table::CPU_STATE, &device.machine().debugger().cpu().global_symtable(), &device))
|
||||
, m_stepaddr(0)
|
||||
, m_stepsleft(0)
|
||||
, m_delay_steps(0)
|
||||
|
@ -363,8 +363,9 @@ symbol_entry::~symbol_entry()
|
||||
// symbol_table - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
symbol_table::symbol_table(running_machine &machine, symbol_table *parent, device_t *device)
|
||||
symbol_table::symbol_table(running_machine &machine, table_type type, symbol_table *parent, device_t *device)
|
||||
: m_machine(machine)
|
||||
, m_type(type)
|
||||
, m_parent(parent)
|
||||
, m_memintf(dynamic_cast<device_memory_interface *>(device))
|
||||
, m_memory_modified(nullptr)
|
||||
|
@ -171,11 +171,21 @@ public:
|
||||
READ_WRITE
|
||||
};
|
||||
|
||||
// Identifies the type of symbols stored in this table. These help symlist create
|
||||
// useful output
|
||||
enum table_type
|
||||
{
|
||||
CPU_STATE, // CPU registers, etc.
|
||||
BUILTIN_GLOBALS, // Built-in MAME global symbols (e.g., beamx, beamy, frame, etc.)
|
||||
// (also used for tables outside debugger: lua scripts, cheat engine)
|
||||
};
|
||||
|
||||
// construction/destruction
|
||||
symbol_table(running_machine &machine, symbol_table *parent = nullptr, device_t *device = nullptr);
|
||||
symbol_table(running_machine &machine, table_type type, symbol_table *parent = nullptr, device_t *device = nullptr);
|
||||
|
||||
// getters
|
||||
const std::unordered_map<std::string, std::unique_ptr<symbol_entry>> &entries() const { return m_symlist; }
|
||||
table_type type() const { return m_type; }
|
||||
symbol_table *parent() const { return m_parent; }
|
||||
running_machine &machine() { return m_machine; }
|
||||
|
||||
@ -212,6 +222,7 @@ private:
|
||||
|
||||
// internal state
|
||||
running_machine & m_machine; // reference to the machine
|
||||
table_type m_type; // kind of symbols stored in this table
|
||||
symbol_table * m_parent; // pointer to the parent symbol table
|
||||
std::unordered_map<std::string,std::unique_ptr<symbol_entry>> m_symlist; // list of symbols
|
||||
device_memory_interface *const m_memintf; // pointer to the local memory interface (if any)
|
||||
|
@ -683,7 +683,7 @@ void cheat_script::script_entry::output_argument::save(util::core_file &cheatfil
|
||||
|
||||
cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, std::string const &filename, util::xml::data_node const &cheatnode)
|
||||
: m_manager(manager)
|
||||
, m_symbols(manager.machine(), &globaltable)
|
||||
, m_symbols(manager.machine(), symbol_table::BUILTIN_GLOBALS, &globaltable)
|
||||
, m_state(SCRIPT_STATE_OFF)
|
||||
, m_numtemp(DEFAULT_TEMP_VARIABLES)
|
||||
, m_argindex(0)
|
||||
@ -1065,7 +1065,7 @@ cheat_manager::cheat_manager(running_machine &machine)
|
||||
, m_numlines(0)
|
||||
, m_lastline(0)
|
||||
, m_disabled(true)
|
||||
, m_symtable(machine)
|
||||
, m_symtable(machine, symbol_table::BUILTIN_GLOBALS)
|
||||
{
|
||||
// if the cheat engine is disabled, we're done
|
||||
if (!machine.options().cheat())
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
|
||||
symbol_table_wrapper(lua_engine &host, running_machine &machine, std::shared_ptr<symbol_table_wrapper> const &parent, device_t *device)
|
||||
: m_host(host)
|
||||
, m_table(machine, parent ? &parent->table() : nullptr, device)
|
||||
, m_table(machine, symbol_table::BUILTIN_GLOBALS, parent ? &parent->table() : nullptr, device)
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user