Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
13 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. time.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Ramon J San Andres (ramonsa) 8-Nov-1993
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. VOID
  16. FileTimeToString(
  17. IN LARGE_INTEGER Time,
  18. IN BOOLEAN TimeZone,
  19. OUT PCHAR Buffer
  20. );
  21. ULONG64
  22. DumpKTimer(
  23. IN ULONG64 pTimer,
  24. IN ULONGLONG InterruptTimeOffset,
  25. IN OPTIONAL ULONG64 Blink
  26. )
  27. {
  28. ULONG64 Displacement;
  29. CHAR Buff[256];
  30. ULONG Result;
  31. ULONG64 NextThread;
  32. LARGE_INTEGER SystemTime;
  33. ULONG Period, Off;
  34. LARGE_INTEGER Due;
  35. ULONG64 Dpc, DeferredRoutine, WaitList_Flink, Timer_Flink, Timer_Blink;
  36. if ( GetFieldValue(pTimer, "nt!_KTIMER", "DueTime.QuadPart", Due.QuadPart) ) {
  37. dprintf("Unable to get contents of Timer @ %p\n", pTimer );
  38. return(0);
  39. }
  40. SystemTime.QuadPart = Due.QuadPart + InterruptTimeOffset;
  41. if (SystemTime.QuadPart < 0) {
  42. strcpy(Buff, " NEVER ");
  43. } else {
  44. FileTimeToString(SystemTime, FALSE, Buff);
  45. }
  46. GetFieldValue(pTimer, "nt!_KTIMER", "Period", Period);
  47. GetFieldValue(pTimer, "nt!_KTIMER", "Dpc", Dpc);
  48. GetFieldValue(pTimer, "nt!_KTIMER", "Header.WaitListHead.Flink", WaitList_Flink);
  49. GetFieldValue(pTimer, "nt!_KTIMER", "TimerListEntry.Flink", Timer_Flink);
  50. GetFieldValue(pTimer, "nt!_KTIMER", "TimerListEntry.Blink", Timer_Blink);
  51. dprintf("%c %08lx %08lx [%s] ",
  52. (Period != 0) ? 'P' : ' ',
  53. Due.LowPart,
  54. Due.HighPart,
  55. Buff);
  56. if (Dpc != 0) {
  57. if (GetFieldValue(Dpc, "nt!_KDPC", "DeferredRoutine", DeferredRoutine)) {
  58. dprintf("Unable to get contents of DPC @ %p\n", Dpc);
  59. return(0);
  60. }
  61. // dprintf("p(%p)", DeferredRoutine);
  62. GetSymbol(DeferredRoutine,
  63. Buff,
  64. &Displacement);
  65. dprintf("%s",Buff);
  66. if (Displacement != 0) {
  67. dprintf("+%1p ", Displacement);
  68. } else {
  69. dprintf(" ");
  70. }
  71. }
  72. //
  73. // List all the threads
  74. //
  75. NextThread = WaitList_Flink;
  76. GetFieldOffset("nt!_KTIMER", "Header.WaitListHead", &Off);
  77. while (WaitList_Flink && (NextThread != pTimer+Off)) {
  78. ULONG64 Flink;
  79. ULONG64 Thread=0;
  80. if (GetFieldValue(NextThread, "nt!_KWAIT_BLOCK", "Thread", Thread)) {
  81. dprintf("Unable to get contents of waitblock @ %p\n", NextThread);
  82. } else {
  83. dprintf("thread %p ",Thread);
  84. }
  85. if (GetFieldValue(NextThread,
  86. "nt!_LIST_ENTRY",
  87. "Flink",
  88. Flink)) {
  89. dprintf("Unable to read next WaitListEntry @ %p\n",NextThread);
  90. break;
  91. }
  92. NextThread = Flink;
  93. }
  94. dprintf("\n");
  95. if (Blink &&
  96. (Timer_Blink != Blink)) {
  97. dprintf(" Timer at %p has wrong Blink! (Blink %08p, should be %08p)\n",
  98. pTimer,
  99. Timer_Blink,
  100. Blink);
  101. }
  102. if (Timer_Flink == 0) {
  103. dprintf(" Timer at %p has been zeroed! (Flink %08p, Blink %08p)\n",
  104. pTimer,
  105. Timer_Flink,
  106. Timer_Blink);
  107. }
  108. return(Timer_Flink);
  109. }
  110. DECLARE_API( timer )
  111. /*++
  112. Routine Description:
  113. Dumps all timers in the system.
  114. Arguments:
  115. args -
  116. Return Value:
  117. None
  118. --*/
  119. {
  120. ULONG CurrentList;
  121. ULONG Index;
  122. LARGE_INTEGER InterruptTime;
  123. LARGE_INTEGER SystemTime;
  124. ULONG MaximumList;
  125. ULONG MaximumSearchCount=0;
  126. ULONG MaximumTimerCount;
  127. ULONG64 NextEntry;
  128. ULONG64 LastEntry;
  129. ULONG64 p;
  130. ULONG64 NextTimer;
  131. ULONG64 KeTickCount;
  132. ULONG64 KiMaximumSearchCount;
  133. ULONG Result;
  134. ULONG64 TickCount=0;
  135. ULONG64 TimerTable;
  136. ULONG TotalTimers;
  137. ULONG KtimerOffset;
  138. ULONG TimerListOffset;
  139. ULONG WakeTimerListOffset;
  140. ULONG64 WakeTimerList;
  141. ULONG64 pETimer, Temp;
  142. ULONG64 SharedUserData;
  143. CHAR Buffer[256];
  144. ULONGLONG InterruptTimeOffset;
  145. UCHAR TypName[]="_KUSER_SHARED_DATA";
  146. CHAR SystemTime1[12]={0}, InterruptTime1[12]={0};
  147. FIELD_INFO offField = {"TimerListEntry", NULL, 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL};
  148. SYM_DUMP_PARAM TypeSym ={
  149. sizeof (SYM_DUMP_PARAM), "nt!_KTIMER", DBG_DUMP_NO_PRINT, 0,
  150. NULL, NULL, NULL, 1, &offField
  151. };
  152. SharedUserData = MM_SHARED_USER_DATA_VA;
  153. //
  154. // Get the system time and print the header banner.
  155. //
  156. if (!GetFieldValue(SharedUserData, TypName, "SystemTime", SystemTime1) )
  157. {
  158. // For x86
  159. GetFieldValue(SharedUserData, TypName, "InterruptTime.High1Time", InterruptTime.HighPart);
  160. GetFieldValue(SharedUserData, TypName, "InterruptTime.LowPart", InterruptTime.LowPart);
  161. GetFieldValue(SharedUserData, TypName, "SystemTime.High1Time", SystemTime.HighPart);
  162. GetFieldValue(SharedUserData, TypName, "SystemTime.LowPart", SystemTime.LowPart);
  163. }
  164. else if (!GetFieldValue(SharedUserData, TypName, "InterruptTime", InterruptTime1) ) {
  165. // For Alphas
  166. InterruptTime.QuadPart = *((PULONG64) &InterruptTime1[0]);
  167. SystemTime.QuadPart = *((PULONG64) &SystemTime1[0]);
  168. }
  169. else
  170. {
  171. dprintf("%08p: Unable to get shared data\n",SharedUserData);
  172. return E_INVALIDARG;
  173. }
  174. /*
  175. #ifdef TARGET_ALPHA
  176. InterruptTime.QuadPart = SharedData.InterruptTime;
  177. SystemTime.QuadPart = SharedData.SystemTime;
  178. #else
  179. InterruptTime.HighPart = SharedData.InterruptTime.High1Time;
  180. InterruptTime.LowPart = SharedData.InterruptTime.LowPart;
  181. SystemTime.HighPart = SharedData.SystemTime.High1Time;
  182. SystemTime.LowPart = SharedData.SystemTime.LowPart;
  183. #endif
  184. */
  185. InterruptTimeOffset = SystemTime.QuadPart - InterruptTime.QuadPart;
  186. FileTimeToString(SystemTime, TRUE, Buffer);
  187. dprintf("Dump system timers\n\n");
  188. dprintf("Interrupt time: %08lx %08lx [%s]\n\n",
  189. InterruptTime.LowPart,
  190. InterruptTime.HighPart,
  191. Buffer);
  192. //
  193. // Get the address of the timer table list head array and scan each
  194. // list for timers.
  195. //
  196. dprintf("List Timer Interrupt Low/High Fire Time DPC/thread\n");
  197. MaximumList = 0;
  198. TimerTable = GetExpression( "nt!KiTimerTableListHead" );
  199. if ( !TimerTable ) {
  200. dprintf("Unable to get value of KiTimerTableListHead\n");
  201. return E_INVALIDARG;
  202. }
  203. TotalTimers = 0;
  204. // Get The TimerListOffset in KTIMER offset
  205. if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
  206. return E_INVALIDARG ;
  207. }
  208. TimerListOffset = (ULONG) offField.address;
  209. for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {
  210. //
  211. // Read the forward link in the next timer table list head.
  212. //
  213. if ( GetFieldValue(TimerTable, "nt!_LIST_ENTRY", "Flink", NextEntry)) {
  214. dprintf("Unable to get contents of next entry @ %p\n", TimerTable );
  215. continue;
  216. }
  217. //
  218. // Scan the current timer list and display the timer values.
  219. //
  220. LastEntry = TimerTable;
  221. CurrentList = 0;
  222. while (NextEntry != TimerTable) {
  223. CurrentList += 1;
  224. NextTimer = NextEntry - TimerListOffset; // CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  225. TotalTimers += 1;
  226. if (CurrentList == 1) {
  227. dprintf("%3ld %08p ", Index, NextTimer);
  228. } else {
  229. dprintf(" %08p ", NextTimer);
  230. }
  231. p = LastEntry;
  232. LastEntry = NextEntry;
  233. NextEntry = DumpKTimer(NextTimer, InterruptTimeOffset, p);
  234. if (NextEntry==0) {
  235. break;
  236. }
  237. if (CheckControlC()) {
  238. return E_INVALIDARG;
  239. }
  240. }
  241. TimerTable += GetTypeSize("nt!_LIST_ENTRY");
  242. if (CurrentList > MaximumList) {
  243. MaximumList = CurrentList;
  244. }
  245. if (CheckControlC()) {
  246. return E_INVALIDARG;
  247. }
  248. }
  249. dprintf("\n\nTotal Timers: %d, Maximum List: %d\n",
  250. TotalTimers,
  251. MaximumList);
  252. //
  253. // Get the current tick count and convert to the hand value.
  254. //
  255. KeTickCount = GetExpression( "nt!KeTickCount" );
  256. if ( KeTickCount && !GetFieldValue(KeTickCount, "ULONG", NULL, TickCount)) {
  257. dprintf("Current Hand: %d", (ULONG) TickCount & (TIMER_TABLE_SIZE - 1));
  258. }
  259. //
  260. // Get the maximum search count if the target system is a checked
  261. // build and display the count.
  262. //
  263. KiMaximumSearchCount = GetExpression( "nt!KiMaximumSearchCount" );
  264. if ( KiMaximumSearchCount &&
  265. !GetFieldValue(KiMaximumSearchCount, "ULONG", NULL, Temp)) {
  266. MaximumSearchCount = (ULONG) Temp;
  267. dprintf(", Maximum Search: %d", MaximumSearchCount);
  268. }
  269. dprintf("\n\n");
  270. //
  271. // Dump the list of wakeable timers
  272. //
  273. dprintf("Wakeable timers:\n");
  274. WakeTimerList = GetExpression("nt!ExpWakeTimerList");
  275. if (!WakeTimerList) {
  276. dprintf("Unable to get value of ExpWakeTimerList\n");
  277. return E_INVALIDARG;
  278. }
  279. // Get The WakeTimerLis tOffset in ETIMER
  280. TypeSym.sName = "_ETIMER";
  281. offField.fName = "WakeTimerListEntry";
  282. if (Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size)) {
  283. return E_INVALIDARG;
  284. }
  285. TimerListOffset = (ULONG) offField.address;
  286. offField.fName = "KeTimer";
  287. Ioctl(IG_DUMP_SYMBOL_INFO, &TypeSym, TypeSym.size);
  288. KtimerOffset = (ULONG) offField.address;
  289. //
  290. // Read the forward link in the wake timer list
  291. //
  292. if (!ReadPointer(WakeTimerList,
  293. &NextEntry)) {
  294. dprintf("Unable to get contents of next entry @ %p\n",WakeTimerList);
  295. return E_INVALIDARG;
  296. }
  297. //
  298. // Scan the timer list and display the timer values.
  299. //
  300. while (NextEntry != WakeTimerList) {
  301. pETimer = NextEntry - TimerListOffset;
  302. dprintf("%08lx\t", pETimer + KtimerOffset);
  303. DumpKTimer(pETimer + KtimerOffset, InterruptTimeOffset, 0);
  304. GetFieldValue(pETimer, "_ETIMER", "WakeTimerListEntry.Flink", NextEntry);
  305. // NextEntry = ETimer.WakeTimerListEntry.Flink;
  306. if (CheckControlC()) {
  307. return E_INVALIDARG;
  308. }
  309. }
  310. dprintf("\n");
  311. return S_OK;
  312. }
  313. VOID
  314. FileTimeToString(
  315. IN LARGE_INTEGER Time,
  316. IN BOOLEAN TimeZone,
  317. OUT PCHAR Buffer
  318. )
  319. {
  320. TIME_FIELDS TimeFields;
  321. TIME_ZONE_INFORMATION TimeZoneInfo;
  322. PWCHAR pszTz;
  323. ULONGLONG TzBias;
  324. DWORD Result;
  325. //
  326. // Get the local (to the debugger) timezone bias
  327. //
  328. Result = GetTimeZoneInformation(&TimeZoneInfo);
  329. if (Result == 0xffffffff) {
  330. pszTz = L"UTC";
  331. } else {
  332. //
  333. // Bias is in minutes, convert to 100ns units
  334. //
  335. TzBias = (ULONGLONG)TimeZoneInfo.Bias * 60 * 10000000;
  336. switch (Result) {
  337. case TIME_ZONE_ID_UNKNOWN:
  338. pszTz = L"unknown";
  339. break;
  340. case TIME_ZONE_ID_STANDARD:
  341. pszTz = TimeZoneInfo.StandardName;
  342. break;
  343. case TIME_ZONE_ID_DAYLIGHT:
  344. pszTz = TimeZoneInfo.DaylightName;
  345. break;
  346. }
  347. Time.QuadPart -= TzBias;
  348. }
  349. RtlTimeToTimeFields(&Time, &TimeFields);
  350. if (TimeZone) {
  351. sprintf(Buffer, "%2d/%2d/%d %02d:%02d:%02d.%03d (%ws)",
  352. TimeFields.Month,
  353. TimeFields.Day,
  354. TimeFields.Year,
  355. TimeFields.Hour,
  356. TimeFields.Minute,
  357. TimeFields.Second,
  358. TimeFields.Milliseconds,
  359. pszTz);
  360. } else {
  361. sprintf(Buffer, "%2d/%2d/%d %02d:%02d:%02d.%03d",
  362. TimeFields.Month,
  363. TimeFields.Day,
  364. TimeFields.Year,
  365. TimeFields.Hour,
  366. TimeFields.Minute,
  367. TimeFields.Second,
  368. TimeFields.Milliseconds);
  369. }
  370. }
  371. DECLARE_API( filetime )
  372. /*++
  373. Routine Description:
  374. Reformats a 64-bit NT time (FILETIME) as something a human
  375. being can understand
  376. Arguments:
  377. args - 64-bit filetime to reformat
  378. Return Value:
  379. None
  380. --*/
  381. {
  382. LARGE_INTEGER Time;
  383. CHAR Buffer[256];
  384. Time.QuadPart = GetExpression(args);
  385. if (Time.QuadPart == 0) {
  386. dprintf("!filetime <64-bit FILETIME>\n");
  387. } else {
  388. FileTimeToString(Time,TRUE, Buffer);
  389. dprintf("%s\n",Buffer);
  390. }
  391. return S_OK;
  392. }