Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/runtime/internal/memory.d

Revision 1289:4a5eea0334e5, 18.0 kB (checked in by Benjamin Kramer <benny.kra@gmail.com>, 3 years ago)

Add runtime support for darwin x86_64

Line 
1 /**
2  * This module exposes functionality for inspecting and manipulating memory.
3  *
4  * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
5  *            All rights reserved.
6  * License:
7  *  This software is provided 'as-is', without any express or implied
8  *  warranty. In no event will the authors be held liable for any damages
9  *  arising from the use of this software.
10  *
11  *  Permission is granted to anyone to use this software for any purpose,
12  *  including commercial applications, and to alter it and redistribute it
13  *  freely, in both source and binary form, subject to the following
14  *  restrictions:
15  *
16  *  o  The origin of this software must not be misrepresented; you must not
17  *     claim that you wrote the original software. If you use this software
18  *     in a product, an acknowledgment in the product documentation would be
19  *     appreciated but is not required.
20  *  o  Altered source versions must be plainly marked as such, and must not
21  *     be misrepresented as being the original software.
22  *  o  This notice may not be removed or altered from any source
23  *     distribution.
24  * Authors:   Walter Bright, Sean Kelly
25  */
26 module memory;
27
28 version = GC_Use_Dynamic_Ranges;
29
30 version(darwin)
31 {
32     version = GC_Use_Data_Dyld;
33     version = GC_Use_Dynamic_Ranges;
34 }
35 else version(Posix)
36 {
37     version = GC_Use_Data_Proc_Maps;
38 }
39 else version(solaris)
40 {
41     version = GC_Use_Data_Proc_Maps;
42 }
43
44 version(GC_Use_Data_Proc_Maps)
45 {
46     version(Posix) {} else {
47         static assert(false, "Proc Maps only supported on Posix systems");
48     }
49     private import tango.stdc.posix.unistd;
50     private import tango.stdc.posix.fcntl;
51     private import tango.stdc.string;
52
53     version = GC_Use_Dynamic_Ranges;
54 }
55
56 private
57 {
58     version( linux )
59     {
60         //version = SimpleLibcStackEnd;
61
62         version( SimpleLibcStackEnd )
63         {
64             extern (C) extern void* __libc_stack_end;
65         }
66         else
67         {
68             import tango.stdc.posix.dlfcn;
69         }
70     }
71     pragma(intrinsic, "llvm.frameaddress")
72     {
73             void* llvm_frameaddress(uint level=0);
74     }
75 }
76
77
78 /**
79  *
80  */
81
82 version( solaris ) {   
83     version(X86_64) {
84         extern (C) void* _userlimit;
85     }
86 }
87
88 extern (C) void* rt_stackBottom()
89 {
90     version( Win32 )
91     {
92         void* bottom;
93         asm
94         {
95             mov EAX, FS:4;
96             mov bottom, EAX;
97         }
98         return bottom;
99     }
100     else version( linux )
101     {
102         version( SimpleLibcStackEnd )
103         {
104             return __libc_stack_end;
105         }
106         else
107         {
108             // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
109                 static void** libc_stack_end;
110
111                 if( libc_stack_end == libc_stack_end.init )
112                 {
113                     void* handle = dlopen( null, RTLD_NOW );
114                     libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
115                     dlclose( handle );
116                 }
117                 return *libc_stack_end;
118         }
119     }
120     else version( darwin )
121     {
122         // darwin has a fixed stack bottom
123         version(X86_64)
124             return cast(void*) 0x7fff5fc00000;
125         else
126             return cast(void*) 0xc0000000;
127     }
128     else version( solaris )
129     {
130         version(X86_64) {
131             return _userlimit;
132         }
133         else {
134             // <sys/vmparam.h>
135             return cast(void*) 0x8048000;
136         }
137     }
138     else
139     {
140         static assert( false, "Operating system not supported." );
141     }
142 }
143
144
145 /**
146  *
147  */
148 extern (C) void* rt_stackTop()
149 {
150     version( D_InlineAsm_X86 )
151     {
152         asm
153         {
154             naked;
155             mov EAX, ESP;
156             ret;
157         }
158     }
159     else
160     {
161         return llvm_frameaddress();
162     }
163 }
164
165
166 private
167 {
168     version( Win32 )
169     {
170         extern (C)
171         {
172             extern int _data_start__;
173             extern int _bss_end__;
174         }
175
176         alias _data_start__ Data_Start;
177         alias _bss_end__    Data_End;
178     }
179     else version( linux )
180     {
181         extern (C)
182         {
183             extern int _data;
184             extern int __data_start;
185             extern int _end;
186             extern int _data_start__;
187             extern int _data_end__;
188             extern int _bss_start__;
189             extern int _bss_end__;
190             extern int __fini_array_end;
191         }
192
193         alias __data_start  Data_Start;
194         alias _end          Data_End;
195     }
196     else version( solaris )
197     {
198         extern(C)
199         {
200             extern int _environ;
201             extern int _end;
202         }
203
204         alias _environ      Data_Start;
205         alias _end          Data_End;
206     }
207
208     version( GC_Use_Dynamic_Ranges )
209     {
210         private import tango.stdc.stdlib;
211
212         struct DataSeg
213         {
214             void* beg;
215             void* end;
216         }
217
218         DataSeg* allSegs = null;
219         size_t   numSegs = 0;
220
221         extern (C) void _d_gc_add_range( void* beg, void* end )
222         {
223             void* ptr = realloc( allSegs, (numSegs + 1) * DataSeg.sizeof );
224
225             if( ptr ) // if realloc fails, we have problems
226             {
227                 allSegs = cast(DataSeg*) ptr;
228                 allSegs[numSegs].beg = beg;
229                 allSegs[numSegs].end = end;
230                 numSegs++;
231             }
232         }
233
234         extern (C) void _d_gc_remove_range( void* beg )
235         {
236             for( size_t pos = 0; pos < numSegs; ++pos )
237             {
238                 if( beg == allSegs[pos].beg )
239                 {
240                     while( ++pos < numSegs )
241                     {
242                         allSegs[pos-1] = allSegs[pos];
243                     }
244                     numSegs--;
245                     return;
246                 }
247             }
248         }
249     }
250
251     alias void delegate( void*, void* ) scanFn;
252
253     void* dataStart,  dataEnd;
254 }
255
256
257 /**
258  *
259  */
260 extern (C) void rt_scanStaticData( scanFn scan )
261 {
262     scan( dataStart, dataEnd );
263
264     version( GC_Use_Dynamic_Ranges )
265     {
266         for( size_t pos = 0; pos < numSegs; ++pos )
267         {
268             scan( allSegs[pos].beg, allSegs[pos].end );
269         }
270     }
271 }
272
273 void initStaticDataPtrs()
274 {
275     const int S = (void*).sizeof;
276
277     // Can't assume the input addresses are word-aligned
278     static void* adjust_up( void* p )
279     {
280         return p + ((S - (cast(size_t)p & (S-1))) & (S-1)); // cast ok even if 64-bit
281     }
282
283     static void * adjust_down( void* p )
284     {
285         return p - (cast(size_t) p & (S-1));
286     }
287
288     version( Win32 )
289     {
290         dataStart = adjust_up( &Data_Start );
291         dataEnd   = adjust_down( &Data_End );
292     }
293     else version(linux)
294     {
295         dataStart = adjust_up( &Data_Start );
296         dataEnd   = adjust_down( &Data_End );
297     }
298     else version(solaris)
299     {
300         dataStart = adjust_up( &Data_Start );
301         dataEnd   = adjust_down( &Data_End );
302     }
303     else version(GC_Use_Data_Dyld)
304     {
305         _d_dyld_start();
306     }
307     else
308     {
309         static assert( false, "Operating system not supported." );
310     }
311
312     version( GC_Use_Data_Proc_Maps )
313     {
314         parseDataProcMaps();
315     }
316 }
317
318 version( GC_Use_Data_Proc_Maps )
319 {
320 version(solaris)
321 {
322     typedef long offset_t;
323     enum : uint { PRMAPSZ = 64, MA_WRITE = 0x02 }
324     extern(C)
325     {
326         struct prmap {
327             uintptr_t pr_vaddr;         /* virtual address of mapping */
328             size_t pr_size;             /* size of mapping in bytes */
329             char[PRMAPSZ]  pr_mapname;  /* name in /proc/<pid>/object */
330             private offset_t pr_offset; /* offset into mapped object, if any */
331             int pr_mflags;              /* protection and attribute flags (see below) */
332             int pr_pagesize;            /* pagesize (bytes) for this mapping */
333             int pr_shmid;               /* SysV shmid, -1 if not SysV shared memory */
334
335             private int[1] pr_filler;
336         }
337     }
338
339     debug (ProcMaps) extern (C) int printf(char*, ...);
340
341     void parseDataProcMaps()
342     {
343         debug (ProcMaps) printf("initStaticDataPtrs()\n");
344         // http://docs.sun.com/app/docs/doc/816-5174/proc-4
345         prmap pr;
346
347         int   fd = open("/proc/self/map", O_RDONLY);
348         scope (exit) close(fd);
349
350         while (prmap.sizeof == read(fd, &pr, prmap.sizeof))
351         if (pr.pr_mflags & MA_WRITE)
352         {
353             void* start = cast(void*) pr.pr_vaddr;
354             void* end   = cast(void*)(pr.pr_vaddr + pr.pr_size);
355             debug (ProcMaps) printf("  vmem at %p - %p with size %d bytes\n", start, end, pr.pr_size);
356
357             // Exclude stack  and  dataStart..dataEnd
358             if ( ( !dataEnd ||
359                 !( dataStart >= start && dataEnd <= end ) ) &&
360                 !( &pr >= start && &pr < end ) )
361             {
362                 // we already have static data from this region.  anything else
363                 // is heap (%% check)
364                 debug (ProcMaps) printf("  Adding map range %p - %p\n", start, end);
365                 _d_gc_add_range(start, end);
366             }
367         }
368     }
369 }
370 else
371 {
372     const int S = (void*).sizeof;
373
374     // TODO: This could use cleanup!
375     void parseDataProcMaps()
376     {
377         // TODO: Exclude zero-mapped regions
378
379         int   fd = open("/proc/self/maps", O_RDONLY);
380         ptrdiff_t   count; // %% need to configure ret for read..
381         char  buf[2024];
382         char* p;
383         char* e;
384         char* s;
385         void* start;
386         void* end;
387
388         p = buf.ptr;
389         if (fd != -1)
390         {
391             while ( (count = read(fd, p, buf.sizeof - (p - buf.ptr))) > 0 )
392             {
393                 e = p + count;
394                 p = buf.ptr;
395                 while (true)
396                 {
397                     s = p;
398                     while (p < e && *p != '\n')
399                         p++;
400                     if (p < e)
401                     {
402                         // parse the entry in [s, p)
403                         static if( S == 4 )
404                         {
405                             enum Ofs
406                             {
407                                 Write_Prot = 19,
408                                 Start_Addr = 0,
409                                 End_Addr   = 9,
410                                 Addr_Len   = 8,
411                             }
412                         }
413                         else static if( S == 8 )
414                         {
415                             //X86-64 only has 12 bytes address space(in PAE mode) - not 16
416                             //We also need the 32 bit offsets for 32 bit apps
417                             version(X86_64) {
418                                 enum Ofs
419                                 {
420                                     Write_Prot = 27,
421                                     Start_Addr = 0,
422                                     End_Addr   = 13,
423                                     Addr_Len   = 12,
424                                     Write_Prot_32 = 19,
425                                     Start_Addr_32 = 0,
426                                     End_Addr_32   = 9,
427                                     Addr_Len_32   = 8,
428                                 }
429                             }
430                             else
431                             {
432                                 enum Ofs
433                                 {
434                                     Write_Prot = 35,
435                                     Start_Addr = 0,
436                                     End_Addr   = 9,
437                                     Addr_Len   = 17,
438                                 }
439                             }
440                         }
441                         else
442                         {
443                             static assert( false );
444                         }
445
446                         // %% this is wrong for 64-bit:
447                         // long strtoul(const char*,char**,int);
448                         // but seems to work on x86-64:
449                         // probably because C's long is 64 bit there
450
451                         if( s[Ofs.Write_Prot] == 'w' )
452                         {
453                             s[Ofs.Start_Addr + Ofs.Addr_Len] = '\0';
454                             s[Ofs.End_Addr + Ofs.Addr_Len] = '\0';
455                             start = cast(void*) strtoul(s + Ofs.Start_Addr, null, 16);
456                             end   = cast(void*) strtoul(s + Ofs.End_Addr, null, 16);
457
458                             // 1. Exclude anything overlapping [dataStart, dataEnd)
459                             // 2. Exclude stack
460                             if ( ( !dataEnd ||
461                                 !( dataStart >= start && dataEnd <= end ) ) &&
462                                 !( &buf[0] >= start && &buf[0] < end ) )
463                             {
464                                 // we already have static data from this region.  anything else
465                                 // is heap (%% check)
466                                 debug (ProcMaps) printf("Adding map range %p 0%p\n", start, end);
467                                 _d_gc_add_range(start, end);
468                             }
469                         }
470                         version(X86_64)
471                         {
472                             //We need to check here for 32 bit apps like ldc produces
473                             //and add them to the gc scan range
474                             if( s[Ofs.Write_Prot_32] == 'w' )
475                             {
476                                 s[Ofs.Start_Addr_32 + Ofs.Addr_Len_32] = '\0';
477                                 s[Ofs.End_Addr_32 + Ofs.Addr_Len_32] = '\0';
478                                 start = cast(void*) strtoul(s + Ofs.Start_Addr_32, null, 16);
479                                 end   = cast(void*) strtoul(s + Ofs.End_Addr_32, null, 16);
480                                 if ( ( !dataEnd ||
481                                     !( dataStart >= start && dataEnd <= end ) ) &&
482                                     !( &buf[0] >= start && &buf[0] < end ) )
483                                 {
484                                     _d_gc_add_range(start, end);
485                                 }
486                             }
487                         }
488
489                         p++;
490                     }
491                     else
492                     {
493                         count = p - s;
494                         memmove(buf.ptr, s, cast(size_t)count);
495                         p = buf.ptr + count;
496                         break;
497                     }
498                 }
499             }
500             close(fd);
501         }
502     }
503 }
504 }
505
506 /*
507  * GDC dyld memory module:
508  * http://www.dsource.org/projects/tango/browser/trunk/lib/compiler/gdc/memory_dyld.c
509  * Port to the D programming language: Jacob Carlborg
510  */
511 version (GC_Use_Data_Dyld)
512 {
513     private
514     {
515         const char* SEG_DATA = "__DATA".ptr;
516         const char* SECT_DATA = "__data".ptr;
517         const char* SECT_BSS = "__bss".ptr;
518         const char* SECT_COMMON = "__common".ptr;
519
520         struct SegmentSection
521         {
522             const char* segment;
523             const char* section;
524         }
525
526         struct mach_header
527         {
528             uint magic;
529             int cputype;
530             int cpusubtype;
531             uint filetype;
532             uint ncmds;
533             uint sizeofcmds;
534             uint flags;
535             version(X86_64)
536                 uint reserved;
537         }
538
539         struct section
540         {
541             char[16] sectname;
542             char[16] segname;
543             version(X86_64)
544             {
545                 ulong addr;
546                 ulong size;
547             }
548             else
549             {
550                 uint addr;
551                 uint size;
552             }
553             uint offset;
554             uint align_;
555             uint reloff;
556             uint nreloc;
557             uint flags;
558             uint reserved1;
559             uint reserved2;
560             version(X86_64)
561                 uint reserved3;
562         }
563
564         alias extern (C) void function (mach_header* mh, ptrdiff_t vmaddr_slide) DyldFuncPointer;
565
566         version(X86_64)
567             extern (C) /*const*/ section* getsectbynamefromheader_64(/*const*/ mach_header* mhp, /*const*/ char* segname, /*const*/ char* sectname);
568         else
569             extern (C) /*const*/ section* getsectbynamefromheader(/*const*/ mach_header* mhp, /*const*/ char* segname, /*const*/ char* sectname);
570         extern (C) void _dyld_register_func_for_add_image(DyldFuncPointer func);
571         extern (C) void _dyld_register_func_for_remove_image(DyldFuncPointer func);
572
573         const SegmentSection[3] GC_dyld_sections = [SegmentSection(SEG_DATA, SECT_DATA), SegmentSection(SEG_DATA, SECT_BSS), SegmentSection(SEG_DATA, SECT_COMMON)];   
574
575         extern (C) void on_dyld_add_image (/*const*/ mach_header* hdr, ptrdiff_t slide)
576         {
577             void* start;
578             void* end;
579             /*const*/ section* sec;
580
581             foreach (s ; GC_dyld_sections)
582             {
583                 version(X86_64)
584                     sec = getsectbynamefromheader_64(hdr, s.segment, s.section);
585                 else
586                     sec = getsectbynamefromheader(hdr, s.segment, s.section);
587
588                 if (sec == null || sec.size == 0)
589                     continue;
590
591                 start = cast(void*) (sec.addr + slide);
592                 end = cast(void*) (start + sec.size);
593
594                 _d_gc_add_range(start, end);
595             }
596         }
597
598         extern (C) void on_dyld_remove_image (/*const*/ mach_header* hdr, ptrdiff_t slide)
599         {
600             void* start;
601             void* end;
602             /*const*/ section* sec;
603
604             foreach (s ; GC_dyld_sections)
605             {
606                 version(X86_64)
607                     sec = getsectbynamefromheader_64(hdr, s.segment, s.section);
608                 else
609                     sec = getsectbynamefromheader(hdr, s.segment, s.section);
610
611                 if (sec == null || sec.size == 0)
612                     continue;
613
614                 start = cast(void*) (sec.addr + slide);
615                 end = cast(void*) (start + sec.size);
616
617                 _d_gc_remove_range(start);
618             }
619         }
620
621         void _d_dyld_start ()
622         {
623             static bool started;
624
625             if (!started)
626             {
627                 started = true;
628
629                 _dyld_register_func_for_add_image(&on_dyld_add_image);
630                 _dyld_register_func_for_remove_image(&on_dyld_remove_image);
631             }
632         }
633     }
634 }
Note: See TracBrowser for help on using the browser.
Copyright © 2008, LDC Development Team.