Leaked source code of windows server 2003
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.

601 lines
14 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. mmap.cpp
  5. Abstract:
  6. Implementation of memory map class.
  7. Author:
  8. Matthew D Hendel (math) 16-Sep-1999
  9. Revision History:
  10. --*/
  11. #include "ntsdp.hpp"
  12. MappedMemoryMap::MappedMemoryMap(void)
  13. {
  14. m_RegionCount = 0;
  15. m_List = NULL;
  16. }
  17. MappedMemoryMap::~MappedMemoryMap(void)
  18. {
  19. PMEMORY_MAP_ENTRY Entry;
  20. PMEMORY_MAP_ENTRY Next;
  21. Entry = m_List;
  22. while ( Entry != NULL )
  23. {
  24. Next = Entry->Next;
  25. free ( Entry );
  26. Entry = Next;
  27. }
  28. }
  29. PMEMORY_MAP_ENTRY
  30. MappedMemoryMap::AddMapEntry(ULONG64 BaseOfRegion, ULONG SizeOfRegion,
  31. PVOID Buffer, PVOID UserData,
  32. BOOL AllowOverlap)
  33. {
  34. PMEMORY_MAP_ENTRY PrevEntry;
  35. PMEMORY_MAP_ENTRY MapEntry;
  36. MapEntry = (MEMORY_MAP_ENTRY *)malloc ( sizeof ( MEMORY_MAP_ENTRY ) );
  37. if (!MapEntry)
  38. {
  39. return NULL;
  40. }
  41. MapEntry->BaseOfRegion = BaseOfRegion;
  42. MapEntry->SizeOfRegion = SizeOfRegion;
  43. MapEntry->Region = Buffer;
  44. MapEntry->UserData = UserData;
  45. MapEntry->AllowOverlap = AllowOverlap;
  46. MapEntry->Next = NULL;
  47. //
  48. // Insert the element.
  49. //
  50. PrevEntry = FindPreceedingRegion(BaseOfRegion);
  51. if ( PrevEntry == NULL )
  52. {
  53. //
  54. // Insert at head.
  55. //
  56. MapEntry->Next = m_List;
  57. m_List = MapEntry;
  58. }
  59. else
  60. {
  61. //
  62. // Insert in order.
  63. //
  64. MapEntry->Next = PrevEntry->Next;
  65. PrevEntry->Next = MapEntry;
  66. }
  67. m_RegionCount++;
  68. return MapEntry;
  69. }
  70. HRESULT
  71. MappedMemoryMap::AddRegion(
  72. IN ULONG64 BaseOfRegion,
  73. IN ULONG SizeOfRegion,
  74. IN PVOID Buffer,
  75. IN PVOID UserData,
  76. IN BOOL AllowOverlap
  77. )
  78. {
  79. //
  80. // The region size cannot be zero.
  81. //
  82. if (SizeOfRegion == 0)
  83. {
  84. ErrOut("**** MappedMemoryMap::AddRegion: Empty region being added.\n");
  85. return S_OK;
  86. }
  87. if (IsBadReadPtr(Buffer, SizeOfRegion))
  88. {
  89. ErrOut("**** MappedMemoryMap::AddRegion: Mapping too small to map "
  90. "%s:%X from %p\n", FormatAddr64(BaseOfRegion),
  91. SizeOfRegion, Buffer);
  92. return E_INVALIDARG;
  93. }
  94. ULONG64 EndOfRegion;
  95. PMEMORY_MAP_ENTRY Entry;
  96. ULONG Size;
  97. while (SizeOfRegion > 0)
  98. {
  99. //
  100. // Find the first overlapping region.
  101. // We need to rescan the whole list as it
  102. // may have changed due to insertion of fragments
  103. // of the new region.
  104. //
  105. EndOfRegion = BaseOfRegion + SizeOfRegion;
  106. for (Entry = m_List; Entry != NULL; Entry = Entry->Next)
  107. {
  108. if (EndOfRegion > Entry->BaseOfRegion &&
  109. Entry->BaseOfRegion >= BaseOfRegion)
  110. {
  111. if (AllowOverlap || Entry->AllowOverlap)
  112. {
  113. // Overlap can occur when a stack, ethread or
  114. // eprocess is taken from static data in an image.
  115. // For example, the x86 idle process is static
  116. // data in ntoskrnl. Triage dumps contain the
  117. // eprocess data and it gets mapped and can overlap
  118. // with the ntoskrnl image.
  119. #if 0
  120. WarnOut("WARNING: Allowing overlapped region %s - %s\n",
  121. FormatAddr64(BaseOfRegion),
  122. FormatAddr64(BaseOfRegion + SizeOfRegion - 1));
  123. #endif
  124. Entry = NULL;
  125. }
  126. break;
  127. }
  128. }
  129. if (Entry == NULL ||
  130. BaseOfRegion < Entry->BaseOfRegion)
  131. {
  132. // There's a portion of the beginning of the new
  133. // region which does not overlap so add it and
  134. // trim the description.
  135. Size = Entry == NULL ? SizeOfRegion :
  136. (ULONG)(Entry->BaseOfRegion - BaseOfRegion);
  137. if (!AddMapEntry(BaseOfRegion, Size, Buffer, UserData,
  138. AllowOverlap))
  139. {
  140. return E_OUTOFMEMORY;
  141. }
  142. if (Size == SizeOfRegion)
  143. {
  144. // None of the region overlapped so we're done.
  145. return S_OK;
  146. }
  147. BaseOfRegion += Size;
  148. SizeOfRegion -= Size;
  149. Buffer = (PUCHAR)Buffer + Size;
  150. }
  151. //
  152. // Now handle the overlap.
  153. //
  154. if (SizeOfRegion > Entry->SizeOfRegion)
  155. {
  156. Size = Entry->SizeOfRegion;
  157. }
  158. else
  159. {
  160. Size = SizeOfRegion;
  161. }
  162. int Compare;
  163. __try
  164. {
  165. Compare = memcmp(Buffer, Entry->Region, Size);
  166. }
  167. __except(MappingExceptionFilter(GetExceptionInformation()))
  168. {
  169. return HRESULT_FROM_NT(GetExceptionCode());
  170. }
  171. if (Compare)
  172. {
  173. ErrOut("**** MappedMemoryMap::AddRegion: "
  174. "Conflicting region %s - %s\n",
  175. FormatAddr64(BaseOfRegion),
  176. FormatAddr64(BaseOfRegion + SizeOfRegion - 1));
  177. return HR_REGION_CONFLICT;
  178. }
  179. // Overlap region data matched so it's OK to just
  180. // trim the overlap out of the new region and move
  181. // on to the next possible overlap.
  182. BaseOfRegion += Size;
  183. SizeOfRegion -= Size;
  184. Buffer = (PUCHAR)Buffer + Size;
  185. }
  186. return S_OK;
  187. }
  188. BOOL
  189. MappedMemoryMap::ReadMemory(
  190. IN ULONG64 BaseOfRange,
  191. IN OUT PVOID Buffer,
  192. IN ULONG SizeOfRange,
  193. OUT ULONG * BytesRead
  194. )
  195. /*++
  196. Routine Description:
  197. Read memory from the memory map. ReadMemory can read across regions, as
  198. long as there is no unallocated space between regions.
  199. This routine will do a partial read if the region ends before
  200. SizeOfRange bytes have been read. In that case BytesRead will return the
  201. number of bytes actually read.
  202. Arguments:
  203. BaseOfRange - The base address where we want to read memory from.
  204. SizeOfRange - The length of the region to read memory from.
  205. Buffer - A pointer to a buffer to read memory into.
  206. BytesRead - On success, the number of bytes successfully read.
  207. Return Values:
  208. TRUE - If any number of bytes were successfully read from the memory map.
  209. FALSE - If no bytes were read.
  210. --*/
  211. {
  212. ULONG BytesToReadFromRegion;
  213. PMEMORY_MAP_ENTRY Entry;
  214. ULONG64 BaseToRead;
  215. ULONG SizeToRead;
  216. PBYTE BufferForRead;
  217. ULONG_PTR OffsetToRead;
  218. ULONG AvailSize;
  219. //
  220. // We return TRUE if we read any bytes successfully and FALSE if not.
  221. //
  222. *BytesRead = 0;
  223. BaseToRead = BaseOfRange;
  224. SizeToRead = SizeOfRange;
  225. BufferForRead = (PBYTE) Buffer;
  226. do
  227. {
  228. Entry = FindContainingRegion(BaseToRead);
  229. if ( !Entry )
  230. {
  231. if (*BytesRead)
  232. {
  233. return TRUE;
  234. }
  235. else
  236. {
  237. return FALSE;
  238. }
  239. }
  240. PMEMORY_MAP_ENTRY NextEntry = Entry->Next;
  241. // Due to overlap there may be other entries
  242. // that need to be processed even before the
  243. // end of the containing region.
  244. AvailSize = Entry->SizeOfRegion;
  245. while (NextEntry != NULL)
  246. {
  247. if (NextEntry->BaseOfRegion > BaseToRead)
  248. {
  249. ULONG64 EntryDiff =
  250. NextEntry->BaseOfRegion - Entry->BaseOfRegion;
  251. if (EntryDiff < AvailSize)
  252. {
  253. AvailSize = (ULONG)EntryDiff;
  254. }
  255. break;
  256. }
  257. NextEntry = NextEntry->Next;
  258. }
  259. if (BaseToRead + SizeToRead > Entry->BaseOfRegion + AvailSize)
  260. {
  261. BytesToReadFromRegion = (ULONG)
  262. (Entry->BaseOfRegion - BaseToRead) + AvailSize;
  263. }
  264. else
  265. {
  266. BytesToReadFromRegion = SizeToRead;
  267. }
  268. OffsetToRead = (ULONG_PTR) (BaseToRead - Entry->BaseOfRegion);
  269. __try
  270. {
  271. RtlCopyMemory (BufferForRead,
  272. (PBYTE)Entry->Region + OffsetToRead,
  273. BytesToReadFromRegion
  274. );
  275. }
  276. __except(MappingExceptionFilter(GetExceptionInformation()))
  277. {
  278. return FALSE;
  279. }
  280. *BytesRead += BytesToReadFromRegion;
  281. BaseToRead += BytesToReadFromRegion;
  282. SizeToRead -= BytesToReadFromRegion;
  283. BufferForRead += BytesToReadFromRegion;
  284. } while ( SizeToRead );
  285. return TRUE;
  286. }
  287. BOOL
  288. MappedMemoryMap::GetRegionInfo(
  289. IN ULONG64 Addr,
  290. OUT ULONG64* BaseOfRegion, OPTIONAL
  291. OUT ULONG* SizeOfRegion, OPTIONAL
  292. OUT PVOID* Buffer, OPTIONAL
  293. OUT PVOID* UserData OPTIONAL
  294. )
  295. /*++
  296. Routine Description:
  297. Get information about the region containing the address Addr.
  298. Arguments:
  299. Addr - An address that is contained within some region in the map.
  300. BaseOfRegion - Pointer to a buffer to return the region base.
  301. SizeOfRegion - Pointer to a buffer to retutn the region size.
  302. Buffer - Pointer to a buffer to return the region buffer pointer.
  303. UserData - Pointer to a buffer to return the region client param.
  304. Return Values:
  305. TRUE - On success.
  306. FALSE - On failure.
  307. --*/
  308. {
  309. PMEMORY_MAP_ENTRY Entry;
  310. Entry = FindContainingRegion(Addr);
  311. if ( !Entry )
  312. {
  313. return FALSE;
  314. }
  315. if ( BaseOfRegion )
  316. {
  317. *BaseOfRegion = Entry->BaseOfRegion;
  318. }
  319. if ( SizeOfRegion )
  320. {
  321. *SizeOfRegion = Entry->SizeOfRegion;
  322. }
  323. if ( Buffer )
  324. {
  325. *Buffer = Entry->Region;
  326. }
  327. if ( UserData )
  328. {
  329. *UserData = Entry->UserData;
  330. }
  331. return TRUE;
  332. }
  333. BOOL
  334. MappedMemoryMap::GetNextRegion(
  335. IN ULONG64 Addr,
  336. OUT PULONG64 Next
  337. )
  338. {
  339. PMEMORY_MAP_ENTRY Entry;
  340. Entry = m_List;
  341. while (Entry != NULL)
  342. {
  343. //
  344. // Assuming they're in order.
  345. //
  346. if (Entry->BaseOfRegion > Addr)
  347. {
  348. *Next = Entry->BaseOfRegion;
  349. return TRUE;
  350. }
  351. Entry = Entry->Next;
  352. }
  353. return FALSE;
  354. }
  355. BOOL
  356. MappedMemoryMap::RemoveRegion(
  357. IN ULONG64 BaseOfRegion,
  358. IN ULONG SizeOfRegion
  359. )
  360. {
  361. // XXX drewb - This should carve the given region out of
  362. // any existing regions. Right now we don't need general
  363. // removal functionality though so only handle the case
  364. // where the requested removal is an exact single region
  365. // match.
  366. PMEMORY_MAP_ENTRY PrevEntry;
  367. PMEMORY_MAP_ENTRY Entry;
  368. PrevEntry = FindPreceedingRegion(BaseOfRegion);
  369. if (PrevEntry != NULL)
  370. {
  371. Entry = PrevEntry->Next;
  372. }
  373. else
  374. {
  375. Entry = m_List;
  376. }
  377. if (Entry == NULL)
  378. {
  379. ErrOut("MappedMemoryMap::RemoveRegion NULL region for %s:%x\n",
  380. FormatAddr64(BaseOfRegion), SizeOfRegion);
  381. return FALSE;
  382. }
  383. else if (Entry->BaseOfRegion != BaseOfRegion ||
  384. Entry->SizeOfRegion != SizeOfRegion)
  385. {
  386. ErrOut("MappedMemoryMap::RemoveRegion region mismatch: "
  387. "%s:%x vs. entry %s:%x\n",
  388. FormatAddr64(BaseOfRegion), SizeOfRegion,
  389. FormatAddr64(Entry->BaseOfRegion), Entry->SizeOfRegion);
  390. return FALSE;
  391. }
  392. if (PrevEntry == NULL)
  393. {
  394. m_List = Entry->Next;
  395. }
  396. else
  397. {
  398. PrevEntry->Next = Entry->Next;
  399. }
  400. free(Entry);
  401. m_RegionCount--;
  402. return TRUE;
  403. }
  404. BOOL
  405. MappedMemoryMap::GetRegionByUserData(
  406. IN PVOID UserData,
  407. OUT PULONG64 Base,
  408. OUT PULONG Size
  409. )
  410. {
  411. PMEMORY_MAP_ENTRY Entry;
  412. Entry = m_List;
  413. while (Entry != NULL)
  414. {
  415. if (Entry->UserData == UserData)
  416. {
  417. *Base = Entry->BaseOfRegion;
  418. *Size = Entry->SizeOfRegion;
  419. return TRUE;
  420. }
  421. Entry = Entry->Next;
  422. }
  423. return FALSE;
  424. }
  425. //
  426. // Private functions
  427. //
  428. PMEMORY_MAP_ENTRY
  429. MappedMemoryMap::FindPreceedingRegion(
  430. IN ULONG64 BaseOfRegion
  431. )
  432. {
  433. PMEMORY_MAP_ENTRY PrevEntry;
  434. PMEMORY_MAP_ENTRY Entry;
  435. PrevEntry = NULL;
  436. Entry = m_List;
  437. while (Entry != NULL)
  438. {
  439. //
  440. // Assuming they're in order.
  441. //
  442. if ( Entry->BaseOfRegion >= BaseOfRegion )
  443. {
  444. return PrevEntry;
  445. }
  446. PrevEntry = Entry;
  447. Entry = Entry->Next;
  448. }
  449. return PrevEntry;
  450. }
  451. PMEMORY_MAP_ENTRY
  452. MappedMemoryMap::FindContainingRegion(
  453. IN ULONG64 Addr
  454. )
  455. {
  456. PMEMORY_MAP_ENTRY Entry;
  457. PMEMORY_MAP_ENTRY ReturnEntry = NULL;
  458. Entry = m_List;
  459. //
  460. // We may have overlapping regions, so keep going until we find
  461. // the most precise one (assumed to be the one we care about)
  462. //
  463. while ( Entry != NULL )
  464. {
  465. if ( Entry->BaseOfRegion <= Addr &&
  466. Addr < Entry->BaseOfRegion + Entry->SizeOfRegion)
  467. {
  468. ReturnEntry = Entry;
  469. }
  470. else if (ReturnEntry != NULL &&
  471. Addr >= ReturnEntry->BaseOfRegion + ReturnEntry->SizeOfRegion)
  472. {
  473. // Optimization - we can stop searching if we've already
  474. // found a block and have now left its region. We can't
  475. // stop as long as we're in its region as there may
  476. // be more exact overlaps anywhere within the entire region.
  477. break;
  478. }
  479. Entry = Entry->Next;
  480. }
  481. return ReturnEntry;
  482. }