325 lines
7.6 KiB
C
325 lines
7.6 KiB
C
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Debuggee state buffers.
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1999-2000.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#ifndef __STATEBUF_H__
|
||
|
#define __STATEBUF_H__
|
||
|
|
||
|
// Different WU_UPDATE qualifiers, sent in WPARAM.
|
||
|
enum UpdateType
|
||
|
{
|
||
|
UPDATE_BUFFER,
|
||
|
UPDATE_BP,
|
||
|
UPDATE_EXEC,
|
||
|
UPDATE_INPUT_REQUIRED,
|
||
|
UPDATE_START_SESSION,
|
||
|
UPDATE_END_SESSION,
|
||
|
UPDATE_PROMPT_TEXT,
|
||
|
UPDATE_EXIT
|
||
|
};
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
MINVAL_WINDOW = 0,
|
||
|
DOC_WINDOW,
|
||
|
WATCH_WINDOW,
|
||
|
LOCALS_WINDOW,
|
||
|
CPU_WINDOW,
|
||
|
DISASM_WINDOW,
|
||
|
CMD_WINDOW,
|
||
|
SCRATCH_PAD_WINDOW,
|
||
|
MEM_WINDOW,
|
||
|
QUICKW_WINDOW,
|
||
|
CALLS_WINDOW,
|
||
|
PROCESS_THREAD_WINDOW,
|
||
|
MAXVAL_WINDOW,
|
||
|
// Artificial values so there are well-defined bit
|
||
|
// positions for state which is not tied to a specific window.
|
||
|
EVENT_BIT,
|
||
|
BP_BIT,
|
||
|
BP_CMDS_BIT,
|
||
|
FILTER_BIT,
|
||
|
MODULE_BIT
|
||
|
} WIN_TYPES, * PWIN_TYPES;
|
||
|
|
||
|
#define FIRST_WINDOW ((WIN_TYPES)(MINVAL_WINDOW + 1))
|
||
|
#define LAST_WINDOW ((WIN_TYPES)(MAXVAL_WINDOW - 1))
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// StateBuffer.
|
||
|
//
|
||
|
// A state buffer is a dynamic container for data passed from
|
||
|
// the engine thread to the UI thread. It may be used for
|
||
|
// holding window content, in which case it will have an HWND
|
||
|
// associated with it, or it can be an internal buffer for non-UI
|
||
|
// purposes.
|
||
|
//
|
||
|
// A list of current window-associated state buffers is kept for
|
||
|
// the engine to traverse when it is updating state for the UI.
|
||
|
// The UI thread is the only thread that can add to this list.
|
||
|
// The engine thread is the only thread that can remove a buffer
|
||
|
// from the list. This is necessary for proper lifetime management
|
||
|
// of dynamically-created buffers.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class StateBuffer : public LIST_ENTRY
|
||
|
{
|
||
|
public:
|
||
|
DBG_CRITICAL_SECTION m_Lock;
|
||
|
WIN_TYPES m_enumType;
|
||
|
HWND m_Win;
|
||
|
ULONG m_UpdateTypes;
|
||
|
UpdateType m_UpdateType;
|
||
|
|
||
|
StateBuffer(ULONG ChangeBy);
|
||
|
virtual ~StateBuffer(void);
|
||
|
|
||
|
PVOID AddData(ULONG Len);
|
||
|
BOOL AddString(PCSTR Str, BOOL SoftTerminate);
|
||
|
void RemoveHead(ULONG Len);
|
||
|
void RemoveMiddle(ULONG Start, ULONG Len);
|
||
|
void RemoveTail(ULONG Len);
|
||
|
HRESULT Resize(ULONG Len);
|
||
|
void Free(void);
|
||
|
|
||
|
void Empty(void)
|
||
|
{
|
||
|
m_DataUsed = 0;
|
||
|
}
|
||
|
HRESULT GetStatus(void)
|
||
|
{
|
||
|
return m_Status;
|
||
|
}
|
||
|
void SetStatus(HRESULT Status)
|
||
|
{
|
||
|
m_Status = Status;
|
||
|
}
|
||
|
ULONG GetReadRequest(void)
|
||
|
{
|
||
|
return m_ReadRequest;
|
||
|
}
|
||
|
ULONG GetReadDone(void)
|
||
|
{
|
||
|
return m_ReadDone;
|
||
|
}
|
||
|
void RequestRead(void)
|
||
|
{
|
||
|
InterlockedIncrement((LONG *)&m_ReadRequest);
|
||
|
}
|
||
|
void SetReadDone(ULONG Done)
|
||
|
{
|
||
|
m_ReadDone = Done;
|
||
|
}
|
||
|
PVOID GetDataBuffer(void)
|
||
|
{
|
||
|
return m_Data;
|
||
|
}
|
||
|
ULONG GetDataLen(void)
|
||
|
{
|
||
|
return m_DataUsed;
|
||
|
}
|
||
|
|
||
|
HRESULT Update(void);
|
||
|
|
||
|
void UiRequestRead(void);
|
||
|
HRESULT UiLockForRead(void);
|
||
|
|
||
|
// Base implementation just returns S_OK for
|
||
|
// buffers maintained in other ways.
|
||
|
// ReadState should only be called in the engine thread.
|
||
|
virtual HRESULT ReadState(void);
|
||
|
|
||
|
protected:
|
||
|
void SetNoData(void)
|
||
|
{
|
||
|
m_Data = NULL;
|
||
|
m_DataLen = 0;
|
||
|
Empty();
|
||
|
}
|
||
|
|
||
|
ULONG m_ChangeBy;
|
||
|
|
||
|
UINT m_UpdateMessage;
|
||
|
HRESULT m_Status;
|
||
|
ULONG m_ReadRequest;
|
||
|
ULONG m_ReadDone;
|
||
|
|
||
|
PBYTE m_Data;
|
||
|
ULONG m_DataLen;
|
||
|
ULONG m_DataUsed;
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// OutputToStateBuffer.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class OutputToStateBuffer : public DefOutputCallbacks
|
||
|
{
|
||
|
public:
|
||
|
OutputToStateBuffer(void)
|
||
|
{
|
||
|
m_Buffer = NULL;
|
||
|
}
|
||
|
|
||
|
void SetBuffer(StateBuffer* Buffer)
|
||
|
{
|
||
|
m_Buffer = Buffer;
|
||
|
}
|
||
|
|
||
|
HRESULT Start(BOOL Empty);
|
||
|
HRESULT End(BOOL RemoveLastNewLine);
|
||
|
|
||
|
ULONG GetLineCount(void)
|
||
|
{
|
||
|
return m_NewLineCount + m_PartialLine;
|
||
|
}
|
||
|
ULONG RecountLines(void)
|
||
|
{
|
||
|
m_NewLineCount = 0;
|
||
|
AddLines((PSTR)m_Buffer->GetDataBuffer() + m_DataStart);
|
||
|
return GetLineCount();
|
||
|
}
|
||
|
|
||
|
void ReplaceChar(char From, char To);
|
||
|
|
||
|
// IDebugOutputCallbacks.
|
||
|
STDMETHOD(Output)(
|
||
|
THIS_
|
||
|
IN ULONG Mask,
|
||
|
IN PCSTR Text
|
||
|
);
|
||
|
|
||
|
private:
|
||
|
void AddLines(PCSTR Start);
|
||
|
|
||
|
StateBuffer* m_Buffer;
|
||
|
ULONG m_DataStart;
|
||
|
HRESULT m_Status;
|
||
|
ULONG m_NewLineCount;
|
||
|
ULONG m_PartialLine;
|
||
|
};
|
||
|
|
||
|
extern OutputToStateBuffer g_OutStateBuf;
|
||
|
extern OutputToStateBuffer g_UiOutStateBuf;
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Dynamic state buffers.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
extern LIST_ENTRY g_StateList;
|
||
|
|
||
|
// Global lock for short operations where it doesn't matter
|
||
|
// if the threads block on each other briefly. This lock should
|
||
|
// not be held longer than a fraction of a second.
|
||
|
// Used for protecting:
|
||
|
// State buffer list.
|
||
|
// g_Event values.
|
||
|
extern DBG_CRITICAL_SECTION g_QuickLock;
|
||
|
|
||
|
#define LockStateBuffer(Buffer) Dbg_EnterCriticalSection(&(Buffer)->m_Lock)
|
||
|
#define UnlockStateBuffer(Buffer) Dbg_LeaveCriticalSection(&(Buffer)->m_Lock)
|
||
|
|
||
|
#define AssertStateBufferLocked(Buffer) \
|
||
|
Assert(Dbg_CriticalSectionOwned(&(Buffer)->m_Lock))
|
||
|
|
||
|
extern ULONG64 g_CodeIp;
|
||
|
// If g_CodeFileFound[0] == 0 no source file was found.
|
||
|
extern char g_CodeFileFound[];
|
||
|
// If g_CodeSymFile[0] == 0 no source symbol information was found.
|
||
|
extern char g_CodeSymFile[];
|
||
|
extern ULONG g_CodeLine;
|
||
|
extern BOOL g_CodeUserActivated;
|
||
|
extern ULONG g_CodeBufferSequence;
|
||
|
|
||
|
extern ULONG64 g_EventIp;
|
||
|
extern ULONG64 g_EventReturnAddr;
|
||
|
extern ULONG g_CurProcessId, g_CurProcessSysId;
|
||
|
extern ULONG g_CurThreadId, g_CurThreadSysId;
|
||
|
|
||
|
enum BpStateType
|
||
|
{
|
||
|
BP_ENABLED,
|
||
|
BP_DISABLED,
|
||
|
BP_NONE,
|
||
|
BP_UNKNOWN
|
||
|
};
|
||
|
|
||
|
struct BpBufferData
|
||
|
{
|
||
|
ULONG64 Offset;
|
||
|
ULONG Id;
|
||
|
ULONG Flags;
|
||
|
ULONG Thread;
|
||
|
ULONG Sequence;
|
||
|
ULONG FileOffset;
|
||
|
};
|
||
|
extern ULONG g_BpCount;
|
||
|
extern StateBuffer* g_BpBuffer;
|
||
|
extern ULONG g_BpTextOffset;
|
||
|
|
||
|
extern StateBuffer* g_BpCmdsBuffer;
|
||
|
|
||
|
extern StateBuffer* g_FilterTextBuffer;
|
||
|
|
||
|
extern StateBuffer* g_FilterBuffer;
|
||
|
extern ULONG g_FilterArgsOffset;
|
||
|
extern ULONG g_FilterCmdsOffset;
|
||
|
extern ULONG g_FilterWspCmdsOffset;
|
||
|
extern ULONG g_NumSpecEvents, g_NumSpecEx, g_NumArbEx;
|
||
|
|
||
|
extern StateBuffer* g_ModuleBuffer;
|
||
|
extern ULONG g_NumModules;
|
||
|
|
||
|
void FillCodeBuffer(ULONG64 Ip, BOOL UserActivated);
|
||
|
void FillEventBuffer(void);
|
||
|
|
||
|
void ReadStateBuffers(void);
|
||
|
|
||
|
#define BUFFERS_ALL 0xffffffff
|
||
|
|
||
|
void InvalidateStateBuffers(ULONG Types);
|
||
|
|
||
|
void UpdateBufferWindows(ULONG Types, UpdateType Type);
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Static state buffers.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
extern StateBuffer* g_RegisterNamesBuffer;
|
||
|
extern StateBuffer* g_WatchWinBuffer;
|
||
|
|
||
|
extern PUSHORT g_RegisterMap;
|
||
|
extern ULONG g_RegisterMapEntries;
|
||
|
|
||
|
#define MAP_REGISTER(i) \
|
||
|
(g_RegisterMap != NULL && (i) < g_RegisterMapEntries ? \
|
||
|
g_RegisterMap[(i)] : (i))
|
||
|
|
||
|
void GetRegisterMapText(HWND Edit);
|
||
|
void ScanRegisterMapText(HWND Edit);
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// UI thread state buffer.
|
||
|
//
|
||
|
// The UI thread has simple needs and so one state buffer for
|
||
|
// output capture is sufficient.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
extern StateBuffer g_UiOutputCapture;
|
||
|
|
||
|
#endif // #ifndef __STATEBUF_H__
|