1 // PE/COFF-specific support for sections. 2 // Copyright (C) 2021-2022 Free Software Foundation, Inc. 3 4 // GCC is free software; you can redistribute it and/or modify it under 5 // the terms of the GNU General Public License as published by the Free 6 // Software Foundation; either version 3, or (at your option) any later 7 // version. 8 9 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY 10 // WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 // for more details. 13 14 // Under Section 7 of GPL version 3, you are granted additional 15 // permissions described in the GCC Runtime Library Exception, version 16 // 3.1, as published by the Free Software Foundation. 17 18 // You should have received a copy of the GNU General Public License and 19 // a copy of the GCC Runtime Library Exception along with this program; 20 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21 // <http://www.gnu.org/licenses/>. 22 23 module gcc.sections.pecoff; 24 25 version (Windows): 26 27 import core.memory; 28 import core.stdc.stdlib; 29 import core.sys.windows.winbase; 30 import core.sys.windows.windef; 31 import core.sys.windows.winnt; 32 import rt.minfo; 33 import core.internal.container.array; 34 import core.internal.container.hashtab; 35 import gcc.sections.common; 36 37 version (GNU_EMUTLS) 38 import gcc.emutls; 39 40 alias DSO SectionGroup; 41 struct DSO 42 { 43 static int opApply(scope int delegate(ref DSO) dg) 44 { 45 foreach (dso; _loadedDSOs) 46 { 47 if (auto res = dg(*dso)) 48 return res; 49 } 50 return 0; 51 } 52 53 static int opApplyReverse(scope int delegate(ref DSO) dg) 54 { 55 foreach_reverse (dso; _loadedDSOs) 56 { 57 if (auto res = dg(*dso)) 58 return res; 59 } 60 return 0; 61 } 62 63 @property immutable(ModuleInfo*)[] modules() const nothrow @nogc 64 { 65 return _moduleGroup.modules; 66 } 67 68 @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc 69 { 70 return _moduleGroup; 71 } 72 73 @property inout(void[])[] gcRanges() inout nothrow @nogc 74 { 75 return _gcRanges[]; 76 } 77 78 private: 79 80 invariant() 81 { 82 safeAssert(_moduleGroup.modules.length > 0, "No modules for DSO."); 83 } 84 85 void** _slot; 86 ModuleGroup _moduleGroup; 87 Array!(void[]) _gcRanges; 88 89 version (Shared) 90 { 91 Array!(void[]) _codeSegments; // array of code segments 92 Array!(DSO*) _deps; // D libraries needed by this DSO 93 void* _handle; // corresponding handle 94 } 95 } 96 97 /**** 98 * Boolean flag set to true while the runtime is initialized. 99 */ 100 __gshared bool _isRuntimeInitialized; 101 102 /**** 103 * Gets called on program startup just before GC is initialized. 104 */ 105 void initSections() nothrow @nogc 106 { 107 _isRuntimeInitialized = true; 108 } 109 110 /*** 111 * Gets called on program shutdown just after GC is terminated. 112 */ 113 void finiSections() nothrow @nogc 114 { 115 _isRuntimeInitialized = false; 116 } 117 118 alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; 119 120 version (Shared) 121 { 122 import gcc.sections : pinLoadedLibraries, unpinLoadedLibraries, 123 inheritLoadedLibraries, cleanupLoadedLibraries; 124 125 /*** 126 * Called once per thread; returns array of thread local storage ranges 127 */ 128 Array!(ThreadDSO)* initTLSRanges() @nogc nothrow 129 { 130 return &_loadedDSOs(); 131 } 132 133 void finiTLSRanges(Array!(ThreadDSO)* tdsos) @nogc nothrow 134 { 135 // Nothing to do here. tdsos used to point to the _loadedDSOs instance 136 // in the dying thread's TLS segment and as such is not valid anymore. 137 // The memory for the array contents was already reclaimed in 138 // cleanupLoadedLibraries(). 139 } 140 141 void scanTLSRanges(Array!(ThreadDSO)* tdsos, scope ScanDG dg) nothrow 142 { 143 version (GNU_EMUTLS) 144 _d_emutls_scan(dg); 145 else 146 static assert(0, "Native TLS unimplemented"); 147 } 148 149 // interface for core.thread to inherit loaded libraries 150 pragma(mangle, gcc.sections.pinLoadedLibraries.mangleof) 151 void* pinLoadedLibraries() nothrow @nogc 152 { 153 auto res = cast(Array!(ThreadDSO)*)calloc(1, Array!(ThreadDSO).sizeof); 154 res.length = _loadedDSOs.length; 155 foreach (i, ref tdso; _loadedDSOs) 156 { 157 (*res)[i] = tdso; 158 if (tdso._addCnt) 159 { 160 // Increment the DLL ref for explicitly loaded libraries to pin them. 161 char[MAX_PATH] buf; 162 char[] buffer = buf[]; 163 const success = .LoadLibraryA(nameForDSO(tdso._pdso, buffer)) !is null; 164 safeAssert(success, "Failed to increment DLL ref."); 165 (*res)[i]._addCnt = 1; // new array takes over the additional ref count 166 } 167 } 168 return res; 169 } 170 171 pragma(mangle, gcc.sections.unpinLoadedLibraries.mangleof) 172 void unpinLoadedLibraries(void* p) nothrow @nogc 173 { 174 auto pary = cast(Array!(ThreadDSO)*)p; 175 // In case something failed we need to undo the pinning. 176 foreach (ref tdso; *pary) 177 { 178 if (tdso._addCnt) 179 { 180 auto handle = tdso._pdso._handle; 181 safeAssert(handle !is null, "Invalid library handle."); 182 .FreeLibrary(handle); 183 } 184 } 185 pary.reset(); 186 .free(pary); 187 } 188 189 // Called before TLS ctors are ran, copy over the loaded libraries 190 // of the parent thread. 191 pragma(mangle, gcc.sections.inheritLoadedLibraries.mangleof) 192 void inheritLoadedLibraries(void* p) nothrow @nogc 193 { 194 safeAssert(_loadedDSOs.empty, "DSOs have already been registered for this thread."); 195 _loadedDSOs.swap(*cast(Array!(ThreadDSO)*)p); 196 .free(p); 197 } 198 199 // Called after all TLS dtors ran, decrements all remaining DLL refs. 200 pragma(mangle, gcc.sections.cleanupLoadedLibraries.mangleof) 201 void cleanupLoadedLibraries() nothrow @nogc 202 { 203 foreach (ref tdso; _loadedDSOs) 204 { 205 if (tdso._addCnt == 0) continue; 206 207 auto handle = tdso._pdso._handle; 208 safeAssert(handle !is null, "Invalid DSO handle."); 209 for (; tdso._addCnt > 0; --tdso._addCnt) 210 .FreeLibrary(handle); 211 } 212 213 // Free the memory for the array contents. 214 _loadedDSOs.reset(); 215 } 216 } 217 else 218 { 219 /*** 220 * Called once per thread; returns array of thread local storage ranges 221 */ 222 Array!(void[])* initTLSRanges() nothrow @nogc 223 { 224 return null; 225 } 226 227 void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc 228 { 229 } 230 231 void scanTLSRanges(Array!(void[])* rngs, scope ScanDG dg) nothrow 232 { 233 version (GNU_EMUTLS) 234 _d_emutls_scan(dg); 235 else 236 static assert(0, "Native TLS unimplemented"); 237 } 238 } 239 240 private: 241 242 version (Shared) 243 { 244 /* 245 * Array of thread local DSO metadata for all libraries loaded and 246 * initialized in this thread. 247 * 248 * Note: 249 * A newly spawned thread will inherit these libraries. 250 * Note: 251 * We use an array here to preserve the order of 252 * initialization. If that became a performance issue, we 253 * could use a hash table and enumerate the DSOs during 254 * loading so that the hash table values could be sorted when 255 * necessary. 256 */ 257 struct ThreadDSO 258 { 259 DSO* _pdso; 260 static if (_pdso.sizeof == 8) uint _refCnt, _addCnt; 261 else static if (_pdso.sizeof == 4) ushort _refCnt, _addCnt; 262 else static assert(0, "unimplemented"); 263 alias _pdso this; 264 } 265 266 @property ref Array!(ThreadDSO) _loadedDSOs() @nogc nothrow 267 { 268 static Array!(ThreadDSO) x; 269 return x; 270 } 271 272 /* 273 * Set to true during rt_loadLibrary/rt_unloadLibrary calls. 274 */ 275 bool _rtLoading; 276 277 /* 278 * Hash table to map the native handle (as returned by dlopen) 279 * to the corresponding DSO*, protected by a mutex. 280 */ 281 __gshared CRITICAL_SECTION _handleToDSOMutex; 282 @property ref HashTab!(void*, DSO*) _handleToDSO() @nogc nothrow 283 { 284 __gshared HashTab!(void*, DSO*) x; 285 return x; 286 } 287 } 288 else 289 { 290 /* 291 * Static DSOs loaded by the runtime linker. This includes the 292 * executable. These can't be unloaded. 293 */ 294 @property ref Array!(DSO*) _loadedDSOs() @nogc nothrow 295 { 296 __gshared Array!(DSO*) x; 297 return x; 298 } 299 300 enum _rtLoading = false; 301 } 302 303 /////////////////////////////////////////////////////////////////////////////// 304 // Compiler to runtime interface. 305 /////////////////////////////////////////////////////////////////////////////// 306 307 /**** 308 * This data structure is generated by the compiler, and then passed to 309 * _d_dso_registry(). 310 */ 311 struct CompilerDSOData 312 { 313 size_t _version; // currently 1 314 void** _slot; // can be used to store runtime data 315 immutable(object.ModuleInfo*)* _minfo_beg, _minfo_end; // array of modules in this object file 316 } 317 318 T[] toRange(T)(T* beg, T* end) { return beg[0 .. end - beg]; } 319 320 /* For each shared library and executable, the compiler generates code that 321 * sets up CompilerDSOData and calls _d_dso_registry(). 322 * A pointer to that code is inserted into both the .ctors and .dtors 323 * segment so it gets called by the loader on startup and shutdown. 324 */ 325 extern(C) void _d_dso_registry(CompilerDSOData* data) 326 { 327 // only one supported currently 328 safeAssert(data._version >= 1, "Incompatible compiler-generated DSO data version."); 329 330 // no backlink => register 331 if (*data._slot is null) 332 { 333 immutable firstDSO = _loadedDSOs.empty; 334 if (firstDSO) initLocks(); 335 336 DSO* pdso = cast(DSO*).calloc(1, DSO.sizeof); 337 assert(typeid(DSO).initializer().ptr is null); 338 pdso._slot = data._slot; 339 *data._slot = pdso; // store backlink in library record 340 341 pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end)); 342 343 HMODULE handle = void; 344 const moduleFound = findModuleHandleForAddr(data._slot, handle); 345 safeAssert(moduleFound, "Failed to find image header."); 346 347 scanSegments(handle, pdso); 348 349 version (Shared) 350 { 351 getDependencies(handle, pdso._deps); 352 pdso._handle = handle; 353 setDSOForHandle(pdso, pdso._handle); 354 355 if (!_rtLoading) 356 { 357 /* This DSO was not loaded by rt_loadLibrary which 358 * happens for all dependencies of an executable or 359 * the first dlopen call from a C program. 360 * In this case we add the DSO to the _loadedDSOs of this 361 * thread with a refCnt of 1 and call the TlsCtors. 362 */ 363 immutable ushort refCnt = 1, addCnt = 0; 364 _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt)); 365 } 366 } 367 else 368 { 369 foreach (p; _loadedDSOs) 370 safeAssert(p !is pdso, "DSO already registered."); 371 _loadedDSOs.insertBack(pdso); 372 } 373 374 // don't initialize modules before rt_init was called 375 if (_isRuntimeInitialized) 376 { 377 registerGCRanges(pdso); 378 // rt_loadLibrary will run tls ctors, so do this only for dlopen 379 immutable runTlsCtors = !_rtLoading; 380 runModuleConstructors(pdso, runTlsCtors); 381 } 382 } 383 // has backlink => unregister 384 else 385 { 386 DSO* pdso = cast(DSO*)*data._slot; 387 *data._slot = null; 388 389 // don't finalizes modules after rt_term was called (see Bugzilla 11378) 390 if (_isRuntimeInitialized) 391 { 392 // rt_unloadLibrary already ran tls dtors, so do this only for dlclose 393 immutable runTlsDtors = !_rtLoading; 394 runModuleDestructors(pdso, runTlsDtors); 395 unregisterGCRanges(pdso); 396 // run finalizers after module dtors (same order as in rt_term) 397 version (Shared) runFinalizers(pdso); 398 } 399 400 version (Shared) 401 { 402 if (!_rtLoading) 403 { 404 /* This DSO was not unloaded by rt_unloadLibrary so we 405 * have to remove it from _loadedDSOs here. 406 */ 407 foreach (i, ref tdso; _loadedDSOs) 408 { 409 if (tdso._pdso == pdso) 410 { 411 _loadedDSOs.remove(i); 412 break; 413 } 414 } 415 } 416 417 unsetDSOForHandle(pdso, pdso._handle); 418 } 419 else 420 { 421 // static DSOs are unloaded in reverse order 422 safeAssert(pdso == _loadedDSOs.back, "DSO being unregistered isn't current last one."); 423 _loadedDSOs.popBack(); 424 } 425 426 freeDSO(pdso); 427 428 // last DSO being unloaded => shutdown registry 429 if (_loadedDSOs.empty) 430 { 431 version (GNU_EMUTLS) 432 _d_emutls_destroy(); 433 version (Shared) 434 { 435 safeAssert(_handleToDSO.empty, "_handleToDSO not in sync with _loadedDSOs."); 436 _handleToDSO.reset(); 437 } 438 finiLocks(); 439 } 440 } 441 } 442 443 /////////////////////////////////////////////////////////////////////////////// 444 // dynamic loading 445 /////////////////////////////////////////////////////////////////////////////// 446 447 // Shared D libraries are only supported when linking against a shared druntime library. 448 449 version (Shared) 450 { 451 ThreadDSO* findThreadDSO(DSO* pdso) nothrow @nogc 452 { 453 foreach (ref tdata; _loadedDSOs) 454 if (tdata._pdso == pdso) return &tdata; 455 return null; 456 } 457 458 void incThreadRef(DSO* pdso, bool incAdd) 459 { 460 if (auto tdata = findThreadDSO(pdso)) // already initialized 461 { 462 if (incAdd && ++tdata._addCnt > 1) return; 463 ++tdata._refCnt; 464 } 465 else 466 { 467 foreach (dep; pdso._deps) 468 incThreadRef(dep, false); 469 immutable ushort refCnt = 1, addCnt = incAdd ? 1 : 0; 470 _loadedDSOs.insertBack(ThreadDSO(pdso, refCnt, addCnt)); 471 pdso._moduleGroup.runTlsCtors(); 472 } 473 } 474 475 void decThreadRef(DSO* pdso, bool decAdd) 476 { 477 auto tdata = findThreadDSO(pdso); 478 safeAssert(tdata !is null, "Failed to find thread DSO."); 479 safeAssert(!decAdd || tdata._addCnt > 0, "Mismatching rt_unloadLibrary call."); 480 481 if (decAdd && --tdata._addCnt > 0) return; 482 if (--tdata._refCnt > 0) return; 483 484 pdso._moduleGroup.runTlsDtors(); 485 foreach (i, ref td; _loadedDSOs) 486 if (td._pdso == pdso) _loadedDSOs.remove(i); 487 foreach (dep; pdso._deps) 488 decThreadRef(dep, false); 489 } 490 } 491 492 /*********************************** 493 * These are a temporary means of providing a GC hook for DLL use. They may be 494 * replaced with some other similar functionality later. 495 */ 496 extern (C) 497 { 498 void* gc_getProxy(); 499 void gc_setProxy(void* p); 500 void gc_clrProxy(); 501 502 alias void function(void*) gcSetFn; 503 alias void function() gcClrFn; 504 } 505 506 /******************************************* 507 * Loads a DLL written in D with the name 'name'. 508 * Returns: 509 * opaque handle to the DLL if successfully loaded 510 * null if failure 511 */ 512 extern(C) void* rt_loadLibrary(const char* name) 513 { 514 version (Shared) 515 { 516 immutable save = _rtLoading; 517 _rtLoading = true; 518 scope (exit) _rtLoading = save; 519 } 520 return initLibrary(.LoadLibraryA(name)); 521 } 522 523 extern (C) void* rt_loadLibraryW(const wchar_t* name) 524 { 525 version (Shared) 526 { 527 immutable save = _rtLoading; 528 _rtLoading = true; 529 scope (exit) _rtLoading = save; 530 } 531 return initLibrary(.LoadLibraryW(name)); 532 } 533 534 void* initLibrary(void* handle) 535 { 536 if (handle is null) 537 return null; 538 539 version (Shared) 540 { 541 // if it's a D library 542 if (auto pdso = dsoForHandle(handle)) 543 incThreadRef(pdso, true); 544 } 545 gcSetFn gcSet = cast(gcSetFn) GetProcAddress(handle, "gc_setProxy"); 546 if (gcSet !is null) 547 { 548 // BUG: Set proxy, but too late 549 gcSet(gc_getProxy()); 550 } 551 return handle; 552 } 553 554 /************************************* 555 * Unloads DLL that was previously loaded by rt_loadLibrary(). 556 * Input: 557 * handle the handle returned by rt_loadLibrary() 558 * Returns: 559 * 1 succeeded 560 * 0 some failure happened 561 */ 562 extern(C) int rt_unloadLibrary(void* handle) 563 { 564 if (handle is null) 565 return false; 566 567 version (Shared) 568 { 569 immutable save = _rtLoading; 570 _rtLoading = true; 571 scope (exit) _rtLoading = save; 572 573 // if it's a D library 574 if (auto pdso = dsoForHandle(handle)) 575 decThreadRef(pdso, true); 576 } 577 gcClrFn gcClr = cast(gcClrFn) GetProcAddress(handle, "gc_clrProxy"); 578 if (gcClr !is null) 579 gcClr(); 580 return .FreeLibrary(handle) != 0; 581 } 582 583 /////////////////////////////////////////////////////////////////////////////// 584 // helper functions 585 /////////////////////////////////////////////////////////////////////////////// 586 587 void initLocks() nothrow @nogc 588 { 589 version (Shared) 590 InitializeCriticalSection(&_handleToDSOMutex); 591 } 592 593 void finiLocks() nothrow @nogc 594 { 595 version (Shared) 596 DeleteCriticalSection(&_handleToDSOMutex); 597 } 598 599 void runModuleConstructors(DSO* pdso, bool runTlsCtors) 600 { 601 pdso._moduleGroup.sortCtors(); 602 pdso._moduleGroup.runCtors(); 603 if (runTlsCtors) pdso._moduleGroup.runTlsCtors(); 604 } 605 606 void runModuleDestructors(DSO* pdso, bool runTlsDtors) 607 { 608 if (runTlsDtors) pdso._moduleGroup.runTlsDtors(); 609 pdso._moduleGroup.runDtors(); 610 } 611 612 void registerGCRanges(DSO* pdso) nothrow @nogc 613 { 614 foreach (rng; pdso._gcRanges) 615 GC.addRange(rng.ptr, rng.length); 616 } 617 618 void unregisterGCRanges(DSO* pdso) nothrow @nogc 619 { 620 foreach (rng; pdso._gcRanges) 621 GC.removeRange(rng.ptr); 622 } 623 624 version (Shared) void runFinalizers(DSO* pdso) 625 { 626 foreach (seg; pdso._codeSegments) 627 GC.runFinalizers(seg); 628 } 629 630 void freeDSO(DSO* pdso) nothrow @nogc 631 { 632 pdso._gcRanges.reset(); 633 version (Shared) 634 { 635 pdso._codeSegments.reset(); 636 pdso._deps.reset(); 637 pdso._handle = null; 638 } 639 .free(pdso); 640 } 641 642 version (Shared) 643 { 644 @nogc nothrow: 645 const(char)* nameForDSO(DSO* pdso, ref char[] buffer) 646 { 647 const success = GetModuleFileNameA(pdso._handle, buffer.ptr, cast(DWORD)buffer.length) != 0; 648 safeAssert(success, "Failed to get DLL name."); 649 return buffer.ptr; 650 } 651 652 DSO* dsoForHandle(in void* handle) 653 { 654 DSO* pdso; 655 .EnterCriticalSection(&_handleToDSOMutex); 656 if (auto ppdso = handle in _handleToDSO) 657 pdso = *ppdso; 658 .LeaveCriticalSection(&_handleToDSOMutex); 659 return pdso; 660 } 661 662 void setDSOForHandle(DSO* pdso, void* handle) 663 { 664 .EnterCriticalSection(&_handleToDSOMutex); 665 safeAssert(handle !in _handleToDSO, "DSO already registered."); 666 _handleToDSO[handle] = pdso; 667 .LeaveCriticalSection(&_handleToDSOMutex); 668 } 669 670 void unsetDSOForHandle(DSO* pdso, void* handle) 671 { 672 .EnterCriticalSection(&_handleToDSOMutex); 673 safeAssert(_handleToDSO[handle] == pdso, "Handle doesn't match registered DSO."); 674 _handleToDSO.remove(handle); 675 .LeaveCriticalSection(&_handleToDSOMutex); 676 } 677 678 void getDependencies(in HMODULE handle, ref Array!(DSO*) deps) 679 { 680 auto nthdr = getNTHeader(handle); 681 auto import_entry = nthdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 682 auto addr = import_entry.VirtualAddress; 683 auto datasize = import_entry.Size; 684 685 if (addr == 0 && datasize == 0) 686 { 687 // Maybe the optional header isn't there, look for the section. 688 foreach (section; getSectionHeader(handle)) 689 { 690 if (!compareSectionName(section, ".idata")) 691 continue; 692 addr = section.VirtualAddress; 693 datasize = section.Misc.VirtualSize; 694 break; 695 } 696 if (datasize == 0) 697 return; 698 } 699 else 700 { 701 bool foundSection = false; 702 foreach (section; getSectionHeader(handle)) 703 { 704 if (!compareSectionName(section, ".idata")) 705 continue; 706 // Section containing import table has no contents. 707 if (section.Misc.VirtualSize == 0) 708 return; 709 foundSection = true; 710 break; 711 } 712 // There is an import table, but the section containing it could not be found 713 if (!foundSection) 714 return; 715 } 716 717 // Get the names of each DLL 718 for (uint i = 0; i + IMAGE_IMPORT_DESCRIPTOR.sizeof <= datasize; 719 i += IMAGE_IMPORT_DESCRIPTOR.sizeof) 720 { 721 const data = cast(PIMAGE_IMPORT_DESCRIPTOR)(handle + addr + i); 722 if (data.Name == 0) 723 break; 724 725 // dll name of dependency 726 auto name = cast(char*)(handle + data.Name); 727 // get handle without loading the library 728 auto libhandle = handleForName(name); 729 // the runtime linker has already loaded all dependencies 730 safeAssert(handle !is null, "Failed to get library handle."); 731 // if it's a D library 732 if (auto pdso = dsoForHandle(handle)) 733 deps.insertBack(pdso); // append it to the dependencies 734 } 735 } 736 737 void* handleForName(const char* name) 738 { 739 return GetModuleHandleA(name); 740 } 741 } 742 743 /////////////////////////////////////////////////////////////////////////////// 744 // PE/COFF program header iteration 745 /////////////////////////////////////////////////////////////////////////////// 746 747 bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc 748 { 749 if (name[] != cast(char[])section.Name[0 .. name.length]) 750 return false; 751 return name.length == 8 || section.Name[name.length] == 0; 752 } 753 754 /************ 755 * Scan segments in the image header and store 756 * the writeable data segments in *pdso. 757 */ 758 759 void scanSegments(in HMODULE handle, DSO* pdso) nothrow @nogc 760 { 761 foreach (section; getSectionHeader(handle)) 762 { 763 // the ".data" image section includes both object file sections ".data" and ".bss" 764 if (compareSectionName(section, ".data")) 765 { 766 auto data = cast(void*)handle + section.VirtualAddress; 767 pdso._gcRanges.insertBack(data[0 .. section.Misc.VirtualSize]); 768 continue; 769 } 770 771 version (Shared) 772 { 773 if (compareSectionName(section, ".text")) 774 { 775 auto text = cast(void*)handle + section.VirtualAddress; 776 pdso._codeSegments.insertBack(text[0 .. section.Misc.VirtualSize]); 777 continue; 778 } 779 } 780 } 781 } 782 783 /************************** 784 * Input: 785 * handle where the output is to be written 786 * Returns: 787 * true if found, and *handle is filled in 788 */ 789 790 bool findModuleHandleForAddr(in void* addr, out HMODULE handle) nothrow @nogc 791 { 792 if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, 793 cast(const(wchar)*) addr, &handle)) 794 return true; 795 796 return false; 797 } 798 799 /** 800 * Returns the image NT header for the HMODULE handle passed, 801 * or null if not found. 802 */ 803 PIMAGE_NT_HEADERS getNTHeader(in HMODULE handle) nothrow @nogc 804 { 805 auto doshdr = cast(PIMAGE_DOS_HEADER)handle; 806 if (doshdr.e_magic != IMAGE_DOS_SIGNATURE) 807 return null; 808 809 return cast(typeof(return))(cast(void*)doshdr + doshdr.e_lfanew); 810 } 811 812 /** 813 * Returns the image section header for the HMODULE handle passed, 814 * or null if not found. 815 */ 816 IMAGE_SECTION_HEADER[] getSectionHeader(in HMODULE handle) nothrow @nogc 817 { 818 if (auto nthdr = getNTHeader(handle)) 819 { 820 const void* opthdr = &nthdr.OptionalHeader; 821 const offset = nthdr.FileHeader.SizeOfOptionalHeader; 822 const length = nthdr.FileHeader.NumberOfSections; 823 return (cast(PIMAGE_SECTION_HEADER)(opthdr + offset))[0 .. length]; 824 } 825 return null; 826 } 827