1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
|
/*********************************************************************
debugcpu.h
Debugger CPU/memory interface engine.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
*********************************************************************/
#pragma once
#ifndef __DEBUGCPU_H__
#define __DEBUGCPU_H__
#include "cpuintrf.h"
#include "express.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
#define TRACE_LOOPS 64
#define DEBUG_HISTORY_SIZE 256
#define WATCHPOINT_READ 1
#define WATCHPOINT_WRITE 2
#define WATCHPOINT_READWRITE (WATCHPOINT_READ | WATCHPOINT_WRITE)
#define DEBUG_FLAG_OBSERVING 0x00000001 /* observing this CPU */
#define DEBUG_FLAG_HISTORY 0x00000002 /* tracking this CPU's history */
#define DEBUG_FLAG_TRACING 0x00000004 /* tracing this CPU */
#define DEBUG_FLAG_TRACING_OVER 0x00000008 /* tracing this CPU with step over behavior */
#define DEBUG_FLAG_HOOKED 0x00000010 /* per-instruction callback hook */
#define DEBUG_FLAG_STEPPING 0x00000020 /* CPU is single stepping */
#define DEBUG_FLAG_STEPPING_OVER 0x00000040 /* CPU is stepping over a function */
#define DEBUG_FLAG_STEPPING_OUT 0x00000080 /* CPU is stepping out of a function */
#define DEBUG_FLAG_STOP_PC 0x00000100 /* there is a pending stop at cpu->breakpc */
#define DEBUG_FLAG_STOP_CONTEXT 0x00000200 /* there is a pending stop on next context switch */
#define DEBUG_FLAG_STOP_INTERRUPT 0x00000400 /* there is a pending stop on the next interrupt */
#define DEBUG_FLAG_STOP_EXCEPTION 0x00000800 /* there is a pending stop on the next exception */
#define DEBUG_FLAG_STOP_VBLANK 0x00001000 /* there is a pending stop on the next VBLANK */
#define DEBUG_FLAG_STOP_TIME 0x00002000 /* there is a pending stop at cpu->stoptime */
#define DEBUG_FLAG_LIVE_BP 0x00010000 /* there are live breakpoints for this CPU */
#define DEBUG_FLAG_STEPPING_ANY (DEBUG_FLAG_STEPPING | \
DEBUG_FLAG_STEPPING_OVER | \
DEBUG_FLAG_STEPPING_OUT)
#define DEBUG_FLAG_TRACING_ANY (DEBUG_FLAG_TRACING | \
DEBUG_FLAG_TRACING_OVER)
#define DEBUG_FLAG_TRANSIENT (DEBUG_FLAG_STEPPING_ANY | \
DEBUG_FLAG_STOP_PC | \
DEBUG_FLAG_STOP_CONTEXT | \
DEBUG_FLAG_STOP_INTERRUPT | \
DEBUG_FLAG_STOP_EXCEPTION | \
DEBUG_FLAG_STOP_VBLANK | \
DEBUG_FLAG_STOP_TIME)
/***************************************************************************
MACROS
***************************************************************************/
#define ADDR2BYTE(val,info,spc) (((val) << (info)->space[spc].addr2byte_lshift) >> (info)->space[spc].addr2byte_rshift)
#define ADDR2BYTE_MASKED(val,info,spc) (ADDR2BYTE(val,info,spc) & (info)->space[spc].logbytemask)
#define BYTE2ADDR(val,info,spc) (((val) << (info)->space[spc].addr2byte_rshift) >> (info)->space[spc].addr2byte_lshift)
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
typedef int (*debug_instruction_hook_func)(const device_config *device, offs_t curpc);
typedef struct _debug_cpu_breakpoint debug_cpu_breakpoint;
typedef struct _debug_cpu_watchpoint debug_cpu_watchpoint;
typedef struct _debug_trace_info debug_trace_info;
struct _debug_trace_info
{
FILE * file; /* tracing file for this CPU */
char * action; /* action to perform during a trace */
offs_t history[TRACE_LOOPS]; /* history of recent PCs */
int loops; /* number of instructions in a loop */
int nextdex; /* next index */
offs_t trace_over_target; /* target for tracing over
(0 = not tracing over,
~0 = not currently tracing over) */
};
typedef struct _debug_space_info debug_space_info;
struct _debug_space_info
{
const address_space *space; /* pointer to the CPU's address space */
debug_cpu_watchpoint *wplist; /* list of watchpoints */
UINT8 databytes; /* width of the data bus, in bytes */
UINT8 pageshift; /* page shift */
UINT8 addr2byte_lshift; /* left shift to convert CPU address to a byte value */
UINT8 addr2byte_rshift; /* right shift to convert CPU address to a byte value */
UINT8 physchars; /* number of characters to use for physical addresses */
UINT8 logchars; /* number of characters to use for logical addresses */
offs_t physaddrmask; /* physical address mask */
offs_t logaddrmask; /* logical address mask */
offs_t physbytemask; /* physical byte mask */
offs_t logbytemask; /* logical byte mask */
};
typedef struct _debug_hotspot_entry debug_hotspot_entry;
struct _debug_hotspot_entry
{
offs_t access; /* access address */
offs_t pc; /* PC of the access */
int spacenum; /* space where the access occurred */
UINT32 count; /* number of hits */
};
/* In cpuintrf.h: typedef struct _cpu_debug_data cpu_debug_data; */
struct _cpu_debug_data
{
const device_config *device; /* CPU device object */
symbol_table * symtable; /* symbol table for expression evaluation */
UINT32 flags; /* debugging flags for this CPU */
UINT8 endianness; /* little or bigendian */
UINT8 opwidth; /* width of an opcode */
offs_t stepaddr; /* step target address for DEBUG_FLAG_STEPPING_OVER */
int stepsleft; /* number of steps left until done */
offs_t stopaddr; /* stop address for DEBUG_FLAG_STOP_PC */
attotime stoptime; /* stop time for DEBUG_FLAG_STOP_TIME */
int stopirq; /* stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT */
int stopexception; /* stop exception number for DEBUG_FLAG_STOP_EXCEPTION */
attotime endexectime; /* ending time of the current execution */
debug_trace_info trace; /* trace info */
debug_cpu_breakpoint *bplist; /* list of breakpoints */
debug_hotspot_entry *hotspots; /* hotspot list */
offs_t pc_history[DEBUG_HISTORY_SIZE]; /* history of recent PCs */
UINT32 pc_history_index; /* current history index */
int hotspot_count; /* number of hotspots */
int hotspot_threshhold; /* threshhold for the number of hits to print */
cpu_translate_func translate; /* address translation routine */
cpu_read_func read; /* memory read routine */
cpu_write_func write; /* memory write routine */
cpu_readop_func readop; /* opcode read routine */
debug_instruction_hook_func instrhook; /* per-instruction callback hook */
debug_space_info space[ADDRESS_SPACES]; /* per-address space info */
};
struct _debug_cpu_breakpoint
{
debug_cpu_breakpoint *next; /* next in the list */
int index; /* user reported index */
UINT8 enabled; /* enabled? */
offs_t address; /* execution address */
parsed_expression *condition; /* condition */
char * action; /* action */
};
struct _debug_cpu_watchpoint
{
int index; /* user reported index */
UINT8 enabled; /* enabled? */
UINT8 type; /* type (read/write) */
offs_t address; /* start address */
offs_t length; /* length of watch area */
parsed_expression *condition; /* condition */
char * action; /* action */
debug_cpu_watchpoint *next; /* next in the list */
};
/***************************************************************************
GLOBAL VARIABLES
***************************************************************************/
extern const express_callbacks debug_expression_callbacks;
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
/* ----- initialization and cleanup ----- */
/* initialize the CPU tracking for the debugger */
void debug_cpu_init(running_machine *machine);
/* 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) */
const device_config *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);
/* return a specific CPU's symbol table */
symbol_table *debug_cpu_get_symtable(const device_config *device);
/* ----- core debugger hooks ----- */
/* the CPU execution system calls this hook before beginning execution for the given CPU */
void debug_cpu_start_hook(const device_config *device, attotime endtime);
/* the CPU execution system calls this hook when ending execution for the given CPU */
void debug_cpu_stop_hook(const device_config *device);
/* the CPU execution system calls this hook when an interrupt is acknowledged */
void debug_cpu_interrupt_hook(const device_config *device, int irqline);
/* called by the CPU cores when an exception is generated */
void debug_cpu_exception_hook(const device_config *device, int exception);
/* called by the CPU cores before executing each instruction */
void debug_cpu_instruction_hook(const device_config *device, offs_t curpc);
/* the memory system calls this hook when watchpoints are enabled and a memory read happens */
void debug_cpu_memory_read_hook(const address_space *space, offs_t address, UINT64 mem_mask);
/* the memory system calls this hook when watchpoints are enabled and a memory write happens */
void debug_cpu_memory_write_hook(const address_space *space, offs_t address, UINT64 data, UINT64 mem_mask);
/* ----- execution control ----- */
/* halt in the debugger on the next instruction */
void debug_cpu_halt_on_next_instruction(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3);
/* ignore/observe a given CPU */
void debug_cpu_ignore_cpu(const device_config *cpu, int ignore);
/* single step the visible CPU past the requested number of instructions */
void debug_cpu_single_step(running_machine *machine, int numsteps);
/* single step the visible over the requested number of instructions */
void debug_cpu_single_step_over(running_machine *machine, int numsteps);
/* single step the visible CPU out of the current function */
void debug_cpu_single_step_out(running_machine *machine);
/* execute the visible CPU until it hits the given address */
void debug_cpu_go(running_machine *machine, offs_t targetpc);
/* execute until the next VBLANK */
void debug_cpu_go_vblank(running_machine *machine);
/* execute until the specified interrupt fires on the visible CPU */
void debug_cpu_go_interrupt(running_machine *machine, int irqline);
/* execute until the specified exception fires on the visible CPU */
void debug_cpu_go_exception(running_machine *machine, int exception);
/* execute until the specified delay elapses */
void debug_cpu_go_milliseconds(running_machine *machine, UINT64 milliseconds);
/* execute until we hit the next CPU */
void debug_cpu_next_cpu(running_machine *machine);
/* ----- breakpoints ----- */
/* set a new breakpoint, returning its index */
int debug_cpu_breakpoint_set(const device_config *device, offs_t address, parsed_expression *condition, const char *action);
/* clear a breakpoint by index */
int debug_cpu_breakpoint_clear(running_machine *machine, int bpnum);
/* enable/disable a breakpoint by index */
int debug_cpu_breakpoint_enable(running_machine *machine, int bpnum, int enable);
/* ----- watchpoints ----- */
/* set a new watchpoint, returning its index */
int debug_cpu_watchpoint_set(const address_space *space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action);
/* clear a watchpoint by index */
int debug_cpu_watchpoint_clear(running_machine *machine, int wpnum);
/* enable/disable a watchpoint by index */
int debug_cpu_watchpoint_enable(running_machine *machine, int wpnum, int enable);
/* ----- misc debugger functions ----- */
/* specifies a debug command script to execute */
void debug_cpu_source_script(running_machine *machine, const char *file);
/* trace execution of a given CPU */
void debug_cpu_trace(const device_config *device, FILE *file, int trace_over, const char *action);
/* output data into the given CPU's tracefile, if tracing */
void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3);
/* set a hook to be called on each instruction for a given CPU */
void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook);
/* hotspots */
int debug_cpu_hotspot_track(const device_config *device, int numspots, int threshhold);
/* ----- debugger memory accessors ----- */
/* return a byte from the the specified memory space */
UINT8 debug_read_byte(const address_space *space, offs_t address, int apply_translation);
/* return a word from the the specified memory space */
UINT16 debug_read_word(const address_space *space, offs_t address, int apply_translation);
/* return a dword from the the specified memory space */
UINT32 debug_read_dword(const address_space *space, offs_t address, int apply_translation);
/* return a qword from the the specified memory space */
UINT64 debug_read_qword(const address_space *space, offs_t address, int apply_translation);
/* write a byte to the specified memory space */
void debug_write_byte(const address_space *space, offs_t address, UINT8 data, int apply_translation);
/* write a word to the specified memory space */
void debug_write_word(const address_space *space, offs_t address, UINT16 data, int apply_translation);
/* write a dword to the specified memory space */
void debug_write_dword(const address_space *space, offs_t address, UINT32 data, int apply_translation);
/* write a qword to the specified memory space */
void debug_write_qword(const address_space *space, offs_t address, UINT64 data, int apply_translation);
/* read 1,2,4 or 8 bytes at the given offset from opcode space */
UINT64 debug_read_opcode(const address_space *space, offs_t offset, int size, int arg);
#endif
|