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.

510 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. segment.c
  5. Abstract:
  6. This module contains the debugging support needed to track
  7. 16-bit VDM segment notifications.
  8. Author:
  9. Neil Sandlin (neilsa) 1-Mar-1997 Rewrote it
  10. Revision History:
  11. --*/
  12. #include <precomp.h>
  13. #pragma hdrstop
  14. #include <stdio.h>
  15. SEGENTRY SegListHead = {0};
  16. //----------------------------------------------------------------------------
  17. // VDMGetSegtablePointer
  18. //
  19. // This is an undocumented entry point that allows VDMEXTS to dump the
  20. // segment list
  21. //
  22. //----------------------------------------------------------------------------
  23. PSEGENTRY
  24. WINAPI
  25. VDMGetSegtablePointer(
  26. VOID
  27. )
  28. {
  29. return SegListHead.Next;
  30. }
  31. //----------------------------------------------------------------------------
  32. // VDMIsModuleLoaded
  33. //
  34. // Given the path parameter, this routine determines if there are any
  35. // segments in the segment list from the specified executable.
  36. //
  37. //----------------------------------------------------------------------------
  38. BOOL
  39. WINAPI
  40. VDMIsModuleLoaded(
  41. LPSTR szPath
  42. )
  43. {
  44. PSEGENTRY pSegEntry = SegListHead.Next;
  45. if (!*szPath) {
  46. return FALSE;
  47. }
  48. while (pSegEntry) {
  49. if ( _stricmp(pSegEntry->szExePath, szPath) == 0 ) {
  50. return TRUE;
  51. }
  52. pSegEntry = pSegEntry->Next;
  53. }
  54. return FALSE;
  55. }
  56. //----------------------------------------------------------------------------
  57. // SegmentLoad
  58. //
  59. // This routine adds an entry to the segment list based on the parameters
  60. // of a client SegmentLoad notification.
  61. //
  62. //----------------------------------------------------------------------------
  63. BOOL
  64. SegmentLoad(
  65. WORD selector,
  66. WORD segment,
  67. LPSTR szExePath
  68. )
  69. {
  70. PSEGENTRY pSegEntry;
  71. if (strlen(szExePath) >= MAX_PATH16) {
  72. return FALSE;
  73. }
  74. pSegEntry = MALLOC(sizeof(SEGENTRY));
  75. if (pSegEntry == NULL) {
  76. return FALSE;
  77. }
  78. pSegEntry->Next = SegListHead.Next;
  79. SegListHead.Next = pSegEntry;
  80. pSegEntry->selector = selector;
  81. pSegEntry->segment = segment;
  82. pSegEntry->type = SEGTYPE_PROT;
  83. strcpy( pSegEntry->szExePath, szExePath );
  84. ParseModuleName(pSegEntry->szModule, szExePath);
  85. pSegEntry->length = 0;
  86. return TRUE;
  87. }
  88. //----------------------------------------------------------------------------
  89. // SegmentFree
  90. //
  91. // This routine removes the entry from the segment list that matches the
  92. // pass selector.
  93. //
  94. //----------------------------------------------------------------------------
  95. BOOL
  96. SegmentFree(
  97. WORD selector
  98. )
  99. {
  100. PSEGENTRY pSegEntry = SegListHead.Next;
  101. PSEGENTRY pSegPrev = &SegListHead;
  102. PSEGENTRY pSegTmp;
  103. BOOL fResult = FALSE;
  104. while (pSegEntry) {
  105. if ((pSegEntry->type == SEGTYPE_PROT) &&
  106. (pSegEntry->selector == selector)) {
  107. pSegPrev->Next = pSegEntry->Next;
  108. pSegTmp = pSegEntry;
  109. pSegEntry = pSegTmp->Next;
  110. FREE(pSegTmp);
  111. fResult = TRUE;
  112. } else {
  113. pSegEntry = pSegEntry->Next;
  114. }
  115. }
  116. return fResult;
  117. }
  118. //----------------------------------------------------------------------------
  119. // ModuleLoad
  120. //
  121. // This routine adds an entry to the segment list based on the parameters
  122. // of a client ModuleLoad notification.
  123. //
  124. //----------------------------------------------------------------------------
  125. BOOL
  126. ModuleLoad(
  127. WORD selector,
  128. WORD segment,
  129. DWORD length,
  130. LPSTR szExePath
  131. )
  132. {
  133. PSEGENTRY pSegEntry;
  134. if (strlen(szExePath) >= MAX_PATH16) {
  135. return FALSE;
  136. }
  137. pSegEntry = MALLOC(sizeof(SEGENTRY));
  138. if (pSegEntry == NULL) {
  139. return FALSE;
  140. }
  141. pSegEntry->Next = SegListHead.Next;
  142. SegListHead.Next = pSegEntry;
  143. pSegEntry->selector = selector;
  144. pSegEntry->segment = segment;
  145. pSegEntry->type = SEGTYPE_V86;
  146. strcpy( pSegEntry->szExePath, szExePath );
  147. ParseModuleName(pSegEntry->szModule, szExePath);
  148. pSegEntry->length = length;
  149. return TRUE;
  150. }
  151. //----------------------------------------------------------------------------
  152. // ModuleFree
  153. //
  154. // This routine removes all entries from the segment list that contain
  155. // the specified path name.
  156. //
  157. //----------------------------------------------------------------------------
  158. BOOL
  159. ModuleFree(
  160. LPSTR szExePath
  161. )
  162. {
  163. PSEGENTRY pSegEntry = SegListHead.Next;
  164. PSEGENTRY pSegPrev = &SegListHead;
  165. PSEGENTRY pSegTmp;
  166. BOOL fResult = FALSE;
  167. while (pSegEntry) {
  168. if ( _stricmp(pSegEntry->szExePath, szExePath) == 0 ) {
  169. pSegPrev->Next = pSegEntry->Next;
  170. pSegTmp = pSegEntry;
  171. pSegEntry = pSegTmp->Next;
  172. FREE(pSegTmp);
  173. fResult = TRUE;
  174. } else {
  175. pSegEntry = pSegEntry->Next;
  176. }
  177. }
  178. return fResult;
  179. }
  180. BOOL
  181. V86SegmentMove(
  182. WORD Selector,
  183. WORD segment,
  184. DWORD length,
  185. LPSTR szExePath
  186. )
  187. {
  188. PSEGENTRY pSegEntry = SegListHead.Next;
  189. PSEGENTRY pSegPrev = &SegListHead;
  190. //
  191. // first see if one exists already
  192. //
  193. pSegEntry = SegListHead.Next;
  194. while (pSegEntry) {
  195. if ((pSegEntry->type == SEGTYPE_V86) &&
  196. (pSegEntry->segment == segment)) {
  197. // Normal segmove, just update selector
  198. pSegEntry->selector = Selector;
  199. return TRUE;
  200. }
  201. pSegEntry = pSegEntry->Next;
  202. }
  203. //
  204. // An entry for this segment doesn't exist, so create one
  205. //
  206. ModuleLoad(Selector, segment, length, szExePath);
  207. //
  208. // Now delete segment zero for this module. This prevents
  209. // confusion in the symbol routines
  210. //
  211. pSegEntry = SegListHead.Next;
  212. pSegPrev = &SegListHead;
  213. while (pSegEntry) {
  214. if ((pSegEntry->type == SEGTYPE_V86) &&
  215. ( _stricmp(pSegEntry->szExePath, szExePath) == 0 ) &&
  216. (pSegEntry->segment == 0)) {
  217. // Unlink and free it
  218. pSegPrev->Next = pSegEntry->Next;
  219. FREE(pSegEntry);
  220. break;
  221. }
  222. pSegEntry = pSegEntry->Next;
  223. }
  224. return TRUE;
  225. }
  226. BOOL
  227. PMSegmentMove(
  228. WORD Selector1,
  229. WORD Selector2
  230. )
  231. {
  232. PSEGENTRY pSegEntry;
  233. if (!Selector2) {
  234. return (SegmentFree(Selector1));
  235. }
  236. // Look for the segment entry
  237. pSegEntry = SegListHead.Next;
  238. while (pSegEntry) {
  239. if ((pSegEntry->type == SEGTYPE_PROT) &&
  240. (pSegEntry->selector == Selector1)) {
  241. // Normal segmove, just update selector
  242. pSegEntry->selector = Selector2;
  243. return TRUE;
  244. }
  245. pSegEntry = pSegEntry->Next;
  246. }
  247. return FALSE;
  248. }
  249. //----------------------------------------------------------------------------
  250. // ProcessSegmentNotification
  251. //
  252. // This routine is the main entry point for the following debugger
  253. // notifications:
  254. // DBG_SEGLOAD
  255. // DBG_SEGFREE
  256. // DBG_SEGMOVE
  257. // DBG_MODLOAD
  258. // DBG_MODFREE
  259. //
  260. // It is called from VDMProcessException.
  261. //
  262. //----------------------------------------------------------------------------
  263. VOID
  264. ProcessSegmentNotification(
  265. LPDEBUG_EVENT lpDebugEvent
  266. )
  267. {
  268. BOOL b;
  269. DWORD lpNumberOfBytesRead;
  270. LPDWORD lpdw;
  271. SEGMENT_NOTE se;
  272. HANDLE hProcess;
  273. PSEGENTRY pSegEntry, pSegPrev;
  274. lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]);
  275. hProcess = OpenProcess( PROCESS_VM_READ, FALSE, lpDebugEvent->dwProcessId );
  276. if ( hProcess == HANDLE_NULL ) {
  277. return;
  278. }
  279. b = ReadProcessMemory(hProcess,
  280. (LPVOID)lpdw[2],
  281. &se,
  282. sizeof(se),
  283. &lpNumberOfBytesRead );
  284. if ( !b || lpNumberOfBytesRead != sizeof(se) ) {
  285. return;
  286. }
  287. switch(LOWORD(lpdw[0])) {
  288. case DBG_SEGLOAD:
  289. SegmentLoad(se.Selector1, se.Segment, se.FileName);
  290. break;
  291. case DBG_SEGMOVE:
  292. if (se.Type == SN_V86) {
  293. V86SegmentMove(se.Selector2, se.Segment, se.Length, se.FileName);
  294. } else {
  295. PMSegmentMove(se.Selector1, se.Selector2);
  296. }
  297. break;
  298. case DBG_SEGFREE:
  299. // Here, se.Type is a boolean to tell whether to restore
  300. // any breakpoints in the segment. That was done in the api
  301. // because wdeb386 didn't know how to move the breakpoint
  302. // definitions during a SEGMOVE. Currently, we ignore it, but
  303. // it would be nice to either support the flag, or better to
  304. // have ntsd update the breakpoints based on it.
  305. SegmentFree(se.Selector1);
  306. break;
  307. case DBG_MODFREE:
  308. ModuleFree(se.FileName);
  309. break;
  310. case DBG_MODLOAD:
  311. ModuleLoad(se.Selector1, 0, se.Length, se.FileName);
  312. break;
  313. }
  314. CloseHandle( hProcess );
  315. }
  316. void
  317. CopySegmentInfo(
  318. VDM_SEGINFO *si,
  319. PSEGENTRY pSegEntry
  320. )
  321. {
  322. si->Selector = pSegEntry->selector;
  323. si->SegNumber = pSegEntry->segment;
  324. si->Length = pSegEntry->length;
  325. si->Type = (pSegEntry->type == SEGTYPE_V86) ? 0 : 1;
  326. strcpy(si->ModuleName, pSegEntry->szModule);
  327. strcpy(si->FileName, pSegEntry->szExePath);
  328. }
  329. //----------------------------------------------------------------------------
  330. // VDMGetSegmentInfo
  331. //
  332. // This routine fills in a VDM_SEGINFO structure for the segment that matches
  333. // the specified parameters.
  334. // notifications:
  335. // DBG_SEGLOAD
  336. // DBG_SEGFREE
  337. // DBG_SEGMOVE
  338. // DBG_MODLOAD
  339. // DBG_MODFREE
  340. //
  341. // It is called from VDMProcessException.
  342. //
  343. //----------------------------------------------------------------------------
  344. BOOL
  345. WINAPI
  346. VDMGetSegmentInfo(
  347. WORD Selector,
  348. ULONG Offset,
  349. BOOL bProtectMode,
  350. VDM_SEGINFO *si
  351. )
  352. {
  353. PSEGENTRY pSegEntry = SegListHead.Next;
  354. PSEGENTRY pSegPrev = &SegListHead;
  355. int mode = bProtectMode ? SEGTYPE_PROT : SEGTYPE_V86;
  356. ULONG Base, BaseEnd, Target;
  357. while (pSegEntry) {
  358. if (pSegEntry->type == mode) {
  359. switch(mode) {
  360. case SEGTYPE_PROT:
  361. if (pSegEntry->selector == Selector) {
  362. CopySegmentInfo(si, pSegEntry);
  363. return TRUE;
  364. }
  365. break;
  366. case SEGTYPE_V86:
  367. Base = pSegEntry->selector << 4;
  368. BaseEnd = Base + pSegEntry->length;
  369. Target = (Selector << 4) + Offset;
  370. if ((Target >= Base) && (Target < BaseEnd)) {
  371. CopySegmentInfo(si, pSegEntry);
  372. return TRUE;
  373. }
  374. break;
  375. }
  376. }
  377. pSegEntry = pSegEntry->Next;
  378. }
  379. return FALSE;
  380. }
  381. BOOL
  382. GetInfoBySegmentNumber(
  383. LPSTR szModule,
  384. WORD SegNumber,
  385. VDM_SEGINFO *si
  386. )
  387. {
  388. PSEGENTRY pSegEntry = SegListHead.Next;
  389. PSEGENTRY pSegPrev = &SegListHead;
  390. ULONG Base, BaseEnd, Target;
  391. while (pSegEntry) {
  392. if (_stricmp(szModule, pSegEntry->szModule) == 0) {
  393. if (pSegEntry->segment == 0 || pSegEntry->segment == SegNumber) {
  394. CopySegmentInfo(si, pSegEntry);
  395. return TRUE;
  396. }
  397. }
  398. pSegEntry = pSegEntry->Next;
  399. }
  400. return FALSE;
  401. }
  402. BOOL
  403. EnumerateModulesForValue(
  404. BOOL (WINAPI *pfnEnumModuleProc)(LPSTR,LPSTR,PWORD,PDWORD,PWORD),
  405. LPSTR szSymbol,
  406. PWORD pSelector,
  407. PDWORD pOffset,
  408. PWORD pType
  409. )
  410. {
  411. PSEGENTRY pSegEntry = SegListHead.Next;
  412. PSEGENTRY pSegPrev = &SegListHead;
  413. ULONG Base, BaseEnd, Target;
  414. while (pSegEntry) {
  415. if (pSegEntry->szModule) {
  416. //
  417. // BUGBUG should optimize this so that it only calls
  418. // the enum proc once per module, instead of once per
  419. // segment
  420. //
  421. if ((*pfnEnumModuleProc)(pSegEntry->szModule,
  422. szSymbol,
  423. pSelector,
  424. pOffset,
  425. pType)) {
  426. return TRUE;
  427. }
  428. }
  429. pSegEntry = pSegEntry->Next;
  430. }
  431. return FALSE;
  432. }