lsnes/include/core/debug.hpp

203 lines
4.2 KiB
C++

#ifndef _debug__hpp__included__
#define _debug__hpp__included__
#include <functional>
#include <fstream>
#include <cstdint>
#include "library/command.hpp"
#include "library/dispatch.hpp"
class emulator_dispatch;
class loaded_rom;
class memory_space;
/**
* Debugging context.
*/
class debug_context
{
public:
debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom, memory_space& _mspace, command::group& _cmd);
/**
* Type of event.
*/
enum etype
{
DEBUG_READ,
DEBUG_WRITE,
DEBUG_EXEC,
DEBUG_TRACE,
DEBUG_FRAME,
};
/**
* Parameters for read/write/execute event.
*/
struct params_rwx
{
uint64_t addr; //Address.
uint64_t value; //Value/CPU.
};
/**
* Parameters for trace event.
*/
struct params_trace
{
uint64_t cpu; //CPU number.
const char* decoded_insn; //Decoded instruction
bool true_insn; //True instruction flag.
};
/**
* Parameters for frame event.
*/
struct params_frame
{
uint64_t frame; //Frame number.
bool loadstated; //Loadstate flag.
};
/**
* Parameters for debug callback.
*/
struct params
{
etype type;
union {
params_rwx rwx; //READ/WRITE/EXECUTE
params_trace trace; //TRACE.
params_frame frame; //FRAME.
};
};
/**
* Base class of debugging callbacks.
*/
struct callback_base
{
/**
* Destructor.
*/
virtual ~callback_base();
/**
* Do a callback.
*/
virtual void callback(const params& p) = 0;
/**
* Notify about killed callback.
*/
virtual void killed(uint64_t addr, etype type) = 0;
};
/**
* Placeholder for all addresses.
*/
static const uint64_t all_addresses;
/**
* Add a callback.
*/
void add_callback(uint64_t addr, etype type, callback_base& cb);
/**
* Remove a callback.
*/
void remove_callback(uint64_t addr, etype type, callback_base& cb);
/**
* Fire a read callback.
*/
void do_callback_read(uint64_t addr, uint64_t value);
/**
* Fire a write callback.
*/
void do_callback_write(uint64_t addr, uint64_t value);
/**
* Fire a exec callback.
*/
void do_callback_exec(uint64_t addr, uint64_t value);
/**
* Fire a trace callback.
*/
void do_callback_trace(uint64_t cpu, const char* str, bool true_insn = true);
/**
* Fire a frame callback.
*/
void do_callback_frame(uint64_t frame, bool loadstate);
/**
* Set a cheat.
*/
void set_cheat(uint64_t addr, uint64_t value);
/**
* Clear a cheat.
*/
void clear_cheat(uint64_t addr);
/**
* Set execute callback mask.
*/
void setxmask(uint64_t mask);
/**
* Set tracelog file.
*/
void tracelog(uint64_t cpu, const std::string& filename);
/**
* Tracelogging on?
*/
bool is_tracelogging(uint64_t cpu);
/**
* Change tracelog change callback.
*/
void set_tracelog_change_cb(std::function<void()> cb);
/**
* Notify a core change.
*/
void core_change();
/**
* Request a break.
*/
void request_break();
//These are public only for some debugging stuff.
typedef std::list<callback_base*> cb_list;
std::map<uint64_t, cb_list> read_cb;
std::map<uint64_t, cb_list> write_cb;
std::map<uint64_t, cb_list> exec_cb;
std::map<uint64_t, cb_list> trace_cb;
std::map<uint64_t, cb_list> frame_cb;
private:
void do_showhooks();
void do_genevent(const std::string& a);
void do_tracecmd(const std::string& a);
cb_list dummy_cb; //Always empty.
uint64_t xmask = 1;
std::function<void()> tracelog_change_cb;
emulator_dispatch& edispatch;
loaded_rom& rom;
memory_space& mspace;
command::group& cmd;
struct dispatch::target<> corechange;
bool corechange_r = false;
bool requesting_break = false;
command::_fnptr<> showhooks;
command::_fnptr<const std::string&> genevent;
command::_fnptr<const std::string&> tracecmd;
struct tracelog_file : public callback_base
{
std::ofstream stream;
std::string full_filename;
unsigned refcnt;
tracelog_file(debug_context& parent);
~tracelog_file();
void callback(const params& p);
void killed(uint64_t addr, etype type);
private:
debug_context& parent;
};
std::map<uint64_t, tracelog_file*> trace_outputs;
std::map<uint64_t, cb_list>& get_lists(etype type)
{
switch(type) {
case DEBUG_READ: return read_cb;
case DEBUG_WRITE: return write_cb;
case DEBUG_EXEC: return exec_cb;
case DEBUG_TRACE: return trace_cb;
case DEBUG_FRAME: return frame_cb;
default: throw std::runtime_error("Invalid debug callback type");
}
}
};
#endif