Move WinDbg Extension to GitHub (#126)

This commit is contained in:
Nick Banks 2020-02-11 18:04:35 -08:00 коммит произвёл GitHub
Родитель 882a941fa9
Коммит 51d021f092
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 2686 добавлений и 0 удалений

116
src/tools/dbg/analyze.cpp Normal file
Просмотреть файл

@ -0,0 +1,116 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'analyze'. This command is for analyzing
possible issues on a QUIC handle.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicanalyze,
"Analyze issues of a handle",
"{;e,r;addr;The address of the handle}"
)
{
QuicHandle Handle(GetUnnamedArgU64(0));
auto Type = Handle.Type();
if (Type == QUIC_HANDLE_TYPE_CLIENT || Type == QUIC_HANDLE_TYPE_CHILD) {
AnalyzeConnection(Handle.Addr);
} else if (Type == QUIC_HANDLE_TYPE_STREAM) {
AnalyzeStream(Handle.Addr);
} else {
Dml("Not supported for handle type: %s", Handle.TypeStr());
}
Dml("\n");
}
void EXT_CLASS::AnalyzeConnection(UINT64 Addr)
{
Connection Conn(Addr);
QUIC_CONNECTION_STATE state = Conn.State();
if (state.Freed) {
Dml("The connection has been freed.\n");
} else if (state.HandleClosed) {
Dml("The connection has been closed by the application and is in the process of being deleted.\n");
} else if (state.HandleShutdown) {
Dml("The connection has completed the shutdown process and is ready to be closed by the application.\n");
} else if (state.ClosedLocally || state.ClosedRemotely) {
Dml("The connection is in the process of shutting down.");
if (state.ClosedLocally) {
Dml(" It has been closed locally.");
}
if (state.ClosedRemotely) {
Dml(" It has been closed remotely.");
}
Dml("\n");
} else if (state.Connected) {
Dml("The connection is connected.\n");
} else if (state.Started) {
Dml("The connection is in the process of performing the handshake.\n");
} else if (state.Initialized) {
Dml("The connection has been allocated and successfully initialized.\n");
} else if (state.Allocated) {
Dml("The connection has been allocated.\n");
} else {
Dml("The connection is invalid.\n");
}
//
// TODO ...
//
}
void EXT_CLASS::AnalyzeStream(UINT64 Addr)
{
Stream Strm(Addr);
QUIC_STREAM_FLAGS flags = Strm.Flags();
if (flags.Freed) {
Dml("The stream has been freed.\n");
} else if (flags.HandleClosed) {
Dml("The stream has been closed by the application.\n");
} else if (flags.HandleShutdown) {
Dml("The stream has completed the shutdown process and is ready to be closed by the application.\n");
} else {
auto LocallyClosed = flags.LocalCloseFin || flags.LocalCloseReset;
auto RemotelyClosed = flags.RemoteCloseFin || flags.RemoteCloseReset;
if (RemotelyClosed) {
if (flags.RemoteCloseAcked) {
Dml("The stream's receive pipe has been closed and acknowledged.\n");
} else {
Dml("The stream's receive pipe has been closed but not yet acknowledged.\n");
}
} else {
Dml("The stream's receive pipe is open.\n");
}
if (LocallyClosed) {
if (flags.LocalCloseAcked) {
Dml("The stream's send pipe has been closed and acknowledged.\n");
} else {
Dml("The stream's send pipe has been closed but not yet acknowledged.\n");
}
} else {
Dml("The stream's send pipe is open.\n");
}
}
UINT32 SendRequestsCount = 0;
ULONG64 SendRequestsPtr = Strm.SendRequests();
while (SendRequestsPtr != 0) {
SendRequest Request(SendRequestsPtr);
SendRequestsPtr = Request.Next();
SendRequestsCount++;
}
Dml("The stream has %u send requests pending.\n", SendRequestsCount);
}

92
src/tools/dbg/binding.cpp Normal file
Просмотреть файл

@ -0,0 +1,92 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'binding'. This command is for querying the
state of a single binding.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicbinding,
"Shows all information about a Binding",
"{;e,r;addr;The address of the Binding}"
)
{
Binding Binding(GetUnnamedArgU64(0));
auto Lookup = Binding.GetLookup();
auto DatapathBinding = Binding.GetDatapathBinding();
Dml("\n<b>BINDING</b> (<link cmd=\"dt msquic!QUIC_BINDING 0x%I64X\">raw</link>)\n"
"\n"
"\tExclusive %s\n"
"\tConnected %s\n"
"\tRefCount %u\n"
"\tCidCount %u\n"
"\tPartitionCount %u\n"
"\tLocalAddress %s\n"
"\tRemoteAddress %s\n"
"\n",
Binding.Addr,
Binding.Exclusive() ? "true" : "false",
Binding.Connected() ? "true" : "false",
Binding.RefCount(),
Lookup.CidCount(),
Lookup.PartitionCount(),
DatapathBinding.GetLocalAddress().IpString,
DatapathBinding.GetRemoteAddress().IpString);
bool HasAtLeastOne = false;
auto Listeners = Binding.GetListeners();
while (!CheckControlC()) {
ULONG64 LinkAddr = Listeners.Next();
if (LinkAddr == 0) {
break;
}
ULONG64 ListenerAddr = LinkEntryToType(LinkAddr, "msquic!QUIC_LISTENER", "Link");
Dml("\t<link cmd=\"!quiclistener 0x%I64X\">Listener 0x%I64X</link>\n",
ListenerAddr,
ListenerAddr);
HasAtLeastOne = true;
}
if (!HasAtLeastOne) {
Dml("\tNo Listeners\n");
}
Dml("\n");
UCHAR PartitionCount = Lookup.PartitionCount();
if (PartitionCount == 0) {
Connection Conn(Lookup.GetLookupPtr());
Dml("\t<link cmd=\"!quicconnection 0x%I64X\">Connection 0x%I64X</link> [%s]\n",
Conn.Addr,
Conn.Addr,
Conn.TypeStr());
} else {
for (UCHAR i = 0; i < PartitionCount; i++) {
HashTable Hash(Lookup.GetLookupTable(i).GetTablePtr());
Dml("\t<link cmd=\"!hashtable 0x%I64X\">Hash Table %d</link> (%u entries)\n",
Hash.Addr,
i,
Hash.NumEntries());
ULONG64 EntryPtr;
while (!CheckControlC() && Hash.GetNextEntry(&EntryPtr)) {
CidHashEntry Entry(EntryPtr);
Connection Conn(Entry.GetConnection());
Dml("\t <link cmd=\"!quicconnection 0x%I64X\">Connection 0x%I64X</link> [%s]\n",
Conn.Addr,
Conn.Addr,
Conn.TypeStr());
}
}
}
Dml("\n");
}

Просмотреть файл

@ -0,0 +1,220 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'connection'. This command handles state
specific to a single QUIC Connection.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicconnection,
"Shows all information about a Connection",
"{;e,r;addr;The address of the Connection handle}"
)
{
Connection Conn(GetUnnamedArgU64(0));
Dml("\n<b>CONNECTION</b> (<link cmd=\"!quicanalyze 0x%I64X\">analyze</link>) (<link cmd=\"dt msquic!QUIC_CONNECTION 0x%I64X\">raw</link>)\n"
"\n"
"\tLocal Address %s\n"
"\tRemote Address %s\n"
"\tVersion 0x%X\n"
"\tRef Count %d\n",
Conn.Addr,
Conn.Addr,
Conn.GetLocalAddress().IpString,
Conn.GetRemoteAddress().IpString,
Conn.Version(),
Conn.RefCount());
//
// TODO - Enumerate Source and Destination Connection IDs.
//
auto Send = Conn.GetSend();
Dml("\n"
"\tType %s\n"
"\tState %s\n"
"\tSendPktNum %I64u\n",
Conn.TypeStr(),
Conn.StateStr(),
Send.NextPacketNumber());
//
// Streams
//
Dml("\n<u>STREAMS</u>\n"
"\n");
bool HasAtLeastOneStream = false;
ULONG64 HashPtr = Conn.GetStreams().GetStreamTable();
if (HashPtr != 0) {
HashTable Streams(HashPtr);
ULONG64 EntryPtr;
while (!CheckControlC() && Streams.GetNextEntry(&EntryPtr)) {
auto Strm = Stream::FromHashTableEntry(EntryPtr);
Dml("\t<link cmd=\"!quicstream 0x%I64X\">Stream %I64u</link>\n",
Strm.Addr,
Strm.ID());
HasAtLeastOneStream = true;
}
}
if (!HasAtLeastOneStream) {
Dml("\tNo Open Streams\n");
}
//
// Operations
//
Dml("\n<u>OPERATIONS</u>\n"
"\n");
bool HasAtLeastOneOperation = false;
auto Operations = Conn.GetOperQueue().GetOperations();
while (!CheckControlC()) {
auto OperLinkAddr = Operations.Next();
if (OperLinkAddr == 0) {
break;
}
auto Operation = Operation::FromLink(OperLinkAddr);
Dml("\t%s\n", Operation.TypeStr());
HasAtLeastOneOperation = true;
}
if (!HasAtLeastOneOperation) {
Dml("\tNo Operations Queued\n");
}
//
// Send State
//
Dml("\n<u>SEND STATE</u>\n"
"\n"
"\tSend Flags ");
auto SendFlags = Send.SendFlags();
if (SendFlags == 0) {
Dml("NONE");
} else {
if (SendFlags & QUIC_CONN_SEND_FLAG_ACK) {
Dml("ACK\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_CRYPTO) {
Dml("CRYPTO\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_CONNECTION_CLOSE) {
Dml("CONNECTION_CLOSE\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_APPLICATION_CLOSE) {
Dml("APPLICATION_CLOSE\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_DATA_BLOCKED) {
Dml("DATA_BLOCKED\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_MAX_DATA) {
Dml("MAX_DATA\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_MAX_STREAMS_BIDI) {
Dml("MAX_STREAMS_BIDI\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_MAX_STREAMS_UNI) {
Dml("MAX_STREAMS_UNI\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_NEW_CONNECTION_ID) {
Dml("NEW_CONNECTION_ID\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_PING) {
Dml("PING\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_PATH_CHALLENGE) {
Dml("PATH_CHALLENGE\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_PATH_RESPONSE) {
Dml("PATH_RESPONSE\n"
"\t ");
}
if (SendFlags & QUIC_CONN_SEND_FLAG_PMTUD) {
Dml("PMTUD\n"
"\t ");
}
}
Dml("\n"
"\tQueued Streams ");
HasAtLeastOneStream = false;
auto SendStreams = Send.GetSendStreams();
while (!CheckControlC()) {
auto StreamSendLinkAddr = SendStreams.Next();
if (StreamSendLinkAddr == 0) {
break;
}
auto Strm = Stream::FromSendLink(StreamSendLinkAddr);
Dml("<link cmd=\"!quicstream 0x%I64X\">Stream %I64u</link>\n"
"\t ",
Strm.Addr,
Strm.ID());
HasAtLeastOneStream = true;
}
if (!HasAtLeastOneStream) {
Dml("NONE\n");
} else {
Dml("\n");
}
Dml("\tOutstanding Packets ");
auto Loss = Conn.GetLossDetection();
auto SendPackets = Loss.GetSendPackets();
if (SendPackets == 0) {
Dml("NONE\n");
} else {
while (SendPackets && !CheckControlC()) {
auto Packet = SentPacketMetadata(SendPackets);
Dml("<link cmd=\"!quicpacket 0x%I64X\">%I64u</link>\n"
"\t ",
Packet.Addr,
Packet.PacketNumber());
SendPackets = Packet.Next();
}
Dml("\n");
}
Dml("\n");
}
EXT_COMMAND(
quicconn,
"Shows all information about a Connection",
"{;e,r;addr;The address of the Connection handle}"
)
{
EXT_CLASS::quicconnection();
}

68
src/tools/dbg/dump.cpp Normal file
Просмотреть файл

@ -0,0 +1,68 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'dump'. This command is for dumping most all
the current objects.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicdump,
"Dumps all MsQuic objects",
""
)
{
QuicLibrary Lib;
Dml("\n<b>DUMP</b>\n");
auto Registrations = Lib.GetRegistrations();
while (!CheckControlC()) {
ULONG64 RegAddr = Registrations.Next();
if (RegAddr == 0) {
break;
}
auto Registration = Registration::FromLink(RegAddr);
Dml("\n<link cmd=\"!quicregistration 0x%I64X\">Reg 0x%I64X</link> \"%s\"\n",
Registration.Addr,
Registration.Addr,
Registration.GetAppName().Data);
auto Sessions = Registration.GetSessions();
while (!CheckControlC()) {
ULONG64 SessAddr = Sessions.Next();
if (SessAddr == 0) {
break;
}
auto Session = Session::FromLink(SessAddr);
Dml(" <link cmd=\"!quicsession 0x%I64X\">Sess 0x%I64X</link> \"%s\"\n",
Session.Addr,
Session.Addr,
Session.GetAlpn().Data);
auto Connections = Session.GetConnections();
while (!CheckControlC()) {
ULONG64 ConnAddr = Connections.Next();
if (ConnAddr == 0) {
break;
}
auto Connection = Connection::FromSessionLink(ConnAddr);
Dml(" <link cmd=\"!quicconnection 0x%I64X\">Conn 0x%I64X</link> %s\n",
Connection.Addr,
Connection.Addr,
Connection.TypeStr());
}
}
}
Dml("\n");
}

32
src/tools/dbg/handle.cpp Normal file
Просмотреть файл

@ -0,0 +1,32 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'handle'. This command is for querying the
type of a handle.
--*/
#include "quictypes.h"
EXT_COMMAND(
quichandle,
"Shows the type of a handle",
"{;e,r;addr;The address of the handle}"
)
{
QuicHandle Handle(GetUnnamedArgU64(0));
Dml("\n<b>HANDLE</b> (<link cmd=\"dt msquic!QUIC_HANDLE 0x%I64X\">raw</link>)\n"
"\n"
"\tType <link cmd=\"!quic%s 0x%I64X\">%s</link>\n",
Handle.Addr,
Handle.CommandStr(),
Handle.Addr,
Handle.TypeStr());
Dml("\n");
}

85
src/tools/dbg/library.cpp Normal file
Просмотреть файл

@ -0,0 +1,85 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'library'. This command is for querying the
state of the library.
--*/
#include "quictypes.h"
EXT_COMMAND(
quiclibrary,
"Shows the state of the MsQuic library",
""
)
{
QuicLibrary Lib;
Dml("\n<b>LIBRARY</b> (<link cmd=\"dt msquic!QUIC_LIBRARY 0x%I64X\">raw</link>)\n"
"\n"
"\tRefCount %u\n"
"\n",
Lib.Addr,
Lib.RefCount());
Dml("\n<u>REGISTRATIONS</u>\n"
"\n");
bool HasAtLeastOne = false;
auto Registrations = Lib.GetRegistrations();
while (!CheckControlC()) {
ULONG64 LinkAddr = Registrations.Next();
if (LinkAddr == 0) {
break;
}
Registration Registration = Registration::FromLink(LinkAddr);
Dml("\t<link cmd=\"!quicregistration 0x%I64X\">0x%I64X</link>\t\"%s\"\n",
Registration.Addr,
Registration.Addr,
Registration.GetAppName().Data);
HasAtLeastOne = true;
}
if (!HasAtLeastOne) {
Dml("\tNone\n");
}
Dml("\n<u>BINDINGS</u>\n"
"\n");
HasAtLeastOne = false;
auto Bindings = Lib.GetBindings();
while (!CheckControlC()) {
ULONG64 LinkAddr = Bindings.Next();
if (LinkAddr == 0) {
break;
}
auto Binding = Binding::FromLink(LinkAddr);
Dml("\t<link cmd=\"!quicbinding 0x%I64X\">0x%I64X</link>\n",
Binding.Addr,
Binding.Addr);
HasAtLeastOne = true;
}
if (!HasAtLeastOne) {
Dml("\tNone\n");
}
Dml("\n");
}
EXT_COMMAND(
quiclib,
"Shows the state of the MsQuic library",
""
)
{
EXT_CLASS::quiclibrary();
}

Просмотреть файл

@ -0,0 +1,38 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'listener'. This command handles state
specific to a single QUIC Listener.
--*/
#include "quictypes.h"
EXT_COMMAND(
quiclistener,
"Shows all information about a Listener",
"{;e,r;addr;The address of the Listener}"
)
{
Listener Listener(GetUnnamedArgU64(0));
Session Session(Listener.GetSession());
Dml("\n<b>LISTENER</b> (<link cmd=\"dt msquic!QUIC_LISTENER 0x%I64X\">raw</link>)\n"
"\n"
"\tWildCard %s\n"
"\tSession <link cmd=\"!quicsession 0x%I64X\">0x%I64X</link>\t\"%s\"\n"
"\tBinding <link cmd=\"!quicbinding 0x%I64X\">0x%I64X</link>\n"
"\tLocalAddress %s\n\n",
Listener.Addr,
Listener.WildCard() ? "true" : "false",
Session.Addr,
Session.Addr,
Session.GetAlpn().Data,
Listener.GetBinding(),
Listener.GetBinding(),
Listener.GetLocalAddress().IpString);
}

65
src/tools/dbg/packet.cpp Normal file
Просмотреть файл

@ -0,0 +1,65 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'packet'. This command displays the state
for a single send packet.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicpacket,
"Shows all information about a send packet",
"{;e,r;addr;The address of the sent packet}"
)
{
SentPacketMetadata Packet(GetUnnamedArgU64(0));
auto Flags = Packet.Flags();
Dml("\n<b>PACKET</b> (<link cmd=\"dt msquic!QUIC_SENT_PACKET_METADATA 0x%I64X\">raw</link>)\n"
"\n"
"\tKey Type %s\n"
"\tPacket Number %I64u\n"
"\tSent Time (us) %u\n"
"\tLength %hu\n"
"\tFlags ",
Packet.Addr,
Flags.KeyTypeStr(),
Packet.PacketNumber(),
Packet.SentTime(),
Packet.PacketLength());
if (Flags.IsRetransmittable) {
Dml("Retransmittable\n"
"\t ");
}
if (Flags.HasCrypto) {
Dml("Crypto Frames\n"
"\t ");
}
if (Flags.IsPMTUD) {
Dml("PMTUD\n"
"\t ");
}
//
// Frames
//
Dml("\n<u>Frames</u>\n"
"\n");
for (UINT32 i = 0; i < Packet.FrameCount(); i++) {
auto Frame = Packet.GetFrame(i);
Dml("\t<link cmd=\"dt msquic!QUIC_SENT_FRAME_METADATA 0x%I64X\">0x%I64X</link>\t%s\n",
Frame.Addr, Frame.Addr, Frame.TypeStr());
}
Dml("\n");
}

29
src/tools/dbg/quic.def Normal file
Просмотреть файл

@ -0,0 +1,29 @@
EXPORTS
;--------------------------------------------------------------------
; Core exports provided by the ExtCpp framework.
;--------------------------------------------------------------------
DebugExtensionInitialize
DebugExtensionUninitialize
DebugExtensionNotify
help
;--------------------------------------------------------------------
; Extension commands.
;--------------------------------------------------------------------
quicanalyze
quicbinding
quicconn
quicconnection
quicdump
quichandle
quiclib
quiclibrary
quiclistener
quicpacket
quicregistration
quicsession
quicstream
quicworker

Двоичные данные
src/tools/dbg/quic_GalleryManifest.xml Normal file

Двоичный файл не отображается.

20
src/tools/dbg/quicdbg.cpp Normal file
Просмотреть файл

@ -0,0 +1,20 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension
--*/
#include "quicdbg.h"
ULONG g_ulDebug = DEBUG_LEVEL_QUIET;
//
// EXT_DECLARE_GLOBALS must be used to instantiate
// the framework's assumed globals.
//
EXT_DECLARE_GLOBALS();

299
src/tools/dbg/quicdbg.h Normal file
Просмотреть файл

@ -0,0 +1,299 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Declarations and Helpers.
DML Output Documentation available at:
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/customizing-debugger-output-using-dml
--*/
#pragma once
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <engextcpp.hpp>
#include <ws2def.h>
#include <ws2ipdef.h>
#include <ip2string.h>
#include <stdio.h>
extern ULONG g_ulDebug;
#define DEBUG_LEVEL_ERROR 0
#define DEBUG_LEVEL_QUIET 1
#define DEBUG_LEVLE_INFO 2
#define DEBUG_LEVEL_TRACE 3
#define DEBUG_LEVEL_VERBOSE 4
#define DEBUG_LEVEL_LOUD 5
#define dpError(format, ...) \
if (g_ulDebug >= DEBUG_LEVEL_ERROR) dprintf(format, ##__VA_ARGS__)
//
// Base extension class.
// Extensions derive from the provided ExtExtension class.
//
// The standard class name is "Extension". It can be overridden by providing
// an alternate definition of EXT_CLASS before including engextcpp.hpp.
//
// More documentation in minkernel/debuggers/published/engextcpp.w
//
//
class EXT_CLASS : public ExtExtension {
public:
EXT_COMMAND_METHOD(quicanalyze);
EXT_COMMAND_METHOD(quicbinding);
EXT_COMMAND_METHOD(quicconn);
EXT_COMMAND_METHOD(quicconnection);
EXT_COMMAND_METHOD(quicdump);
EXT_COMMAND_METHOD(quichandle);
EXT_COMMAND_METHOD(quiclib);
EXT_COMMAND_METHOD(quiclibrary);
EXT_COMMAND_METHOD(quiclistener);
EXT_COMMAND_METHOD(quicpacket);
EXT_COMMAND_METHOD(quicregistration);
EXT_COMMAND_METHOD(quicsession);
EXT_COMMAND_METHOD(quicstream);
EXT_COMMAND_METHOD(quicworker);
//
// Called by a command when symbols don't seem to be resolving.
//
void
OnSymbolsError(
)
{
m_Control->ControlledOutput(
DEBUG_OUTCTL_AMBIENT_DML,
DEBUG_OUTPUT_NORMAL,
"<b><col fg=\"ebpbg\">"
"Can't resolve msquic symbols."
"</col></b>\n");
}
void AnalyzeConnection(UINT64 Addr);
void AnalyzeStream(UINT64 Addr);
};
extern EXT_CLASS g_ExtInstance;
inline
bool
IsEqualPointer(
_In_ ULONG64 Address1,
_In_ ULONG64 Address2
)
{
if (g_ExtInstance.m_PtrSize == 8) {
return (Address1 == Address2);
} else { // g_ExtInstance.m_PtrSize == 4
return ((Address1 & 0xFFFFFFFF) == (Address2 & 0xFFFFFFFF));
}
}
//
// Reads a non-pointer type at the given address.
//
template<typename T>
bool
ReadTypeAtAddr(
_In_ ULONG64 Addr,
_Out_ T* Value
)
{
ULONG cbRead;
if (!ReadMemory(Addr, Value, sizeof(T), &cbRead)) {
dpError("Error reading at %p\n", Addr);
return false;
}
return true;
}
//
// Reads a pointer at the given address. The size of the pointer is
// determined by the current target.
//
inline
bool
ReadPointerAtAddr(
_In_ ULONG64 Addr,
_Out_ ULONG64* Value
)
{
ULONG cbRead;
if (!ReadMemory(Addr, Value, g_ExtInstance.m_PtrSize, &cbRead)) {
dpError("Error reading at %p\n", Addr);
return false;
}
return true;
}
//
// Reads a null-terminated string at the given address.
//
inline
size_t
ReadStringAtAddr(
_In_ ULONG64 Addr,
_In_ size_t MaxLength,
_Out_writes_bytes_(MaxLength)
char Value[256]
)
{
ULONG cbRead;
size_t offset = 0;
while (offset + 1 < MaxLength && !CheckControlC()) {
if (!ReadMemory(Addr + offset, Value + offset, sizeof(char), &cbRead) ||
Value[offset] == 0) {
break;
}
offset++;
}
Value[offset] = 0;
return offset;
}
//
// Reads a non-pointer type from a struct at the given address.
//
template<typename T>
bool
ReadTypeFromStructAddr(
_In_ ULONG64 StructAddr,
_In_ PSTR StructType,
_In_ PSTR FieldName,
_Out_ T* Value
)
{
ULONG FieldOffset;
if (0 != GetFieldOffset(StructType, FieldName, &FieldOffset)){
dpError("GetFieldOffset failed struct=%s field=%s\n", StructType, FieldName);
return false;
}
return ReadTypeAtAddr(StructAddr + FieldOffset, Value);
}
//
// Reads a pointer type from a struct at the given address. The size of
// the pointer is determined by the current target.
//
inline
bool
ReadPointerFromStructAddr(
_In_ ULONG64 StructAddr,
_In_ PSTR StructType,
_In_ PSTR FieldName,
_Out_ ULONG64* Value
)
{
ULONG FieldOffset;
if (0 != GetFieldOffset(StructType, FieldName, &FieldOffset)){
dpError("GetFieldOffset failed struct=%s field=%s\n", StructType, FieldName);
return false;
}
return ReadPointerAtAddr(StructAddr + FieldOffset, Value);
}
//
// Helper for reading many fields from a single struct.
//
struct Struct {
PSTR Type;
ULONG64 Addr;
Struct(PSTR type, ULONG64 addr) : Type(type), Addr(addr) { }
ULONG
OffsetOf(
_In_ PSTR FieldName
)
{
ULONG FieldOffset;
if (0 != GetFieldOffset(Type, FieldName, &FieldOffset)){
dpError("GetFieldOffset failed struct=%s field=%s\n", Type, FieldName);
}
return FieldOffset;
}
ULONG64
AddrOf(
_In_ PSTR FieldName
)
{
ULONG FieldOffset;
if (0 != GetFieldOffset(Type, FieldName, &FieldOffset)){
dpError("GetFieldOffset failed struct=%s field=%s\n", Type, FieldName);
}
return Addr + FieldOffset;
}
template<typename T>
T
ReadType(
_In_ PSTR FieldName
)
{
T Value;
ReadTypeFromStructAddr(Addr, Type, FieldName, &Value);
return Value;
}
template<typename T>
T
ReadTypeAtOffset(
_In_ ULONG Offset
)
{
T Value;
ReadTypeAtAddr(Addr + Offset, &Value);
return Value;
}
ULONG64
ReadPointer(
_In_ PSTR FieldName
)
{
ULONG64 Value;
ReadPointerFromStructAddr(Addr, Type, FieldName, &Value);
return Value;
}
ULONG64
ReadPointerAtOffset(
_In_ ULONG Offset
)
{
ULONG64 Value;
ReadPointerAtAddr(Addr + Offset, &Value);
return Value;
}
};
struct String {
ULONG64 Addr;
char Data[256];
String(ULONG64 Addr) : Addr(Addr) {
ReadStringAtAddr(Addr, sizeof(Data), Data);
}
};
struct IpAddress {
SOCKADDR_INET Raw;
char IpString[256];
IpAddress(ULONG64 Addr) {
ReadTypeAtAddr(Addr, &Raw);
ULONG StringLen = sizeof(String);
if (Raw.si_family == AF_UNSPEC) {
sprintf(IpString, "UNSPEC:%u", RtlUshortByteSwap(Raw.Ipv4.sin_port));
} else if (Raw.si_family == AF_INET) {
RtlIpv4AddressToStringExA(&Raw.Ipv4.sin_addr, Raw.Ipv4.sin_port, IpString, &StringLen);
} else {
RtlIpv6AddressToStringExA(&Raw.Ipv6.sin6_addr, 0, Raw.Ipv6.sin6_port, IpString, &StringLen);
}
}
};

1293
src/tools/dbg/quictypes.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

16
src/tools/dbg/readme.md Normal file
Просмотреть файл

@ -0,0 +1,16 @@
quic.dll
========================
WinDbg debugger extension for the MsQuic library.
Publishing Instructions
------------------------
- Increment the version number in GalleryManifest.xml.
- Create a folder with name equal to the version number.
- Copy GalleryManifest.xml into the folder.
- To the version folder, add subfolders for x86 and amd64.
- Copy the corresponding versions of quic.dll in each of those subfolders.
- Zip it all up.
- Share it out.
- Send mail to dex-triage@microsoft.com with the path to the shared folder.

Просмотреть файл

@ -0,0 +1,60 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'registration'. This command is for querying the
state of a single registration.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicregistration,
"Shows all information about a Registration",
"{;e,r;addr;The address of the Registration}"
)
{
Registration Registration(GetUnnamedArgU64(0));
Dml("\n<b>REGISTRATION</b> (<link cmd=\"dt msquic!QUIC_REGISTRATION 0x%I64X\">raw</link>)\n"
"\n"
"\tAppName %s\n"
"\n",
Registration.Addr,
Registration.GetAppName().Data);
Dml("\n<u>SESSIONS</u>\n"
"\n");
auto Sessions = Registration.GetSessions();
while (!CheckControlC()) {
ULONG64 LinkAddr = Sessions.Next();
if (LinkAddr == 0) {
break;
}
auto Session = Session::FromLink(LinkAddr);
Dml("\t<link cmd=\"!quicsession 0x%I64X\">0x%I64X</link>\t\"%s\"\n",
Session.Addr,
Session.Addr,
Session.GetAlpn().Data);
}
Dml("\n<u>WORKERS</u>\n"
"\n");
auto Workers = Registration.GetWorkerPool();
UCHAR WorkerCount = Workers.WorkerCount();
for (UCHAR i = 0; i < WorkerCount; i++) {
Dml("\t<link cmd=\"!quicworker 0x%I64X\">Proc %d</link>\t%s\n",
Workers.GetWorker(i).Addr,
Workers.GetWorker(i).IdealProcessor(),
Workers.GetWorker(i).StateStr());
}
Dml("\n");
}

55
src/tools/dbg/session.cpp Normal file
Просмотреть файл

@ -0,0 +1,55 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'session'. This command handles state
specific to a single QUIC Session.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicsession,
"Shows all information about a Session",
"{;e,r;addr;The address of the Session}"
)
{
Session Session(GetUnnamedArgU64(0));
Dml("\n<b>SESSION</b> (<link cmd=\"dt msquic!QUIC_SESSION 0x%I64X\">raw</link>)\n"
"\n"
"\tALPN %s\n"
"\tRegistration <link cmd=\"!quicregistration 0x%I64X\">0x%I64X</link>\n",
Session.Addr,
Session.GetAlpn().Data,
Session.GetRegistration(),
Session.GetRegistration());
Dml("\n<u>CONNECTIONS</u>\n"
"\n");
bool HasAtLeastOne = false;
auto Connections = Session.GetConnections();
while (true) {
ULONG64 LinkAddr = Connections.Next();
if (LinkAddr == 0) {
break;
}
auto Connection = Connection::FromSessionLink(LinkAddr);
Dml("\t<link cmd=\"!quicconnection 0x%I64X\">0x%I64X</link>\n",
Connection.Addr,
Connection.Addr);
HasAtLeastOne = true;
}
if (!HasAtLeastOne) {
Dml("\tNone\n");
}
Dml("\n");
}

139
src/tools/dbg/stream.cpp Normal file
Просмотреть файл

@ -0,0 +1,139 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'stream'. This command handles state
specific to a single QUIC Stream.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicstream,
"Shows all information about a Stream",
"{;e,r;addr;The address of the Stream handle}"
)
{
Stream Strm(GetUnnamedArgU64(0));
Dml("\n<b>STREAM</b> (<link cmd=\"!quicanalyze 0x%I64X\">analyze</link>) (<link cmd=\"dt msquic!QUIC_STREAM 0x%I64X\">raw</link>)\n"
"\n"
"\tID %I64u\n"
"\tState %s\n"
"\tConnection <link cmd=\"!quicconnection 0x%I64X\">0x%I64X</link>\n"
"\tRef Count %d\n",
Strm.Addr,
Strm.Addr,
Strm.ID(),
Strm.StateStr(),
Strm.GetConnection(),
Strm.GetConnection(),
Strm.RefCount());
//
// Send State
//
Dml("\n<u>SEND STATE</u>\n"
"\n"
"\tState %s\n"
"\tMax Offset (FC) %I64u\n"
"\tQueue Length %I64u\n"
"\tBytes Sent %I64u\n"
"\tNext Send Offset %I64u\n"
"\tBytes Acked (UNA) %I64u\n"
"\n"
"\tIn Recovery %s\n"
"\tRecov Window Open %s\n"
"\tRecov Next %I64u\n"
"\tRecov End %I64u\n",
Strm.SendStateStr(),
Strm.MaxAllowedSendOffset(),
Strm.QueuedSendOffset(),
Strm.MaxSentLength(),
Strm.NextSendOffset(),
Strm.UnAckedOffset(),
Strm.InRecovery() ? "YES" : "NO",
Strm.RecoveryWindowOpen() ? "YES" : "NO",
Strm.RecoveryNextOffset(),
Strm.RecoveryEndOffset());
Dml("\n"
"\tQueued For Send %s\n"
"\tSend Flags ",
Strm.SendLink().Flink() == NULL ? "NO" : "YES");
auto SendFlags = Strm.SendFlags();
if (SendFlags == 0) {
Dml("NONE\n");
} else {
if (SendFlags & QUIC_STREAM_SEND_FLAG_DATA_BLOCKED) {
Dml("DATA_BLOCKED\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_DATA) {
Dml("DATA\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_SEND_ABORT) {
Dml("SEND_ABORT\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_RECV_ABORT) {
Dml("RECV_ABORT\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_MAX_DATA) {
Dml("MAX_DATA\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_OPEN) {
Dml("OPEN\n"
"\t ");
}
if (SendFlags & QUIC_STREAM_SEND_FLAG_FIN) {
Dml("FIN\n"
"\t ");
}
}
Dml("\n<u>SEND REQUESTS</u>\n"
"\n");
ULONG64 SendRequestsPtr = Strm.SendRequests();
while (SendRequestsPtr != 0 && !CheckControlC()) {
SendRequest Request(SendRequestsPtr);
Dml("\t<link cmd=\"dt msquic!QUIC_SEND_REQUEST 0x%I64X\">0x%I64X</link> Length:%I64u\n",
SendRequestsPtr,
SendRequestsPtr,
Request.TotalLength());
SendRequestsPtr = Request.Next();
}
//
// Receive State
//
RecvBuffer RecvBuf = Strm.GetRecvBuffer();
Dml("\n<u>RECEIVE STATE</u>\n"
"\n"
"\tState %s\n"
"\tMax Offset (FC) %I64u\n"
"\t0-RTT Length %I64u\n"
"\n"
"\tRecv Win Size %I64u (Alloc %I64u)\n"
"\tRecv Win Start %I64u\n",
Strm.RecvStateStr(),
Strm.MaxAllowedRecvOffset(),
Strm.RecvMax0RttLength(),
RecvBuf.VirtualBufferLength(),
RecvBuf.AllocBufferLength(),
RecvBuf.BaseOffset());
Dml("\n");
}

59
src/tools/dbg/worker.cpp Normal file
Просмотреть файл

@ -0,0 +1,59 @@
/*++
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
Abstract:
QUIC Debugger Extension Command 'worker'. This command handles state
specific to a single QUIC Worker.
--*/
#include "quictypes.h"
EXT_COMMAND(
quicworker,
"Shows all information about a Worker",
"{;e,r;addr;The address of the Worker}"
)
{
Worker Work(GetUnnamedArgU64(0));
Dml("\n<b>WORKER</b> (<link cmd=\"dt msquic!QUIC_WORKER 0x%I64X\">raw</link>)\n"
"\n"
"\tState %s\n"
"\tIdeal Processor %u\n"
"\tThread 0x%X (<link cmd=\"~~[0x%X]s\">UM</link>/<link cmd=\"!thread 0x%I64X\">KM</link>)\n",
Work.Addr,
Work.StateStr(),
Work.IdealProcessor(),
Work.ThreadID(),
Work.ThreadID(),
Work.Thread());
Dml("\n<u>QUEUE</u>\n"
"\n");
bool HasAtLeastOne = false;
LinkedList ProcessConnections = Work.GetConnections();
while (true) {
ULONG64 LinkAddr = ProcessConnections.Next();
if (LinkAddr == 0) {
break;
}
Connection Conn = Connection::FromWorkerLink(LinkAddr);
Dml("\t<link cmd=\"!quicconnection 0x%I64X\">Connection 0x%I64X [%s]</link>\n",
Conn.Addr,
Conn.Addr,
Conn.TypeStr());
HasAtLeastOne = true;
}
if (!HasAtLeastOne) {
Dml("\tNo Connections\n");
}
Dml("\n");
}