aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/DebugMgr.h
blob: 351b72942744dabe64959483ff914438df694a26 (plain)
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
/* -*- mode: C++; tab-width: 4 -*- */
/* ===================================================================== *\
	Copyright (c) 1998-2001 Palm, Inc. or its subsidiaries.
	All rights reserved.

	This file is part of the Palm OS Emulator.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
\* ===================================================================== */

#ifndef _DEBUGMGR_H_
#define _DEBUGMGR_H_

#include "EmCPU68K.h"			// ExceptionNumber
#include "EmMemory.h"			// CEnableFullAccess
#include "EmTypes.h"			// ErrCode

// Types

#pragma mark Types

class SLP;
class CSocket;
class CTCPSocket;

struct SystemCallContext;

typedef uint32	(*registerFun)(int num);
typedef Bool	(*compareFun)(UInt32 a, UInt32 b);

// Breakpoint conditions are of the form:
//
//		<register-expr>[<size>] <cond> <value>
//
// where:
//
//		<register-expr>
//			is either a 68000 register (e.g. "d5") or an indirect reference at
//			a constant offset from a 68000 register (e.g. "8(a6)").  An indirect
//			reference reads from memory; when you set up a breakpoint condition
//			involving an indirect reference, you must be sure that the indirect
//			reference will point to a valid memory address whenever the breakpoint
//			is hit.
//
//		<size>
//			is either ".l" (long), ".w" (word) or ".b" (byte).  If no size is
//			specified, the expression is assumed to be long.
//
//		<cond>
//			is a binary comparison operator: ==, !=, <=, >=, <, or >
//
//		<value>
//			is a 32-bit integer
//
// All comparisons are unsigned!

struct BreakpointCondition
{
	registerFun				regType;
	int				 		regNum;
	Bool					indirect;
	uint32			 		indirectOffset;
	int						size;				/* number of bytes to compare: 4, 2, or 1 */

	compareFun				condition;
	uint32					value;

	// The source text.  We keep this around so that, for example, a user can specify
	// a condition using either hex or decimal notation and they will see the same
	// notation the next time they edit the breakpoint.

	char*					source;

	Bool					Evaluate (void);
};

struct EmBreakpointType
{
	MemPtr					addr;				// address of breakpoint
	Boolean					enabled;			// true if enabled
	Boolean					installed;			// for alignment
};

struct DebugGlobalsType
{
	// Mode settings

	bool					ignoreDbgBreaks;	// if true, ignore DbgBreak's
	bool					firstEntrance;		// true first time we enter debugger
	bool					stepSpy;			// true if step spying.
	bool					breakingOnATrap;	// true if there are A-Traps to check
	bool					continueOverATrap;	// true if skipping over next system call
	bool					continueOverBP; 	// true if skipping over next breakpoint

	bool					checkTrapWordOnExit;
	uint16 					trapWord;
	uint16			 		refNum;

	// Breakpoints and saved opcodes behind each one

	EmBreakpointType		bp[dbgTotalBreakpoints];
	BreakpointCondition*	bpCondition[dbgTotalBreakpoints];	// condition, or NULL if none

	// Current trap breaks

	UInt16					trapBreak[dbgTotalTrapBreaks];
	UInt16					trapParam[dbgTotalTrapBreaks];

	// Step spy support

	emuptr			 		ssAddr; 			// address to step spy on
	UInt32					ssValue;			// saved value

	// Exception type

	int32			 		excType;			// why we entered debugger

	// (adam) Data breakpoint support.	This is similar to the step spy capability, but can monitor
	// an arbitrary range of addresses for writes, and doesn't require a saved value.

	bool					watchEnabled;
	emuptr			 		watchAddr;			// address to watch, or 0 if none
	UInt32					watchBytes; 		// number of bytes to watch
};

// class Debug

#pragma mark class Debug

	// Referenced in SystemPacket.cpp
extern DebugGlobalsType 	gDebuggerGlobals;

extern emuptr	gExceptionAddress;
extern int		gExceptionSize;
extern Bool		gExceptionForRead;


class Debug
{
	public:
		static void 			Initialize				(void);
		static void 			Reset					(void);
		static void 			Save					(SessionFile&);
		static void 			Load					(SessionFile&);
		static void 			Dispose 				(void);

		static void 			Startup 				(void);
		static void 			Shutdown				(void);
		static Bool 			ConnectedToTCPDebugger	(void);
		static CTCPSocket*		GetTCPDebuggerSocket	(void);
		static CSocket*			GetDebuggerSocket		(void);

		static ErrCode			HandleNewPacket 		(SLP&);

		static Bool 			BreakIfConnected		(ExceptionNumber);
		static Bool 			HandleTrap8 			(ExceptionNumber);
		static Bool 			HandleSystemCall		(const SystemCallContext& context);
		static ErrCode			EnterDebugger			(ExceptionNumber, SLP*);
		static ErrCode			ExitDebugger			(void);
		static void 			CheckStepSpy			(emuptr writeAddress, int writeBytes);

		static void 			HandleInstructionBreak	(void);
		static void 			InstallInstructionBreaks(void);
		static void 			RemoveInstructionBreaks	(void);

		static BreakpointCondition*
								NewBreakpointCondition	(const char* sourceString);
		static void 			SetBreakpoint			(int index, emuptr addr, BreakpointCondition* c);
		static void 			ClearBreakpoint 		(int index);
		static void 			DeleteBreakpointCondition	(int index);

		static Bool				BreakpointInstalled		(void);

	private:
		static void 			ConditionalBreak		(void);
		static Bool 			MustBreakOnTrapSystemCall	(uint16 trapWord, uint16 refNum);

		static void 			DoCheckStepSpy			(emuptr writeAddress, int writeBytes);
		static void 			DoCheckWatchpoint		(emuptr writeAddress, int writeBytes);

		static void 			EventCallback			(CSocket* s, int event);
		static void 			CreateListeningSockets	(void);
		static void 			DeleteListeningSockets	(void);
};


// This function is called from the memory setter functions. Make it inline so
// that the common case where stepSpy == FALSE executes quickly.  Yes, this
// _does_ make a difference.

inline void Debug::CheckStepSpy (emuptr writeAddress, int writeBytes)
{
	if (gDebuggerGlobals.stepSpy)
	{
		Debug::DoCheckStepSpy (writeAddress, writeBytes);
	}

	if (gDebuggerGlobals.watchEnabled)
	{
		Debug::DoCheckWatchpoint (writeAddress, writeBytes);
	}
}


#endif /* _DEBUGMGR_H_ */