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