summaryrefslogtreecommitdiffstats
path: root/src/frontend/mame/luaengine_debug.cpp
diff options
context:
space:
mode:
author Vas Crabb <cuavas@users.noreply.github.com>2022-02-12 04:10:39 +1100
committer GitHub <noreply@github.com>2022-02-12 04:10:39 +1100
commita18509185569b8e637c7e129caab5eb75e4adff9 (patch)
tree4e312575e03db0cb0fec4d90a8bb91d831629130 /src/frontend/mame/luaengine_debug.cpp
parentf0fc52d32c4933b76bfc7ba91838b1b29b962595 (diff)
Addressed some Lua scripting pitfalls. (#9294)
Addressed pure virtual function call crash on end of emulation session if you haven't explicitly removed all address space taps, memory corruption on end of emulation session if you haven't explicitly removed all address space change notifiers, and symbol being garbage-collected out from under you while you have parsed expressions or other symbol tables that depend on them. Removed the copy constructor for parsed expressions as the underlying C++ copy constructor appears to be broken, and simplified symbol table constructors. Also made symbol table add methods return the new entry to avoid the need for an extra lookup. Fixed breakpoint/watchpoint objects being inappropriately copied into the tables returned by bplist() and wplist(), allowing the enabled property to be modifiable for breakpoint and watchpoint objects in Lua. Fixed drivers and devices causing a new memory pass-through handler to be allocated on each soft reset, and fixed multiple instances of taps being installed in the event the machine is reset before the tap is removed. Added classes for managing broadcast subscriptions, and adapted address spaces to use this for change notifications.
Diffstat (limited to 'src/frontend/mame/luaengine_debug.cpp')
-rw-r--r--src/frontend/mame/luaengine_debug.cpp256
1 files changed, 175 insertions, 81 deletions
diff --git a/src/frontend/mame/luaengine_debug.cpp b/src/frontend/mame/luaengine_debug.cpp
index 699c303f44f..749d4c34aa0 100644
--- a/src/frontend/mame/luaengine_debug.cpp
+++ b/src/frontend/mame/luaengine_debug.cpp
@@ -30,6 +30,78 @@ struct wrap_textbuf
};
+class symbol_table_wrapper
+{
+public:
+ symbol_table_wrapper(symbol_table_wrapper const &) = delete;
+
+ symbol_table_wrapper(running_machine &machine, std::shared_ptr<symbol_table_wrapper> const &parent, device_t *device)
+ : m_table(machine, parent ? &parent->table() : nullptr, device)
+ , m_parent(parent)
+ {
+ }
+
+ symbol_table &table() { return m_table; }
+ symbol_table const &table() const { return m_table; }
+ std::shared_ptr<symbol_table_wrapper> const &parent() { return m_parent; }
+
+ symbol_entry &add(char const *name) { return m_table.add(name, symbol_table::READ_WRITE); }
+ symbol_entry &add(char const *name, u64 value) { return m_table.add(name, value); }
+ symbol_entry *find(char const *name) const { return m_table.find(name); }
+ symbol_entry *find_deep(char const *name) { return m_table.find_deep(name); }
+
+ u64 value(const char *symbol) { return m_table.value(symbol); }
+ void set_value(const char *symbol, u64 value) { m_table.set_value(symbol, value); }
+
+private:
+ symbol_table m_table;
+ std::shared_ptr<symbol_table_wrapper> const m_parent;
+};
+
+
+class expression_wrapper
+{
+public:
+ expression_wrapper(expression_wrapper const &) = delete;
+ expression_wrapper &operator=(expression_wrapper const &) = delete;
+
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &symtable)
+ : m_expression(symtable->table())
+ , m_symbols(symtable)
+ {
+ }
+
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &symtable, char const *expression, int default_base)
+ : m_expression(symtable->table(), expression, default_base)
+ , m_symbols(symtable)
+ {
+ }
+
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &symtable, char const *expression)
+ : m_expression(symtable->table(), expression)
+ , m_symbols(symtable)
+ {
+ }
+
+ void set_default_base(int base) { m_expression.set_default_base(base); }
+ void parse(char const *string) { m_expression.parse(string); }
+ u64 execute() { return m_expression.execute(); }
+ bool is_empty() const { return m_expression.is_empty(); }
+ char const *original_string() const { return m_expression.original_string(); }
+ std::shared_ptr<symbol_table_wrapper> const &symbols() { return m_symbols; }
+
+ void set_symbols(std::shared_ptr<symbol_table_wrapper> const &symtable)
+ {
+ m_expression.set_symbols(symtable->table());
+ m_symbols = symtable;
+ }
+
+private:
+ parsed_expression m_expression;
+ std::shared_ptr<symbol_table_wrapper> m_symbols;
+};
+
+
template <bool Enable>
sol::object do_breakpoint_enable(device_debug &dev, sol::this_state s, sol::object index)
{
@@ -106,12 +178,12 @@ void lua_engine::initialize_debug(sol::table &emu)
{ "m", EXPSPACE_REGION }
};
- auto const do_add_symbol = [this] (symbol_table &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter, std::optional<char const *> format)
+ auto const do_add_symbol = [this] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter, std::optional<char const *> format) -> symbol_entry &
{
symbol_table::setter_func setfun;
if (setter)
setfun = [this, cbfunc = std::move(*setter)] (u64 value) { invoke(cbfunc, value); };
- st.add(
+ return st.table().add(
name,
[this, cbfunc = std::move(getter)] () -> u64
{
@@ -130,46 +202,50 @@ void lua_engine::initialize_debug(sol::table &emu)
(format && *format) ? *format : "");
};
- auto symbol_table_type = emu.new_usertype<symbol_table>(
+ auto symbol_table_type = emu.new_usertype<symbol_table_wrapper>(
"symbol_table",
sol::call_constructor, sol::factories(
- [] (running_machine &machine, symbol_table *parent, device_t *device) { return std::make_unique<symbol_table>(machine, parent, device); },
- [] (running_machine &machine, symbol_table *parent) { return std::make_unique<symbol_table>(machine, parent); },
- [] (running_machine &machine, device_t &device) { return std::make_unique<symbol_table>(machine, nullptr, &device); },
- [] (running_machine &machine) { return std::make_unique<symbol_table>(machine); }));
+ [] (running_machine &machine)
+ { return std::make_shared<symbol_table_wrapper>(machine, nullptr, nullptr); },
+ [] (std::shared_ptr<symbol_table_wrapper> const &parent, device_t *device)
+ { return std::make_shared<symbol_table_wrapper>(parent->table().machine(), parent, device); },
+ [] (std::shared_ptr<symbol_table_wrapper> const &parent)
+ { return std::make_shared<symbol_table_wrapper>(parent->table().machine(), parent, nullptr); },
+ [] (device_t &device)
+ { return std::make_shared<symbol_table_wrapper>(device.machine(), nullptr, &device); }));
symbol_table_type["set_memory_modified_func"] =
- [this] (symbol_table &st, sol::object cb)
+ [this] (symbol_table_wrapper &st, sol::object cb)
{
if (cb == sol::lua_nil)
- st.set_memory_modified_func(nullptr);
+ st.table().set_memory_modified_func(nullptr);
else if (cb.is<sol::protected_function>())
- st.set_memory_modified_func([this, cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); });
+ st.table().set_memory_modified_func([this, cbfunc = cb.as<sol::protected_function>()] () { invoke(cbfunc); });
else
osd_printf_error("[LUA ERROR] must call set_memory_modified_func with function or nil\n");
};
symbol_table_type["add"] = sol::overload(
- [] (symbol_table &st, char const *name) { st.add(name, symbol_table::READ_WRITE); },
- static_cast<void (symbol_table::*)(char const *, u64)>(&symbol_table::add),
+ static_cast<symbol_entry &(symbol_table_wrapper::*)(char const *)>(&symbol_table_wrapper::add),
+ static_cast<symbol_entry &(symbol_table_wrapper::*)(char const *, u64)>(&symbol_table_wrapper::add),
do_add_symbol,
- [do_add_symbol] (symbol_table &st, char const *name, sol::protected_function getter, sol::lua_nil_t, char const *format)
+ [do_add_symbol] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, sol::lua_nil_t, char const *format) -> symbol_entry &
{
- do_add_symbol(st, name, getter, std::nullopt, format);
+ return do_add_symbol(st, name, getter, std::nullopt, format);
},
- [do_add_symbol] (symbol_table &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter)
+ [do_add_symbol] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, std::optional<sol::protected_function> setter) -> symbol_entry &
{
- do_add_symbol(st, name, getter, setter, nullptr);
+ return do_add_symbol(st, name, getter, setter, nullptr);
},
- [do_add_symbol] (symbol_table &st, char const *name, sol::protected_function getter, char const *format)
+ [do_add_symbol] (symbol_table_wrapper &st, char const *name, sol::protected_function getter, char const *format) -> symbol_entry &
{
- do_add_symbol(st, name, getter, std::nullopt, format);
+ return do_add_symbol(st, name, getter, std::nullopt, format);
},
- [do_add_symbol] (symbol_table &st, char const *name, sol::protected_function getter)
+ [do_add_symbol] (symbol_table_wrapper &st, char const *name, sol::protected_function getter) -> symbol_entry &
{
- do_add_symbol(st, name, getter, std::nullopt, nullptr);
+ return do_add_symbol(st, name, getter, std::nullopt, nullptr);
},
- [this] (symbol_table &st, char const *name, int minparams, int maxparams, sol::protected_function execute)
+ [this] (symbol_table_wrapper &st, char const *name, int minparams, int maxparams, sol::protected_function execute) -> symbol_entry &
{
- st.add(
+ return st.table().add(
name,
minparams,
maxparams,
@@ -185,41 +261,40 @@ void lua_engine::initialize_debug(sol::table &emu)
return result ? *result : 0;
});
});
- symbol_table_type["find"] = &symbol_table::find;
- symbol_table_type["find_deep"] = &symbol_table::find_deep;
- symbol_table_type["value"] = &symbol_table::value;
- symbol_table_type["set_value"] = &symbol_table::set_value;
+ symbol_table_type["find"] = &symbol_table_wrapper::find;
+ symbol_table_type["find_deep"] = &symbol_table_wrapper::find_deep;
+ symbol_table_type["value"] = &symbol_table_wrapper::value;
+ symbol_table_type["set_value"] = &symbol_table_wrapper::set_value;
symbol_table_type["memory_value"] =
- [] (symbol_table &st, char const *name, char const *space, u32 offset, int size, bool disable_se)
+ [] (symbol_table_wrapper &st, char const *name, char const *space, u32 offset, int size, bool disable_se)
{
expression_space const es = s_expression_space_parser(space);
- return st.memory_value(name, es, offset, size, disable_se);
+ return st.table().memory_value(name, es, offset, size, disable_se);
};
symbol_table_type["set_memory_value"] =
- [] (symbol_table &st, char const *name, char const *space, u32 offset, int size, u64 value, bool disable_se)
+ [] (symbol_table_wrapper &st, char const *name, char const *space, u32 offset, int size, u64 value, bool disable_se)
{
expression_space const es = s_expression_space_parser(space);
- st.set_memory_value(name, es, offset, size, value, disable_se);
+ st.table().set_memory_value(name, es, offset, size, value, disable_se);
};
//symbol_table_type["read_memory"] = &symbol_table::read_memory; crashes if you try to use it, need to work out why
//symbol_table_type["write_memory"] = &symbol_table::write_memory; crashes if you try to use it, need to work out why
- symbol_table_type["entries"] = sol::property([] (symbol_table const &st) { return standard_tag_object_ptr_map<symbol_entry>(st.entries()); });
- symbol_table_type["parent"] = sol::property(&symbol_table::parent);
+ symbol_table_type["entries"] = sol::property([] (symbol_table_wrapper const &st) { return standard_tag_object_ptr_map<symbol_entry>(st.table().entries()); });
+ symbol_table_type["parent"] = sol::property(&symbol_table_wrapper::parent);
- auto parsed_expression_type = emu.new_usertype<parsed_expression>(
+ auto parsed_expression_type = emu.new_usertype<expression_wrapper>(
"parsed_expression",
- sol::call_constructor, sol::factories(
- [] (symbol_table &symtable) { return std::make_unique<parsed_expression>(symtable); },
- [] (symbol_table &symtable, char const *expression, int default_base) { return std::make_unique<parsed_expression>(symtable, expression, default_base); },
- [] (symbol_table &symtable, char const *expression) { return std::make_unique<parsed_expression>(symtable, expression); },
- [] (parsed_expression const &src) { return std::make_unique<parsed_expression>(src); }));
- parsed_expression_type["set_default_base"] = &parsed_expression::set_default_base;
- parsed_expression_type["parse"] = [] (parsed_expression &e, char const *string) { e.parse(string); };
- parsed_expression_type["execute"] = &parsed_expression::execute;
- parsed_expression_type["is_empty"] = sol::property(&parsed_expression::is_empty);
- parsed_expression_type["original_string"] = sol::property(&parsed_expression::original_string);
- parsed_expression_type["symbols"] = sol::property(&parsed_expression::symbols, &parsed_expression::set_symbols);
+ sol::call_constructor, sol::constructors<
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &),
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &, char const *, int),
+ expression_wrapper(std::shared_ptr<symbol_table_wrapper> const &, char const *)>());
+ parsed_expression_type["set_default_base"] = &expression_wrapper::set_default_base;
+ parsed_expression_type["parse"] = &expression_wrapper::parse;
+ parsed_expression_type["execute"] = &expression_wrapper::execute;
+ parsed_expression_type["is_empty"] = sol::property(&expression_wrapper::is_empty);
+ parsed_expression_type["original_string"] = sol::property(&expression_wrapper::original_string);
+ parsed_expression_type["symbols"] = sol::property(&expression_wrapper::symbols, &expression_wrapper::set_symbols);
auto symbol_entry_type = sol().registry().new_usertype<symbol_entry>("symbol_entry", sol::no_constructor);
@@ -266,22 +341,22 @@ void lua_engine::initialize_debug(sol::table &emu)
auto device_debug_type = sol().registry().new_usertype<device_debug>("device_debug", sol::no_constructor);
device_debug_type["step"] =
- [] (device_debug &dev, sol::object num)
- {
- int steps = 1;
- if (num.is<int>())
- steps = num.as<int>();
- dev.single_step(steps);
- };
+ [] (device_debug &dev, sol::object num)
+ {
+ int steps = 1;
+ if (num.is<int>())
+ steps = num.as<int>();
+ dev.single_step(steps);
+ };
device_debug_type["go"] = &device_debug::go;
device_debug_type["bpset"] =
- [] (device_debug &dev, offs_t address, char const *cond, char const *act)
- {
- int result(dev.breakpoint_set(address, cond, act));
- dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY);
- dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS);
- return result;
- };
+ [] (device_debug &dev, offs_t address, char const *cond, char const *act)
+ {
+ int result(dev.breakpoint_set(address, cond, act));
+ dev.device().machine().debug_view().update_all(DVT_DISASSEMBLY);
+ dev.device().machine().debug_view().update_all(DVT_BREAK_POINTS);
+ return result;
+ };
device_debug_type["bpclear"] = sol::overload(
[] (device_debug &dev, int index)
{
@@ -302,21 +377,21 @@ void lua_engine::initialize_debug(sol::table &emu)
device_debug_type["bpenable"] = &do_breakpoint_enable<true>;
device_debug_type["bpdisable"] = &do_breakpoint_enable<false>;
device_debug_type["bplist"] =
- [this] (device_debug &dev)
- {
- sol::table table = sol().create_table();
- for (auto const &bpp : dev.breakpoint_list())
- table[bpp.second->index()] = sol::make_reference(sol(), *bpp.second);
- return table;
- };
+ [this] (device_debug &dev)
+ {
+ sol::table table = sol().create_table();
+ for (auto const &bpp : dev.breakpoint_list())
+ table[bpp.second->index()] = sol::make_reference(sol(), bpp.second.get());
+ return table;
+ };
device_debug_type["wpset"] =
- [] (device_debug &dev, addr_space &sp, std::string const &type, offs_t addr, offs_t len, char const *cond, char const *act)
- {
- read_or_write const wptype = s_read_or_write_parser(type);
- int result(dev.watchpoint_set(sp.space, wptype, addr, len, cond, act));
- dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS);
- return result;
- };
+ [] (device_debug &dev, addr_space &sp, std::string const &type, offs_t addr, offs_t len, char const *cond, char const *act)
+ {
+ read_or_write const wptype = s_read_or_write_parser(type);
+ int result(dev.watchpoint_set(sp.space, wptype, addr, len, cond, act));
+ dev.device().machine().debug_view().update_all(DVT_WATCH_POINTS);
+ return result;
+ };
device_debug_type["wpclear"] = sol::overload(
[] (device_debug &dev, int index)
{
@@ -333,18 +408,28 @@ void lua_engine::initialize_debug(sol::table &emu)
device_debug_type["wpenable"] = &do_watchpoint_enable<true>;
device_debug_type["wpdisable"] = &do_watchpoint_enable<false>;
device_debug_type["wplist"] =
- [this] (device_debug &dev, addr_space &sp)
- {
- sol::table table = sol().create_table();
- for (auto &wpp : dev.watchpoint_vector(sp.space.spacenum()))
- table[wpp->index()] = sol::make_reference(sol(), *wpp);
- return table;
- };
+ [this] (device_debug &dev, addr_space &sp)
+ {
+ sol::table table = sol().create_table();
+ for (auto &wpp : dev.watchpoint_vector(sp.space.spacenum()))
+ table[wpp->index()] = sol::make_reference(sol(), wpp.get());
+ return table;
+ };
auto breakpoint_type = sol().registry().new_usertype<debug_breakpoint>("breakpoint", sol::no_constructor);
breakpoint_type["index"] = sol::property(&debug_breakpoint::index);
- breakpoint_type["enabled"] = sol::property(&debug_breakpoint::enabled);
+ breakpoint_type["enabled"] = sol::property(
+ &debug_breakpoint::enabled,
+ [] (debug_breakpoint &bp, bool val)
+ {
+ if (bp.enabled() != val)
+ {
+ bp.setEnabled(val);
+ bp.debugInterface()->device().machine().debug_view().update_all(DVT_DISASSEMBLY);
+ bp.debugInterface()->device().machine().debug_view().update_all(DVT_BREAK_POINTS);
+ }
+ });
breakpoint_type["address"] = sol::property(&debug_breakpoint::address);
breakpoint_type["condition"] = sol::property(&debug_breakpoint::condition);
breakpoint_type["action"] = sol::property(&debug_breakpoint::action);
@@ -352,7 +437,16 @@ void lua_engine::initialize_debug(sol::table &emu)
auto watchpoint_type = sol().registry().new_usertype<debug_watchpoint>("watchpoint", sol::no_constructor);
watchpoint_type["index"] = sol::property(&debug_watchpoint::index);
- watchpoint_type["enabled"] = sol::property(&debug_watchpoint::enabled);
+ watchpoint_type["enabled"] = sol::property(
+ &debug_watchpoint::enabled,
+ [] (debug_watchpoint &wp, bool val)
+ {
+ if (wp.enabled() != val)
+ {
+ wp.setEnabled(val);
+ wp.debugInterface()->device().machine().debug_view().update_all(DVT_WATCH_POINTS);
+ }
+ });
watchpoint_type["type"] = sol::property(
[] (debug_watchpoint &wp) -> char const *
{