зеркало из https://github.com/microsoft/msquic.git
Move WinDbg Extension to GitHub (#126)
This commit is contained in:
Родитель
882a941fa9
Коммит
51d021f092
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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
|
Двоичный файл не отображается.
|
@ -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();
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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");
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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");
|
||||
}
|
Загрузка…
Ссылка в новой задаче