1
0

threads.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. threads.c
  5. Abstract:
  6. This module implements thread related debugger extensions.
  7. Author:
  8. Evan Green 4-Oct-2012
  9. Environment:
  10. Debug Client
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include <minoca/kernel/arm.h>
  17. #include <minoca/debug/dbgext.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define MAX_THREAD_NAME 100
  26. #define MALLOC(_x) malloc(_x)
  27. #define FREE(_x) free(_x)
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. //
  35. // -------------------------------------------------------------------- Globals
  36. //
  37. //
  38. // ------------------------------------------------------------------ Functions
  39. //
  40. INT
  41. ExtThread (
  42. PDEBUGGER_CONTEXT Context,
  43. PSTR Command,
  44. ULONG ArgumentCount,
  45. PSTR *ArgumentValues
  46. )
  47. /*++
  48. Routine Description:
  49. This routine prints out the contents of a Memory Descriptor List. Arguments
  50. to the extension are:
  51. Address - Supplies the address of the MDL.
  52. Arguments:
  53. Context - Supplies a pointer to the debugger applicaton context, which is
  54. an argument to most of the API functions.
  55. Command - Supplies the subcommand entered. This parameter is unused.
  56. ArgumentCount - Supplies the number of arguments in the ArgumentValues
  57. array.
  58. ArgumentValues - Supplies the values of each argument. This memory will be
  59. reused when the function returns, so extensions must not touch this
  60. memory after returning from this call.
  61. Return Value:
  62. 0 if the debugger extension command was successful.
  63. Returns an error code if a failure occurred along the way.
  64. --*/
  65. {
  66. ULONG AddressSize;
  67. ULONGLONG BasePointer;
  68. ULONGLONG BasePointerAddress;
  69. ULONG BytesRead;
  70. PVOID Data;
  71. ULONG DataSize;
  72. ULONGLONG InstructionPointer;
  73. REGISTERS_UNION LocalRegisters;
  74. ULONGLONG Preemptions;
  75. ULONGLONG StackPointer;
  76. ULONGLONG State;
  77. INT Status;
  78. DEBUG_TARGET_INFORMATION TargetInformation;
  79. ULONGLONG ThreadAddress;
  80. PSTR ThreadName;
  81. PTYPE_SYMBOL ThreadType;
  82. ULONGLONG Value;
  83. ULONGLONG Yields;
  84. Data = NULL;
  85. if ((Command != NULL) || (ArgumentCount != 2)) {
  86. DbgOut("Usage: !thread <ThreadAddress>.\n"
  87. " The thread extension prints out the contents of a "
  88. " thread object.\n"
  89. " ThreadAddress - Supplies the address of the thread to "
  90. "dump.\n");
  91. return EINVAL;
  92. }
  93. AddressSize = DbgGetTargetPointerSize(Context);
  94. memset(&LocalRegisters, 0, sizeof(REGISTERS_UNION));
  95. //
  96. // Get the address of the thread and read in the structure.
  97. //
  98. Status = DbgEvaluate(Context, ArgumentValues[1], &ThreadAddress);
  99. if (Status != 0) {
  100. DbgOut("Error: Unable to evaluate Address parameter.\n");
  101. goto ExtThreadEnd;
  102. }
  103. DbgOut("Dumping Thread at 0x%08I64x ", ThreadAddress);
  104. Status = DbgReadTypeByName(Context,
  105. ThreadAddress,
  106. "KTHREAD",
  107. &ThreadType,
  108. &Data,
  109. &DataSize);
  110. if (Status != 0) {
  111. DbgOut("Error: Could not read KTHREAD at 0x%I64x.\n", ThreadAddress);
  112. goto ExtThreadEnd;
  113. }
  114. Status = DbgReadIntegerMember(Context,
  115. ThreadType,
  116. "Header.Type",
  117. ThreadAddress,
  118. Data,
  119. DataSize,
  120. &Value);
  121. if (Status != 0) {
  122. goto ExtThreadEnd;
  123. }
  124. if (Value != ObjectThread) {
  125. DbgOut("Probably not a thread, has an object type %I64d instead of "
  126. "%d.\n",
  127. Value,
  128. ObjectThread);
  129. Status = EINVAL;
  130. goto ExtThreadEnd;
  131. }
  132. //
  133. // If the thread has a name, attempt to read that in and print it.
  134. //
  135. Status = DbgReadIntegerMember(Context,
  136. ThreadType,
  137. "Header.Name",
  138. ThreadAddress,
  139. Data,
  140. DataSize,
  141. &Value);
  142. if (Status != 0) {
  143. goto ExtThreadEnd;
  144. }
  145. if (Value != 0) {
  146. DbgOut("Name: ");
  147. ThreadName = MALLOC(MAX_THREAD_NAME + 1);
  148. if (ThreadName == NULL) {
  149. DbgOut("Error: Could not allocate memory\n");
  150. return ENOMEM;;
  151. }
  152. memset(ThreadName, 0, MAX_THREAD_NAME + 1);
  153. Status = DbgReadMemory(Context,
  154. TRUE,
  155. Value,
  156. MAX_THREAD_NAME,
  157. ThreadName,
  158. &BytesRead);
  159. if ((Status != 0) || (BytesRead == 0)) {
  160. DbgOut("Error: Could not read thread name.\n");
  161. } else {
  162. DbgOut("%s\n", ThreadName);
  163. }
  164. FREE(ThreadName);
  165. }
  166. Status = DbgReadIntegerMember(Context,
  167. ThreadType,
  168. "OwningProcess",
  169. ThreadAddress,
  170. Data,
  171. DataSize,
  172. &Value);
  173. if (Status != 0) {
  174. goto ExtThreadEnd;
  175. }
  176. DbgOut("Process 0x%08I64x ID ", Value);
  177. Status = DbgReadIntegerMember(Context,
  178. ThreadType,
  179. "ThreadId",
  180. ThreadAddress,
  181. Data,
  182. DataSize,
  183. &Value);
  184. if (Status != 0) {
  185. goto ExtThreadEnd;
  186. }
  187. DbgOut("%I64d, Flags: ", Value);
  188. Status = DbgReadIntegerMember(Context,
  189. ThreadType,
  190. "Flags",
  191. ThreadAddress,
  192. Data,
  193. DataSize,
  194. &Value);
  195. if (Status != 0) {
  196. goto ExtThreadEnd;
  197. }
  198. DbgOut("0x%I64x", Value);
  199. if ((Value & THREAD_FLAG_USER_MODE) != 0) {
  200. DbgOut(" UserMode ");
  201. } else {
  202. DbgOut(" KernelMode ");
  203. }
  204. Status = DbgReadIntegerMember(Context,
  205. ThreadType,
  206. "ThreadRoutine",
  207. ThreadAddress,
  208. Data,
  209. DataSize,
  210. &Value);
  211. if (Status != 0) {
  212. goto ExtThreadEnd;
  213. }
  214. DbgPrintAddressSymbol(Context, Value);
  215. Status = DbgReadIntegerMember(Context,
  216. ThreadType,
  217. "ThreadParameter",
  218. ThreadAddress,
  219. Data,
  220. DataSize,
  221. &Value);
  222. if (Status != 0) {
  223. goto ExtThreadEnd;
  224. }
  225. DbgOut(" (Param 0x%I64x)", Value);
  226. DbgOut("\nState: ");
  227. DbgPrintTypeMember(Context,
  228. ThreadAddress,
  229. Data,
  230. DataSize,
  231. ThreadType,
  232. "State",
  233. 0,
  234. 0);
  235. Status = DbgReadIntegerMember(Context,
  236. ThreadType,
  237. "State",
  238. ThreadAddress,
  239. Data,
  240. DataSize,
  241. &State);
  242. if (Status != 0) {
  243. goto ExtThreadEnd;
  244. }
  245. if (State == ThreadStateBlocked) {
  246. Status = DbgReadIntegerMember(Context,
  247. ThreadType,
  248. "WaitBlock",
  249. ThreadAddress,
  250. Data,
  251. DataSize,
  252. &Value);
  253. if (Status != 0) {
  254. goto ExtThreadEnd;
  255. }
  256. DbgOut(" on 0x%08I64x", Value);
  257. }
  258. Status = DbgReadIntegerMember(Context,
  259. ThreadType,
  260. "ResourceUsage.Preemptions",
  261. ThreadAddress,
  262. Data,
  263. DataSize,
  264. &Preemptions);
  265. if (Status != 0) {
  266. goto ExtThreadEnd;
  267. }
  268. Status = DbgReadIntegerMember(Context,
  269. ThreadType,
  270. "ResourceUsage.Yields",
  271. ThreadAddress,
  272. Data,
  273. DataSize,
  274. &Yields);
  275. if (Status != 0) {
  276. goto ExtThreadEnd;
  277. }
  278. DbgOut(" Runs: %I64d, Preemptions %I64d Yields %I64d",
  279. Preemptions + Yields,
  280. Preemptions,
  281. Yields);
  282. DbgOut("\n\n");
  283. //
  284. // To avoid bad memory accesses, avoid printing call stacks for non-living
  285. // or currently running threads.
  286. //
  287. if ((State == ThreadStateRunning) ||
  288. (State == ThreadStateExited) ||
  289. (State == ThreadStateFirstTime)) {
  290. Status = 0;
  291. goto ExtThreadEnd;
  292. }
  293. //
  294. // Get the target information, including the architecture being debugged.
  295. //
  296. Status = DbgGetTargetInformation(Context,
  297. &TargetInformation,
  298. sizeof(DEBUG_TARGET_INFORMATION));
  299. if (Status != 0) {
  300. DbgOut("Error getting debug target information.\n");
  301. return 0;
  302. }
  303. //
  304. // Determine the instruction pointer, stack pointer, and base pointer,
  305. // which are all needed for printing the call stack.
  306. //
  307. InstructionPointer = (UINTN)NULL;
  308. Status = DbgReadIntegerMember(Context,
  309. ThreadType,
  310. "KernelStackPointer",
  311. ThreadAddress,
  312. Data,
  313. DataSize,
  314. &StackPointer);
  315. if (Status != 0) {
  316. goto ExtThreadEnd;
  317. }
  318. BasePointer = (UINTN)NULL;
  319. switch (TargetInformation.MachineType) {
  320. case MACHINE_TYPE_X86:
  321. Status = DbgReadMemory(Context,
  322. TRUE,
  323. StackPointer + 24,
  324. AddressSize,
  325. &BasePointer,
  326. &BytesRead);
  327. if ((Status != 0) || (BytesRead != AddressSize)) {
  328. DbgOut("Error: Could not get base pointer at 0x%08I64x.\n",
  329. StackPointer + 24);
  330. if (Status == 0) {
  331. Status = EINVAL;
  332. }
  333. return Status;
  334. }
  335. Status = DbgReadMemory(Context,
  336. TRUE,
  337. StackPointer + 28,
  338. AddressSize,
  339. &InstructionPointer,
  340. &BytesRead);
  341. if ((Status != 0) || (BytesRead != AddressSize)) {
  342. DbgOut("Error: Could not get return address at 0x%08I64x.\n",
  343. StackPointer + 28);
  344. if (Status == 0) {
  345. Status = EINVAL;
  346. }
  347. return Status;
  348. }
  349. LocalRegisters.X86.Eip = InstructionPointer;
  350. LocalRegisters.X86.Ebp = BasePointer;
  351. LocalRegisters.X86.Esp = BasePointer;
  352. break;
  353. case MACHINE_TYPE_ARM:
  354. Status = DbgReadMemory(Context,
  355. TRUE,
  356. StackPointer + 40,
  357. AddressSize,
  358. &InstructionPointer,
  359. &BytesRead);
  360. if ((Status != 0) || (BytesRead != AddressSize)) {
  361. DbgOut("Error: Could not get return address at 0x%08I64x.\n",
  362. StackPointer + 36);
  363. if (Status == 0) {
  364. Status = EINVAL;
  365. }
  366. return Status;
  367. }
  368. BasePointerAddress = StackPointer + 32;
  369. if ((InstructionPointer & ARM_THUMB_BIT) != 0) {
  370. BasePointerAddress = StackPointer + 16;
  371. }
  372. Status = DbgReadMemory(Context,
  373. TRUE,
  374. BasePointerAddress,
  375. AddressSize,
  376. &BasePointer,
  377. &BytesRead);
  378. if ((Status != 0) || (BytesRead != AddressSize)) {
  379. DbgOut("Error: Could not get base pointer at 0x%08I64x.\n",
  380. BasePointerAddress);
  381. if (Status == 0) {
  382. Status = EINVAL;
  383. }
  384. return Status;
  385. }
  386. LocalRegisters.Arm.R15Pc = InstructionPointer;
  387. LocalRegisters.Arm.R11Fp = BasePointer;
  388. LocalRegisters.Arm.R7 = BasePointer;
  389. LocalRegisters.Arm.R13Sp = BasePointer;
  390. break;
  391. default:
  392. DbgOut("Error: Unknown machine type %d.\n",
  393. TargetInformation.MachineType);
  394. return EINVAL;
  395. }
  396. //
  397. // Print the call stack for the given thread.
  398. //
  399. DbgPrintCallStack(Context, &LocalRegisters, FALSE);
  400. Status = 0;
  401. ExtThreadEnd:
  402. if (Data != NULL) {
  403. free(Data);
  404. }
  405. return Status;
  406. }
  407. //
  408. // --------------------------------------------------------- Internal Functions
  409. //