]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/libdruntime/gcc/sections/pecoff.d
736134913c12c53b5929cff6f0f9ae8e88b5a6f7
[thirdparty/gcc.git] / libphobos / libdruntime / gcc / sections / pecoff.d
1 // PE/COFF-specific support for sections.
2 // Copyright (C) 2021 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 }