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.

332 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. machine.c
  5. Abstract:
  6. This file contains machine specific code to support the INSTALER
  7. program. Specifically, routines to fetch parameters from the
  8. registers/stack of a target process, routines to set a breakpoint
  9. and step over an instruction at a breakpoint.
  10. Author:
  11. Steve Wood (stevewo) 10-Aug-1994
  12. Revision History:
  13. --*/
  14. #include "instaler.h"
  15. #define BREAKPOINT_OPCODE 0xCC
  16. #define INT_OPCODE 0xCD
  17. UCHAR InstructionBuffer = BREAKPOINT_OPCODE;
  18. PVOID BreakpointInstruction = (PVOID)&InstructionBuffer;
  19. ULONG SizeofBreakpointInstruction = sizeof( InstructionBuffer );
  20. BOOLEAN
  21. SkipOverHardcodedBreakpoint(
  22. PPROCESS_INFO Process,
  23. PTHREAD_INFO Thread,
  24. PVOID BreakpointAddress
  25. )
  26. {
  27. UCHAR InstructionByte;
  28. CONTEXT Context;
  29. Context.ContextFlags = CONTEXT_FULL;
  30. if (!GetThreadContext( Thread->Handle, &Context )) {
  31. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  32. return FALSE;
  33. }
  34. if (!ReadMemory( Process,
  35. BreakpointAddress,
  36. &InstructionByte,
  37. sizeof( InstructionByte ),
  38. "hard coded breakpoint"
  39. )
  40. ) {
  41. return FALSE;
  42. }
  43. if (InstructionByte == BREAKPOINT_OPCODE) {
  44. Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 1);
  45. }
  46. else
  47. if (InstructionByte == INT_OPCODE) {
  48. Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 2);
  49. }
  50. else {
  51. return FALSE;
  52. }
  53. if (!SetThreadContext( Thread->Handle, &Context )) {
  54. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  55. return FALSE;
  56. }
  57. else {
  58. return TRUE;
  59. }
  60. }
  61. BOOLEAN
  62. ExtractProcedureParameters(
  63. PPROCESS_INFO Process,
  64. PTHREAD_INFO Thread,
  65. PULONG ReturnAddress,
  66. ULONG SizeOfParameters,
  67. PULONG Parameters
  68. )
  69. {
  70. UINT i;
  71. ULONG NumberOfParameters;
  72. CONTEXT Context;
  73. ULONG StackBuffer[ 1+31 ];
  74. NumberOfParameters = SizeOfParameters / sizeof( ULONG );
  75. if ((NumberOfParameters * sizeof( ULONG )) != SizeOfParameters ||
  76. NumberOfParameters > 31
  77. ) {
  78. DbgEvent( INTERNALERROR, ( "Invalid parameter size %x\n", SizeOfParameters ) );
  79. return FALSE;
  80. }
  81. Context.ContextFlags = CONTEXT_CONTROL;
  82. if (!GetThreadContext( Thread->Handle, &Context )) {
  83. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  84. return FALSE;
  85. }
  86. if (!ReadMemory( Process,
  87. (PVOID)Context.Esp,
  88. StackBuffer,
  89. SizeOfParameters + sizeof( ULONG ),
  90. "parameters"
  91. )
  92. ) {
  93. return FALSE;
  94. }
  95. *ReturnAddress = StackBuffer[ 0 ];
  96. for (i=0; i<NumberOfParameters; i++) {
  97. Parameters[ i ] = StackBuffer[ 1+i ];
  98. }
  99. return TRUE;
  100. }
  101. BOOLEAN
  102. ExtractProcedureReturnValue(
  103. PPROCESS_INFO Process,
  104. PTHREAD_INFO Thread,
  105. PVOID ReturnValue,
  106. ULONG SizeOfReturnValue
  107. )
  108. {
  109. CONTEXT Context;
  110. Context.ContextFlags = CONTEXT_FULL;
  111. if (!GetThreadContext( Thread->Handle, &Context )) {
  112. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  113. return FALSE;
  114. }
  115. switch (SizeOfReturnValue) {
  116. case sizeof( UCHAR ):
  117. *(PUCHAR)ReturnValue = (UCHAR)Context.Eax;
  118. break;
  119. case sizeof( USHORT ):
  120. *(PUSHORT)ReturnValue = (USHORT)Context.Eax;
  121. break;
  122. case sizeof( ULONG ):
  123. *(PULONG)ReturnValue = (ULONG)Context.Eax;
  124. break;
  125. case sizeof( ULONGLONG ):
  126. *(PULONGLONG)ReturnValue = (ULONGLONG)Context.Edx << 32 | Context.Eax;
  127. break;
  128. default:
  129. DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
  130. return FALSE;
  131. }
  132. return TRUE;
  133. }
  134. BOOLEAN
  135. SetProcedureReturnValue(
  136. PPROCESS_INFO Process,
  137. PTHREAD_INFO Thread,
  138. PVOID ReturnValue,
  139. ULONG SizeOfReturnValue
  140. )
  141. {
  142. CONTEXT Context;
  143. Context.ContextFlags = CONTEXT_FULL;
  144. if (!GetThreadContext( Thread->Handle, &Context )) {
  145. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  146. return FALSE;
  147. }
  148. switch (SizeOfReturnValue) {
  149. case sizeof( UCHAR ):
  150. (UCHAR)Context.Eax = *(PUCHAR)ReturnValue;
  151. break;
  152. case sizeof( USHORT ):
  153. (USHORT)Context.Eax = *(PUSHORT)ReturnValue;
  154. break;
  155. case sizeof( ULONG ):
  156. (ULONG)Context.Eax = *(PULONG)ReturnValue;
  157. break;
  158. case sizeof( ULONGLONG ):
  159. (ULONG)Context.Eax = *(PULONG)ReturnValue;
  160. (ULONG)Context.Edx = *((PULONG)ReturnValue + 1);
  161. break;
  162. default:
  163. DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
  164. return FALSE;
  165. }
  166. if (!SetThreadContext( Thread->Handle, &Context )) {
  167. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  168. return FALSE;
  169. }
  170. else {
  171. return TRUE;
  172. }
  173. }
  174. BOOLEAN
  175. ForceReturnToCaller(
  176. PPROCESS_INFO Process,
  177. PTHREAD_INFO Thread,
  178. ULONG SizeOfParameters,
  179. PVOID ReturnAddress,
  180. PVOID ReturnValue,
  181. ULONG SizeOfReturnValue
  182. )
  183. {
  184. CONTEXT Context;
  185. Context.ContextFlags = CONTEXT_FULL;
  186. if (!GetThreadContext( Thread->Handle, &Context )) {
  187. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  188. return FALSE;
  189. }
  190. switch (SizeOfReturnValue) {
  191. case sizeof( UCHAR ):
  192. (UCHAR)Context.Eax = *(PUCHAR)ReturnValue;
  193. break;
  194. case sizeof( USHORT ):
  195. (USHORT)Context.Eax = *(PUSHORT)ReturnValue;
  196. break;
  197. case sizeof( ULONG ):
  198. (ULONG)Context.Eax = *(PULONG)ReturnValue;
  199. break;
  200. case sizeof( ULONGLONG ):
  201. (ULONG)Context.Eax = *(PULONG)ReturnValue;
  202. (ULONG)Context.Edx = *((PULONG)ReturnValue + 1);
  203. break;
  204. default:
  205. DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
  206. return FALSE;
  207. }
  208. Context.Eip = (ULONG)ReturnAddress;
  209. Context.Esp = Context.Esp + sizeof( ReturnAddress ) + SizeOfParameters;
  210. if (!SetThreadContext( Thread->Handle, &Context )) {
  211. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  212. return FALSE;
  213. }
  214. else {
  215. return TRUE;
  216. }
  217. }
  218. BOOLEAN
  219. UndoReturnAddressBreakpoint(
  220. PPROCESS_INFO Process,
  221. PTHREAD_INFO Thread
  222. )
  223. {
  224. CONTEXT Context;
  225. Context.ContextFlags = CONTEXT_FULL;
  226. if (!GetThreadContext( Thread->Handle, &Context )) {
  227. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  228. return FALSE;
  229. }
  230. Context.Eip -= 1; // Back up to where breakpoint instruction was
  231. if (!SetThreadContext( Thread->Handle, &Context )) {
  232. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  233. return FALSE;
  234. }
  235. else {
  236. return TRUE;
  237. }
  238. }
  239. BOOLEAN
  240. BeginSingleStepBreakpoint(
  241. PPROCESS_INFO Process,
  242. PTHREAD_INFO Thread
  243. )
  244. {
  245. CONTEXT Context;
  246. Context.ContextFlags = CONTEXT_FULL;
  247. if (!GetThreadContext( Thread->Handle, &Context )) {
  248. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  249. return FALSE;
  250. }
  251. Context.Eip -= 1; // Back up to where breakpoint instruction was
  252. Context.EFlags |= V86FLAGS_TRACE;
  253. if (!SetThreadContext( Thread->Handle, &Context )) {
  254. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  255. return FALSE;
  256. }
  257. else {
  258. return TRUE;
  259. }
  260. }
  261. BOOLEAN
  262. EndSingleStepBreakpoint(
  263. PPROCESS_INFO Process,
  264. PTHREAD_INFO Thread
  265. )
  266. {
  267. CONTEXT Context;
  268. Context.ContextFlags = CONTEXT_FULL;
  269. if (!GetThreadContext( Thread->Handle, &Context )) {
  270. DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  271. return FALSE;
  272. }
  273. Context.EFlags &= ~V86FLAGS_TRACE;
  274. if (!SetThreadContext( Thread->Handle, &Context )) {
  275. DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
  276. return FALSE;
  277. }
  278. else {
  279. return TRUE;
  280. }
  281. }