diff options
Diffstat (limited to 'trunk/src/emu/debug/debugcpu.h')
-rw-r--r-- | trunk/src/emu/debug/debugcpu.h | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/trunk/src/emu/debug/debugcpu.h b/trunk/src/emu/debug/debugcpu.h new file mode 100644 index 00000000000..2c414b88fc8 --- /dev/null +++ b/trunk/src/emu/debug/debugcpu.h @@ -0,0 +1,460 @@ +/********************************************************************* + + debugcpu.h + + Debugger CPU/memory interface engine. + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#pragma once + +#ifndef __DEBUGCPU_H__ +#define __DEBUGCPU_H__ + +#include "express.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT8 WATCHPOINT_READ = 1; +const UINT8 WATCHPOINT_WRITE = 2; +const UINT8 WATCHPOINT_READWRITE = WATCHPOINT_READ | WATCHPOINT_WRITE; + +const int COMMENT_VERSION = 1; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc); + + +typedef struct _xml_data_node xml_data_node; + + +class device_debug +{ + typedef offs_t (*dasm_override_func)(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options); + +public: + // breakpoint class + class breakpoint + { + friend class device_debug; + + public: + // construction/destruction + breakpoint(symbol_table &symbols, int index, offs_t address, const char *condition = NULL, const char *action = NULL); + + // getters + breakpoint *next() const { return m_next; } + int index() const { return m_index; } + bool enabled() const { return m_enabled; } + offs_t address() const { return m_address; } + const char *condition() const { return m_condition.original_string(); } + const char *action() const { return m_action; } + + private: + // internals + bool hit(offs_t pc); + + breakpoint * m_next; // next in the list + int m_index; // user reported index + UINT8 m_enabled; // enabled? + offs_t m_address; // execution address + parsed_expression m_condition; // condition + astring m_action; // action + }; + + // watchpoint class + class watchpoint + { + friend class device_debug; + + public: + // construction/destruction + watchpoint(symbol_table &symbols, int index, address_space &space, int type, offs_t address, offs_t length, const char *condition = NULL, const char *action = NULL); + + // getters + watchpoint *next() const { return m_next; } + address_space &space() const { return m_space; } + int index() const { return m_index; } + int type() const { return m_type; } + bool enabled() const { return m_enabled; } + offs_t address() const { return m_address; } + offs_t length() const { return m_length; } + const char *condition() const { return m_condition.original_string(); } + const char *action() const { return m_action; } + + private: + // internals + bool hit(int type, offs_t address, int size); + + watchpoint * m_next; // next in the list + address_space & m_space; // address space + int m_index; // user reported index + bool m_enabled; // enabled? + UINT8 m_type; // type (read/write) + offs_t m_address; // start address + offs_t m_length; // length of watch area + parsed_expression m_condition; // condition + astring m_action; // action + }; + +public: + // construction/destruction + device_debug(device_t &device); + ~device_debug(); + + // getters + symbol_table &symtable() { return m_symtable; } + + // commonly-used pass-throughs + offs_t pc() const { return (m_state != NULL) ? m_state->pc() : 0; } + int logaddrchars(address_spacenum spacenum = AS_0) const { return (m_memory != NULL && m_memory->space(spacenum) != NULL) ? m_memory->space(spacenum)->logaddrchars() : 8; } + int min_opcode_bytes() const { return (m_disasm != NULL) ? m_disasm->max_opcode_bytes() : 1; } + int max_opcode_bytes() const { return (m_disasm != NULL) ? m_disasm->max_opcode_bytes() : 1; } + + // hooks used by the rest of the system + void start_hook(attotime endtime); + void stop_hook(); + void interrupt_hook(int irqline); + void exception_hook(int exception); + void instruction_hook(offs_t curpc); + void memory_read_hook(address_space &space, offs_t address, UINT64 mem_mask); + void memory_write_hook(address_space &space, offs_t address, UINT64 data, UINT64 mem_mask); + + // hooks into our operations + void set_instruction_hook(debug_instruction_hook_func hook); + void set_dasm_override(dasm_override_func dasm_override) { m_dasm_override = dasm_override; } + + // disassembly + offs_t disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) const; + + // debugger focus + void ignore(bool ignore = true); + bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); } + + // single stepping + void single_step(int numsteps = 1); + void single_step_over(int numsteps = 1); + void single_step_out(); + + // execution + void go(offs_t targetpc = ~0); + void go_vblank(); + void go_interrupt(int irqline = -1); + void go_exception(int exception); + void go_milliseconds(UINT64 milliseconds); + void go_next_device(); + void halt_on_next_instruction(const char *fmt, ...); + + // breakpoints + breakpoint *breakpoint_first() const { return m_bplist; } + int breakpoint_set(offs_t address, const char *condition = NULL, const char *action = NULL); + bool breakpoint_clear(int index); + void breakpoint_clear_all(); + bool breakpoint_enable(int index, bool enable = true); + void breakpoint_enable_all(bool enable = true); + + // watchpoints + watchpoint *watchpoint_first(address_spacenum spacenum) const { return m_wplist[spacenum]; } + int watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action); + bool watchpoint_clear(int wpnum); + void watchpoint_clear_all(); + bool watchpoint_enable(int index, bool enable = true); + void watchpoint_enable_all(bool enable = true); + + // hotspots + bool hotspot_tracking_enabled() const { return (m_hotspots != NULL); } + void hotspot_track(int numspots, int threshhold); + + // comments + void comment_add(offs_t address, const char *comment, rgb_t color); + bool comment_remove(offs_t addr); + const char *comment_text(offs_t addr) const; + UINT32 comment_count() const { return m_comment_list.count(); } + UINT32 comment_change_count() const { return m_comment_change; } + bool comment_export(xml_data_node &node); + bool comment_import(xml_data_node &node); + void comment_dump(offs_t addr = ~0); + UINT32 compute_opcode_crc32(offs_t address) const; + + // history + offs_t history_pc(int index) const; + + // tracing + void trace(FILE *file, bool trace_over, const char *action); + void trace_printf(const char *fmt, ...); + void trace_flush() { if (m_trace != NULL) m_trace->flush(); } + + void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; } + + static const int HISTORY_SIZE = 256; + +private: + // internal helpers + void compute_debug_flags(); + void prepare_for_step_overout(offs_t pc); + UINT32 dasm_wrapped(astring &buffer, offs_t pc); + + // breakpoint and watchpoint helpers + void breakpoint_update_flags(); + void breakpoint_check(offs_t pc); + void watchpoint_update_flags(address_space &space); + void watchpoint_check(address_space &space, int type, offs_t address, UINT64 value_to_write, UINT64 mem_mask); + void hotspot_check(address_space &space, offs_t address); + + // symbol get/set callbacks + static UINT64 get_current_pc(symbol_table &table, void *ref); + static UINT64 get_cycles(symbol_table &table, void *ref); + static UINT64 get_logunmap(symbol_table &table, void *ref); + static void set_logunmap(symbol_table &table, void *ref, UINT64 value); + static UINT64 get_state(symbol_table &table, void *ref); + static void set_state(symbol_table &table, void *ref, UINT64 value); + + // basic device information + device_t & m_device; // device we are attached to + device_execute_interface *m_exec; // execute interface, if present + device_memory_interface *m_memory; // memory interface, if present + device_state_interface *m_state; // state interface, if present + device_disasm_interface *m_disasm; // disasm interface, if present + + // global state + UINT32 m_flags; // debugging flags for this CPU + symbol_table m_symtable; // symbol table for expression evaluation + debug_instruction_hook_func m_instrhook; // per-instruction callback hook + + // disassembly + dasm_override_func m_dasm_override; // pointer to provided override function + UINT8 m_opwidth; // width of an opcode + + // stepping information + offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER + int m_stepsleft; // number of steps left until done + + // execution information + offs_t m_stopaddr; // stop address for DEBUG_FLAG_STOP_PC + attotime m_stoptime; // stop time for DEBUG_FLAG_STOP_TIME + int m_stopirq; // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT + int m_stopexception; // stop exception number for DEBUG_FLAG_STOP_EXCEPTION + attotime m_endexectime; // ending time of the current execution + + // history + offs_t m_pc_history[HISTORY_SIZE]; // history of recent PCs + UINT32 m_pc_history_index; // current history index + + // breakpoints and watchpoints + breakpoint * m_bplist; // list of breakpoints + watchpoint * m_wplist[ADDRESS_SPACES]; // watchpoint lists for each address space + + // tracing + class tracer + { + public: + tracer(device_debug &debug, FILE &file, bool trace_over, const char *action); + ~tracer(); + + void update(offs_t pc); + void vprintf(const char *format, va_list va); + void flush(); + + private: + static const int TRACE_LOOPS = 64; + + device_debug & m_debug; // reference to our owner + FILE & m_file; // tracing file for this CPU + astring m_action; // action to perform during a trace + offs_t m_history[TRACE_LOOPS]; // history of recent PCs + int m_loops; // number of instructions in a loop + int m_nextdex; // next index + bool m_trace_over; // true if we're tracing over + offs_t m_trace_over_target; // target for tracing over + // (0 = not tracing over, + // ~0 = not currently tracing over) + }; + tracer * m_trace; // tracer state + + // hotspots + struct hotspot_entry + { + offs_t m_access; // access address + offs_t m_pc; // PC of the access + address_space * m_space; // space where the access occurred + UINT32 m_count; // number of hits + }; + hotspot_entry * m_hotspots; // hotspot list + int m_hotspot_count; // number of hotspots + int m_hotspot_threshhold; // threshhold for the number of hits to print + + // comments + class dasm_comment + { + public: + dasm_comment(const char *text, offs_t address, rgb_t color, UINT32 crc); + + dasm_comment *next() const { return m_next; } + + dasm_comment * m_next; // next comment in the list + offs_t m_address; // address in question + rgb_t m_color; // color to use + UINT32 m_crc; // CRC of code + astring m_text; // text + }; + simple_list<dasm_comment> m_comment_list; // list of comments + UINT32 m_comment_change; // change counter for comments + + // internal flag values + static const UINT32 DEBUG_FLAG_OBSERVING = 0x00000001; // observing this CPU + static const UINT32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history + static const UINT32 DEBUG_FLAG_TRACING = 0x00000004; // tracing this CPU + static const UINT32 DEBUG_FLAG_TRACING_OVER = 0x00000008; // tracing this CPU with step over behavior + static const UINT32 DEBUG_FLAG_HOOKED = 0x00000010; // per-instruction callback hook + static const UINT32 DEBUG_FLAG_STEPPING = 0x00000020; // CPU is single stepping + static const UINT32 DEBUG_FLAG_STEPPING_OVER = 0x00000040; // CPU is stepping over a function + static const UINT32 DEBUG_FLAG_STEPPING_OUT = 0x00000080; // CPU is stepping out of a function + static const UINT32 DEBUG_FLAG_STOP_PC = 0x00000100; // there is a pending stop at cpu->breakpc + static const UINT32 DEBUG_FLAG_STOP_INTERRUPT = 0x00000400; // there is a pending stop on the next interrupt + static const UINT32 DEBUG_FLAG_STOP_EXCEPTION = 0x00000800; // there is a pending stop on the next exception + static const UINT32 DEBUG_FLAG_STOP_VBLANK = 0x00001000; // there is a pending stop on the next VBLANK + static const UINT32 DEBUG_FLAG_STOP_TIME = 0x00002000; // there is a pending stop at cpu->stoptime + static const UINT32 DEBUG_FLAG_LIVE_BP = 0x00010000; // there are live breakpoints for this CPU + + static const UINT32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT; + static const UINT32 DEBUG_FLAG_TRACING_ANY = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER; + static const UINT32 DEBUG_FLAG_TRANSIENT = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | + DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK | DEBUG_FLAG_STOP_TIME; +}; + + + +//************************************************************************** +// FUNCTION PROTOTYPES +//************************************************************************** + +/* ----- initialization and cleanup ----- */ + +/* initialize the CPU tracking for the debugger */ +void debug_cpu_init(running_machine &machine); +void debug_cpu_configure_memory(running_machine &machine, symbol_table &table); + +/* flushes all traces; this is useful if a trace is going on when we fatalerror */ +void debug_cpu_flush_traces(running_machine &machine); + + + +/* ----- debugging status & information ----- */ + +/* return the visible CPU device (the one that commands should apply to) */ +device_t *debug_cpu_get_visible_cpu(running_machine &machine); + +/* TRUE if the debugger is currently stopped within an instruction hook callback */ +int debug_cpu_within_instruction_hook(running_machine &machine); + +/* return TRUE if the current execution state is stopped */ +int debug_cpu_is_stopped(running_machine &machine); + + + +/* ----- symbol table interfaces ----- */ + +/* return the global symbol table */ +symbol_table *debug_cpu_get_global_symtable(running_machine &machine); + +/* return the locally-visible symbol table */ +symbol_table *debug_cpu_get_visible_symtable(running_machine &machine); + + + +/* ----- misc debugger functions ----- */ + +/* specifies a debug command script to execute */ +void debug_cpu_source_script(running_machine &machine, const char *file); + + + +/* ----- debugger comment helpers ----- */ + +// save all comments for a given machine +bool debug_comment_save(running_machine &machine); + +// load all comments for a given machine +bool debug_comment_load(running_machine &machine); + + + +/* ----- debugger memory accessors ----- */ + +/* return the physical address corresponding to the given logical address */ +int debug_cpu_translate(address_space *space, int intention, offs_t *address); + +/* return a byte from the the specified memory space */ +UINT8 debug_read_byte(address_space *space, offs_t address, int apply_translation); + +/* return a word from the the specified memory space */ +UINT16 debug_read_word(address_space *space, offs_t address, int apply_translation); + +/* return a dword from the the specified memory space */ +UINT32 debug_read_dword(address_space *space, offs_t address, int apply_translation); + +/* return a qword from the the specified memory space */ +UINT64 debug_read_qword(address_space *space, offs_t address, int apply_translation); + +/* return 1,2,4 or 8 bytes from the specified memory space */ +UINT64 debug_read_memory(address_space *space, offs_t address, int size, int apply_translation); + +/* write a byte to the specified memory space */ +void debug_write_byte(address_space *space, offs_t address, UINT8 data, int apply_translation); + +/* write a word to the specified memory space */ +void debug_write_word(address_space *space, offs_t address, UINT16 data, int apply_translation); + +/* write a dword to the specified memory space */ +void debug_write_dword(address_space *space, offs_t address, UINT32 data, int apply_translation); + +/* write a qword to the specified memory space */ +void debug_write_qword(address_space *space, offs_t address, UINT64 data, int apply_translation); + +/* write 1,2,4 or 8 bytes to the specified memory space */ +void debug_write_memory(address_space *space, offs_t address, UINT64 data, int size, int apply_translation); + +/* read 1,2,4 or 8 bytes at the given offset from opcode space */ +UINT64 debug_read_opcode(address_space *space, offs_t offset, int size, int arg); + + +#endif |