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_ */
|