00001 00007 #include "stdafx.h" 00008 #include "PacketLog.h" 00009 #include <bzscmn/bzscmn.h> 00010 00011 static const char szHTMLPreambleFormat[] = "<html><head><title>KDVMWare Packet Log - %S</title>\r\n\ 00012 <style>table {font-family: Courier New} tr.recv {color: red; } tr.send {color: green; }</style>\r\n\ 00013 </head>\r\n<body><center><h1>KDVMWare Packet Log - %S</h1></center>\r\n"; 00014 00015 static const char szLegend[] = "Legend: <b><font color = red>Debugger-to-kernel packets are in red</font>; <font color = green>Kernel-to-debugger packets are in green</font></b><br/>\r\n"; 00016 static const char szTableHeader[] = "<table border><tr><td>#</td><td>Time</td><td>Type</td><td>Data</td></tr>"; 00017 00018 static const char szTerminationSimulationNotification[] = "</table><br/><center><font color = \"blue\"><b>----- Simulating session termination -----</b></font></center><br/>"; 00019 static const char szTerminationSimulationEndFmt[] = "</table><br/><center><font color = \"blue\"><b>----- Session termination simulated: %s -----</b></font></center><br/>"; 00020 00021 static const char szHTMLFooter[] = "\r\n</table></body></html>"; 00022 00023 PacketLogger::PacketLogger( const TCHAR *pszKdPipeName ) 00024 : m_LogFilePath(_T("")) 00025 , m_SendPacketNumber(0) 00026 , m_RecvPacketNumber(0) 00027 , m_bTableHeaderPrinted(false) 00028 { 00029 if (!pszKdPipeName) 00030 return; 00031 const TCHAR *p = _tcsrchr(pszKdPipeName, '\\'); 00032 if (!p) 00033 return; 00034 00035 TCHAR tsz[MAX_PATH]; 00036 #ifdef _USRDLL 00037 extern HMODULE g_hThisDll; 00038 GetModuleFileName(g_hThisDll, tsz, sizeof(tsz)/sizeof(tsz[0])); 00039 #else 00040 GetModuleFileName(GetModuleHandle(NULL), tsz, sizeof(tsz)/sizeof(tsz[0])); 00041 #endif 00042 00043 TCHAR *p2 = _tcsrchr(tsz, '\\'); 00044 if (p2) 00045 p2[0] = 0; 00046 00047 m_LogFilePath = tsz; 00048 m_LogFilePath.AppendPath(p + 1); 00049 00050 if (!memcmp(p + 1, L"kd_", 3 * sizeof(TCHAR))) 00051 p += 3; 00052 00053 m_SessionName = (p + 1); 00054 00055 m_LogFilePath.append(_T(".html")); 00056 } 00057 00058 #pragma region Helpers for displaying various constants from windbgkd.h 00059 static const char *GetPacketTypeName(int PacketType) 00060 { 00061 switch(PacketType) 00062 { 00063 case 1: 00064 return " KD_STATE_CHANGE32"; 00065 case 2: 00066 return " KD_STATE_MANIPULATE"; 00067 case 3: 00068 return " KD_DEBUG_IO"; 00069 case 4: 00070 return " KD_ACKNOWLEDGE"; 00071 case 5: 00072 return " KD_RESEND"; 00073 case 6: 00074 return " KD_RESET"; 00075 case 7: 00076 return " KD_STATE_CHANGE64"; 00077 case 8: 00078 return " KD_POLL_BREAKIN"; 00079 case 9: 00080 return " KD_TRACE_IO"; 00081 case 10: 00082 return " KD_CONTROL_REQUEST"; 00083 case 11: 00084 return " KD_FILE_IO"; 00085 default: 00086 return ""; 00087 } 00088 } 00089 00090 static const char *GetApiTypeName(int ApiType) 00091 { 00092 switch (ApiType) 00093 { 00094 case 0x00003030: 00095 return "DbgKdExceptionStateChange"; 00096 case 0x00003031: 00097 return "DbgKdLoadSymbolsStateChange"; 00098 case 0x00003032: 00099 return "DbgKdCommandStringStateChange"; 00100 case 0x00003033: 00101 return "DbgKdMaximumStateChange"; 00102 case 0x00003130: 00103 return "DbgKdReadVirtualMemoryApi"; 00104 case 0x00003131: 00105 return "DbgKdWriteVirtualMemoryApi"; 00106 case 0x00003132: 00107 return "DbgKdGetContextApi"; 00108 case 0x00003133: 00109 return "DbgKdSetContextApi"; 00110 case 0x00003134: 00111 return "DbgKdWriteBreakPointApi"; 00112 case 0x00003135: 00113 return "DbgKdRestoreBreakPointApi"; 00114 case 0x00003136: 00115 return "DbgKdContinueApi"; 00116 case 0x00003137: 00117 return "DbgKdReadControlSpaceApi"; 00118 case 0x00003138: 00119 return "DbgKdWriteControlSpaceApi"; 00120 case 0x00003139: 00121 return "DbgKdReadIoSpaceApi"; 00122 case 0x0000313A: 00123 return "DbgKdWriteIoSpaceApi"; 00124 case 0x0000313B: 00125 return "DbgKdRebootApi"; 00126 case 0x0000313C: 00127 return "DbgKdContinueApi2"; 00128 case 0x0000313D: 00129 return "DbgKdReadPhysicalMemoryApi"; 00130 case 0x0000313E: 00131 return "DbgKdWritePhysicalMemoryApi"; 00132 case 0x0000313F: 00133 return "DbgKdQuerySpecialCallsApi"; 00134 case 0x00003140: 00135 return "DbgKdSetSpecialCallApi"; 00136 case 0x00003141: 00137 return "DbgKdClearSpecialCallsApi"; 00138 case 0x00003142: 00139 return "DbgKdSetInternalBreakPointApi"; 00140 case 0x00003143: 00141 return "DbgKdGetInternalBreakPointApi"; 00142 case 0x00003144: 00143 return "DbgKdReadIoSpaceExtendedApi"; 00144 case 0x00003145: 00145 return "DbgKdWriteIoSpaceExtendedApi"; 00146 case 0x00003146: 00147 return "DbgKdGetVersionApi"; 00148 case 0x00003147: 00149 return "DbgKdWriteBreakPointExApi"; 00150 case 0x00003148: 00151 return "DbgKdRestoreBreakPointExApi"; 00152 case 0x00003149: 00153 return "DbgKdCauseBugCheckApi"; 00154 case 0x00003150: 00155 return "DbgKdSwitchProcessor"; 00156 case 0x00003151: 00157 return "DbgKdPageInApi"; 00158 case 0x00003152: 00159 return "DbgKdReadMachineSpecificRegister"; 00160 case 0x00003153: 00161 return "DbgKdWriteMachineSpecificRegister"; 00162 case 0x00003154: 00163 return "OldVlm1"; 00164 case 0x00003155: 00165 return "OldVlm2"; 00166 case 0x00003156: 00167 return "DbgKdSearchMemoryApi"; 00168 case 0x00003157: 00169 return "DbgKdGetBusDataApi"; 00170 case 0x00003158: 00171 return "DbgKdSetBusDataApi"; 00172 case 0x00003159: 00173 return "DbgKdCheckLowMemoryApi"; 00174 case 0x0000315A: 00175 return "DbgKdClearAllInternalBreakpointsApi"; 00176 case 0x0000315B: 00177 return "DbgKdFillMemoryApi"; 00178 case 0x0000315C: 00179 return "DbgKdQueryMemoryApi"; 00180 case 0x0000315D: 00181 return "DbgKdSwitchPartition"; 00182 case 0x0000315E: 00183 return "DbgKdMaximumManipulate"; 00184 default: 00185 return NULL; 00186 } 00187 } 00188 #pragma endregion 00189 00190 static void DumpHexA(const void *pBuffer, size_t length, BazisLib::ConstManagedPointer<BazisLib::AIFile> &pFile, size_t BytesPerLine = 16, const char *pLineBreak = "<br/>\r\n") 00191 { 00192 PBYTE pBuf = (PBYTE)pBuffer; 00193 std::string strBuf; 00194 strBuf.reserve(1024); 00195 00196 char sz[32]; 00197 for (size_t i = 0; i < length;) 00198 { 00199 size_t todo = length - i; 00200 if (todo > BytesPerLine) 00201 todo = BytesPerLine; 00202 00203 strBuf.erase(); 00204 00205 for (size_t j = 0; j < BytesPerLine; j++) 00206 { 00207 if (j < todo) 00208 _snprintf(sz, sizeof(sz), "%02X ", pBuf[i + j]); 00209 else 00210 strncpy(sz, " ", sizeof(sz)); 00211 strBuf += sz; 00212 } 00213 00214 strBuf += " "; 00215 00216 sz[1] = 0; 00217 for (size_t j = 0; j < todo; j++) 00218 { 00219 BYTE byte = pBuf[i + j]; 00220 if ((byte >= 0x20) && (byte <= 0x7F)) 00221 sz[0] = byte; 00222 else 00223 sz[0] = '.'; 00224 strBuf += sz; 00225 } 00226 00227 i += todo; 00228 pFile->Write(strBuf.c_str(), strBuf.length()); 00229 00230 if (i < length) 00231 pFile->Write(pLineBreak, strlen(pLineBreak)); 00232 00233 } 00234 } 00235 00236 void PacketLogger::OnSendReceivePacket( bool bLoggingEnabled, bool bSendPacket, ULONG PacketType, PKD_BUFFER FirstBuffer, PKD_BUFFER SecondBuffer, PKD_CONTEXT KdContext ) 00237 { 00238 if (!bLoggingEnabled) 00239 { 00240 if (m_pFile && m_pFile->Valid()) 00241 m_pFile->Write(szHTMLFooter, sizeof(szHTMLFooter) - 1); 00242 if (m_pFile) 00243 m_pFile = NULL; 00244 return; 00245 } 00246 if (!m_pFile) 00247 { 00248 m_pFile = new BazisLib::OSFile(m_LogFilePath, BazisLib::FastFileFlags::CreateOrTruncateRW); 00249 if (!m_pFile || !m_pFile->Valid()) 00250 return; 00251 m_StartTime = BazisLib::DateTime::Now(); 00252 m_RecvPacketNumber = m_SendPacketNumber = 1; 00253 char szTmp[sizeof(szHTMLPreambleFormat) + MAX_PATH * 2]; 00254 _snprintf(szTmp, sizeof(szTmp), szHTMLPreambleFormat, m_SessionName.c_str(), m_SessionName.c_str()); 00255 m_pFile->Write(szTmp, strlen(szTmp)); 00256 m_pFile->Write(szLegend, sizeof(szLegend) - 1); 00257 m_bTableHeaderPrinted = false; 00258 } 00259 if (!m_pFile || !m_pFile->Valid()) 00260 return; 00261 00262 if (!m_bTableHeaderPrinted) 00263 { 00264 m_pFile->Write(szTableHeader, sizeof(szTableHeader) - 1); 00265 m_bTableHeaderPrinted = true; 00266 } 00267 00268 char sz[512]; 00269 ULONGLONG t = (BazisLib::DateTime::Now() - m_StartTime).GetTotalMilliseconds(); 00270 00271 unsigned msec = (unsigned)(t % 1000); 00272 unsigned tsec = (unsigned)(t / 1000); 00273 00274 unsigned sec = tsec % 60; 00275 unsigned min = tsec / 60; 00276 unsigned hr = min / 60; 00277 min %= 60; 00278 00279 unsigned &num = bSendPacket ? m_SendPacketNumber : m_RecvPacketNumber; 00280 _snprintf(sz, sizeof(sz), "<tr class=\"%s\"><td>%d</td><td>+%d:%02d:%02d.%04d</td><td>%d%s</td><td>\r\n", bSendPacket ? "send" : "recv", num++, hr, min, sec, msec, PacketType, GetPacketTypeName(PacketType)); 00281 m_pFile->Write(sz, strlen(sz)); 00282 00283 if (FirstBuffer && FirstBuffer->Length) 00284 { 00285 _snprintf(sz, sizeof(sz), "Buf1: Size = %d (0x%X)", FirstBuffer->Length, FirstBuffer->Length); 00286 m_pFile->Write(sz, strlen(sz)); 00287 00288 const char *pApi = GetApiTypeName(*((unsigned *)FirstBuffer->pData)); 00289 if (pApi) 00290 _snprintf(sz, sizeof(sz), "; Api# = %s<br/>\r\n", pApi); 00291 else 00292 _snprintf(sz, sizeof(sz), "<br/>\r\n"); 00293 m_pFile->Write(sz, strlen(sz)); 00294 00295 DumpHexA(FirstBuffer->pData, FirstBuffer->Length, m_pFile); 00296 } 00297 00298 if (SecondBuffer && SecondBuffer->Length) 00299 { 00300 _snprintf(sz, sizeof(sz), "<br/><br/>Buf2: Size = %d (0x%X)<br/>", SecondBuffer->Length, SecondBuffer->Length); 00301 m_pFile->Write(sz, strlen(sz)); 00302 00303 DumpHexA(SecondBuffer->pData, SecondBuffer->Length, m_pFile); 00304 } 00305 _snprintf(sz, sizeof(sz), "</td></tr>\r\n"); 00306 m_pFile->Write(sz, strlen(sz)); 00307 } 00308 00309 PacketLogger::~PacketLogger() 00310 { 00311 if (m_pFile && m_pFile->Valid()) 00312 m_pFile->Write(szHTMLFooter, sizeof(szHTMLFooter) - 1); 00313 } 00314 00315 void PacketLogger::OnWindowsTerminationSimulated() 00316 { 00317 if (!m_pFile) 00318 return; 00319 m_pFile->Write(szTerminationSimulationNotification, sizeof(szTerminationSimulationNotification) - 1); 00320 m_bTableHeaderPrinted = false; 00321 } 00322 00323 void PacketLogger::OnWindowsTerminationSimDone( char *pDebugMsg ) 00324 { 00325 if (!m_pFile) 00326 return; 00327 char szMsg[1024]; 00328 _snprintf(szMsg, sizeof(szMsg), szTerminationSimulationEndFmt, pDebugMsg ? pDebugMsg : "(no additional info)"); 00329 m_pFile->Write(szMsg, strlen(szMsg)); 00330 m_bTableHeaderPrinted = false; 00331 }