Windows NT 4.0 source code leak
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.

473 lines
11 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. kdbreak.c
  5. Abstract:
  6. This module implements machine dependent functions to add and delete
  7. breakpoints from the kernel debugger breakpoint table.
  8. Author:
  9. David N. Cutler 2-Aug-1990
  10. Revision History:
  11. --*/
  12. #include "kdp.h"
  13. BOOLEAN BreakpointsSuspended = FALSE;
  14. //
  15. // Define external references.
  16. //
  17. VOID
  18. KdSetOwedBreakpoints(
  19. VOID
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGEKD, KdpAddBreakpoint)
  23. #pragma alloc_text(PAGEKD, KdpDeleteBreakpoint)
  24. #pragma alloc_text(PAGEKD, KdpDeleteBreakpointRange)
  25. #pragma alloc_text(PAGEKD, KdpSuspendBreakpoint)
  26. #pragma alloc_text(PAGEKD, KdpSuspendAllBreakpoints)
  27. #pragma alloc_text(PAGEKD, KdpRestoreAllBreakpoints)
  28. #endif
  29. ULONG
  30. KdpAddBreakpoint (
  31. IN PVOID Address
  32. )
  33. /*++
  34. Routine Description:
  35. This routine adds an entry to the breakpoint table and returns a handle
  36. to the breakpoint table entry.
  37. Arguments:
  38. Address - Supplies the address where to set the breakpoint.
  39. Return Value:
  40. A value of zero is returned if the specified address is already in the
  41. breakpoint table, there are no free entries in the breakpoint table, the
  42. specified address is not correctly aligned, or the specified address is
  43. not valid. Otherwise, the index of the assigned breakpoint table entry
  44. plus one is returned as the function value.
  45. --*/
  46. {
  47. KDP_BREAKPOINT_TYPE Content;
  48. ULONG Handle;
  49. ULONG Index;
  50. BOOLEAN Accessible;
  51. //
  52. // If the specified address is not properly aligned, then return zero.
  53. //
  54. if (((ULONG)Address & KDP_BREAKPOINT_ALIGN) != 0) {
  55. return 0;
  56. }
  57. //
  58. // Get the instruction to be replaced. If the instruction cannot be read,
  59. // then mark breakpoint as not accessible.
  60. //
  61. if (KdpMoveMemory(
  62. (PCHAR)&Content,
  63. (PCHAR)Address,
  64. sizeof(KDP_BREAKPOINT_TYPE) ) != sizeof(KDP_BREAKPOINT_TYPE)) {
  65. Accessible = FALSE;
  66. } else {
  67. Accessible = TRUE;
  68. }
  69. //
  70. // If the specified address is not write accessible, then return zero.
  71. //
  72. if (Accessible && MmDbgWriteCheck((PVOID)Address) == NULL) {
  73. return 0;
  74. }
  75. //
  76. // Search the breakpoint table for a free entry and check if the specified
  77. // address is already in the breakpoint table.
  78. //
  79. for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index += 1) {
  80. if (KdpBreakpointTable[Index].Flags == 0) {
  81. Handle = Index + 1;
  82. break;
  83. }
  84. }
  85. //
  86. // If a free entry was found, then write breakpoint and return the handle
  87. // value plus one. Otherwise, return zero.
  88. //
  89. if (Handle != 0) {
  90. if ( Accessible ) {
  91. KdpBreakpointTable[Handle - 1].Address = Address;
  92. KdpBreakpointTable[Handle - 1].Content = Content;
  93. KdpBreakpointTable[Handle - 1].Flags = KD_BREAKPOINT_IN_USE;
  94. if (Address < (PVOID)GLOBAL_BREAKPOINT_LIMIT) {
  95. KdpBreakpointTable[Handle - 1].DirectoryTableBase =
  96. KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
  97. }
  98. KdpMoveMemory(
  99. (PCHAR)Address,
  100. (PCHAR)&KdpBreakpointInstruction,
  101. sizeof(KDP_BREAKPOINT_TYPE)
  102. );
  103. } else {
  104. KdpBreakpointTable[Handle - 1].Address = Address;
  105. KdpBreakpointTable[Handle - 1].Flags = KD_BREAKPOINT_NEEDS_WRITE;
  106. KdpOweBreakpoint = TRUE;
  107. if (Address < (PVOID)GLOBAL_BREAKPOINT_LIMIT) {
  108. KdpBreakpointTable[Handle - 1].DirectoryTableBase =
  109. KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
  110. }
  111. }
  112. }
  113. return Handle;
  114. }
  115. VOID
  116. KdSetOwedBreakpoints(
  117. VOID
  118. )
  119. /*++
  120. Routine Description:
  121. This function is called after returning from memory management calls
  122. that may cause an inpage. Its purpose is to store pending
  123. breakpoints in pages just made valid.
  124. Arguments:
  125. None.
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. KDP_BREAKPOINT_TYPE Content;
  131. BOOLEAN Enable;
  132. LONG Index;
  133. //
  134. // If we don't owe any breakpoints then return
  135. //
  136. if ( !KdpOweBreakpoint ) {
  137. return;
  138. }
  139. //
  140. // Freeze all other processors, disable interrupts, and save debug
  141. // port state.
  142. //
  143. Enable = KdEnterDebugger(NULL, NULL);
  144. KdpOweBreakpoint = FALSE;
  145. //
  146. // Search the breakpoint table for breakpoints that need to be
  147. // written.
  148. //
  149. for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index += 1) {
  150. if (KdpBreakpointTable[Index].Flags & KD_BREAKPOINT_NEEDS_WRITE) {
  151. //
  152. // Breakpoint needs to be written
  153. //
  154. if ((KdpBreakpointTable[Index].Address >= (PVOID)GLOBAL_BREAKPOINT_LIMIT) ||
  155. (KdpBreakpointTable[Index].DirectoryTableBase ==
  156. KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0])) {
  157. //
  158. // Check to see if we have write access to the memory
  159. //
  160. if (MmDbgWriteCheck((PVOID)KdpBreakpointTable[Index].Address) == NULL) {
  161. KdpOweBreakpoint = TRUE;
  162. break;
  163. }
  164. //
  165. // Breakpoint is global, or it's directory base matches
  166. //
  167. if (KdpMoveMemory(
  168. (PCHAR)&Content,
  169. (PCHAR)KdpBreakpointTable[Index].Address,
  170. sizeof(KDP_BREAKPOINT_TYPE)
  171. ) != sizeof(KDP_BREAKPOINT_TYPE)) {
  172. KdpOweBreakpoint = TRUE;
  173. } else {
  174. KdpBreakpointTable[Index].Content = Content;
  175. KdpBreakpointTable[Index].Flags = KD_BREAKPOINT_IN_USE;
  176. KdpMoveMemory(
  177. (PCHAR)KdpBreakpointTable[Index].Address,
  178. (PCHAR)&KdpBreakpointInstruction,
  179. sizeof(KDP_BREAKPOINT_TYPE)
  180. );
  181. }
  182. } else {
  183. //
  184. // Breakpoint is local and it's directory base does not match
  185. //
  186. KdpOweBreakpoint = TRUE;
  187. }
  188. }
  189. }
  190. KdExitDebugger(Enable);
  191. return;
  192. }
  193. BOOLEAN
  194. KdpDeleteBreakpoint (
  195. IN ULONG Handle
  196. )
  197. /*++
  198. Routine Description:
  199. This routine deletes an entry from the breakpoint table.
  200. Arguments:
  201. Handle - Supplies the index plus one of the breakpoint table entry
  202. which is to be deleted.
  203. Return Value:
  204. A value of FALSE is returned if the specified handle is not a valid
  205. value or the breakpoint cannot be deleted because the old instruction
  206. cannot be replaced. Otherwise, a value of TRUE is returned.
  207. --*/
  208. {
  209. //
  210. // If the specified handle is not value, then return FALSE.
  211. //
  212. if ((Handle == 0) || (Handle > BREAKPOINT_TABLE_SIZE)) {
  213. return FALSE;
  214. }
  215. Handle -= 1;
  216. //
  217. // If the specified breakpoint table is not valid, the return FALSE.
  218. //
  219. if (KdpBreakpointTable[Handle].Flags == 0) {
  220. return FALSE;
  221. }
  222. //
  223. // If the breakpoint is suspended, just delete from the table
  224. //
  225. if (KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_SUSPENDED) {
  226. KdpBreakpointTable[Handle].Flags = 0;
  227. return TRUE;
  228. }
  229. //
  230. // Replace the instruction contents.
  231. //
  232. if (KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_IN_USE &&
  233. KdpBreakpointTable[Handle].Content != KdpBreakpointInstruction) {
  234. KdpMoveMemory(
  235. (PCHAR)KdpBreakpointTable[Handle].Address,
  236. (PCHAR)&KdpBreakpointTable[Handle].Content,
  237. sizeof(KDP_BREAKPOINT_TYPE)
  238. );
  239. }
  240. //
  241. // Delete breakpoint table entry and return TRUE.
  242. //
  243. KdpBreakpointTable[Handle].Flags = 0;
  244. return TRUE;
  245. }
  246. BOOLEAN
  247. KdpDeleteBreakpointRange (
  248. IN PVOID Lower,
  249. IN PVOID Upper
  250. )
  251. /*++
  252. Routine Description:
  253. This routine deletes all breakpoints falling in a given range
  254. from the breakpoint table.
  255. Arguments:
  256. Lower - inclusive lower address of range from which to remove BPs.
  257. Upper - include upper address of range from which to remove BPs.
  258. Return Value:
  259. TRUE if any breakpoints removed, FALSE otherwise.
  260. --*/
  261. {
  262. ULONG Index;
  263. BOOLEAN ReturnStatus = FALSE;
  264. //
  265. // Examine each entry in the table in turn
  266. //
  267. for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index++) {
  268. if ( (KdpBreakpointTable[Index].Flags & KD_BREAKPOINT_IN_USE) &&
  269. ((KdpBreakpointTable[Index].Address >= Lower) &&
  270. (KdpBreakpointTable[Index].Address <= Upper))
  271. ) {
  272. //
  273. // Breakpiont is in use and falls in range, clear it.
  274. //
  275. if (KdpBreakpointTable[Index].Content != KdpBreakpointInstruction) {
  276. KdpMoveMemory(
  277. (PCHAR)KdpBreakpointTable[Index].Address,
  278. (PCHAR)&KdpBreakpointTable[Index].Content,
  279. sizeof(KDP_BREAKPOINT_TYPE)
  280. );
  281. }
  282. KdpBreakpointTable[Index].Flags = 0;
  283. ReturnStatus = TRUE;
  284. }
  285. }
  286. return ReturnStatus;
  287. }
  288. VOID
  289. KdpSuspendBreakpoint (
  290. ULONG Handle
  291. )
  292. {
  293. Handle -= 1;
  294. if ( (KdpBreakpointTable[Handle].Flags != 0) &&
  295. !(KdpBreakpointTable[Handle].Flags & KD_BREAKPOINT_SUSPENDED) ) {
  296. KdpMoveMemory(
  297. (PCHAR)KdpBreakpointTable[Handle].Address,
  298. (PCHAR)&KdpBreakpointTable[Handle].Content,
  299. sizeof(KDP_BREAKPOINT_TYPE)
  300. );
  301. KdpBreakpointTable[Handle].Flags |= KD_BREAKPOINT_SUSPENDED;
  302. }
  303. return;
  304. } // KdpSuspendBreakpoint
  305. VOID
  306. KdpSuspendAllBreakpoints (
  307. VOID
  308. )
  309. {
  310. ULONG index;
  311. BreakpointsSuspended = TRUE;
  312. for ( index = 0; index < BREAKPOINT_TABLE_SIZE; index++ ) {
  313. if ( (KdpBreakpointTable[index].Flags != 0) &&
  314. !(KdpBreakpointTable[index].Flags & KD_BREAKPOINT_SUSPENDED) ) {
  315. //
  316. // Replace the instruction contents.
  317. //
  318. if ( KdpBreakpointTable[index].Flags & KD_BREAKPOINT_IN_USE &&
  319. KdpBreakpointTable[index].Content != KdpBreakpointInstruction ) {
  320. KdpMoveMemory(
  321. (PCHAR)KdpBreakpointTable[index].Address,
  322. (PCHAR)&KdpBreakpointTable[index].Content,
  323. sizeof(KDP_BREAKPOINT_TYPE)
  324. );
  325. KdpBreakpointTable[index].Flags |= KD_BREAKPOINT_SUSPENDED;
  326. }
  327. }
  328. }
  329. return;
  330. } // KdpSuspendAllBreakpoints
  331. VOID
  332. KdpRestoreAllBreakpoints (
  333. VOID
  334. )
  335. {
  336. ULONG index;
  337. BreakpointsSuspended = FALSE;
  338. for ( index = 0; index < BREAKPOINT_TABLE_SIZE; index++ ) {
  339. if ( KdpBreakpointTable[index].Flags & KD_BREAKPOINT_SUSPENDED ) {
  340. KdpMoveMemory(
  341. (PCHAR)KdpBreakpointTable[index].Address,
  342. (PCHAR)&KdpBreakpointInstruction,
  343. sizeof(KDP_BREAKPOINT_TYPE)
  344. );
  345. KdpBreakpointTable[index].Flags &= ~KD_BREAKPOINT_SUSPENDED;
  346. }
  347. }
  348. return;
  349. } // KdpRestoreAllBreakpoints