summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/debug/debugcpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/debug/debugcpu.h')
-rw-r--r--trunk/src/emu/debug/debugcpu.h461
1 files changed, 461 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..c8f5930f69c
--- /dev/null
+++ b/trunk/src/emu/debug/debugcpu.h
@@ -0,0 +1,461 @@
+/*********************************************************************
+
+ 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_totalcycles(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