The OpenD Programming Language

1 /**
2  * The runtime module exposes information specific to the D runtime code.
3  *
4  * Copyright: Copyright Sean Kelly 2005 - 2009.
5  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6  * Authors:   Sean Kelly
7  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/runtime.d, _runtime.d)
8  * Documentation: https://dlang.org/phobos/core_runtime.html
9  */
10 
11 module core.runtime;
12 
13 version (OSX)
14     version = Darwin;
15 else version (iOS)
16     version = Darwin;
17 else version (TVOS)
18     version = Darwin;
19 else version (WatchOS)
20     version = Darwin;
21 
22 version (DRuntime_Use_Libunwind)
23 {
24     import core.internal.backtrace.libunwind;
25     // This shouldn't be necessary but ensure that code doesn't get mixed
26     // It does however prevent the unittest SEGV handler to be installed,
27     // which is desireable as it uses backtrace directly.
28     private enum hasExecinfo = false;
29 }
30 else
31     import core.internal.execinfo;
32 
33 /// C interface for Runtime.loadLibrary
34 extern (C) void* rt_loadLibrary(const char* name);
35 /// ditto
36 version (Windows) extern (C) void* rt_loadLibraryW(const wchar* name);
37 
38 /// C interface for Runtime.unloadLibrary, returns 1/0 instead of bool
39 extern (C) int rt_unloadLibrary(void* ptr);
40 
41 /// C interface for Runtime.initialize, returns 1/0 instead of bool
42 extern(C) int rt_init();
43 /// C interface for Runtime.terminate, returns 1/0 instead of bool
44 extern(C) int rt_term();
45 
46 /**
47  * This type is returned by the module unit test handler to indicate testing
48  * results.
49  */
50 struct UnitTestResult
51 {
52     /**
53      * Number of modules which were tested
54      */
55     size_t executed;
56 
57     /**
58      * Number of modules passed the unittests
59      */
60     size_t passed;
61 
62     /**
63      * Should the main function be run or not? This is ignored if any tests
64      * failed.
65      */
66     bool runMain;
67 
68     /**
69      * Should we print a summary of the results?
70      */
71     bool summarize;
72 
73     /**
74      * Simple check for whether execution should continue after unit tests
75      * have been run. Works with legacy code that expected a bool return.
76      *
77      * Returns:
78      *    true if execution should continue after testing is complete, false if
79      *    not.
80      */
81     bool opCast(T : bool)() const
82     {
83         return runMain && (executed == passed);
84     }
85 
86     /// Simple return code that says unit tests pass, and main should be run
87     enum UnitTestResult pass = UnitTestResult(0, 0, true, false);
88     /// Simple return code that says unit tests failed.
89     enum UnitTestResult fail = UnitTestResult(1, 0, false, false);
90 }
91 
92 /// Legacy module unit test handler
93 alias bool function() ModuleUnitTester;
94 /// Module unit test handler
95 alias UnitTestResult function() ExtendedModuleUnitTester;
96 private
97 {
98     alias bool function(Object) CollectHandler;
99     alias Throwable.TraceInfo function( void* ptr ) TraceHandler;
100 
101     alias void delegate( Throwable ) ExceptionHandler;
102     extern (C) void _d_print_throwable(Throwable t);
103 
104     extern (C) void* thread_stackBottom() nothrow @nogc;
105 }
106 
107 
108 shared static this()
109 {
110     // NOTE: Some module ctors will run before this handler is set, so it's
111     //       still possible the app could exit without a stack trace.  If
112     //       this becomes an issue, the handler could be set in C main
113     //       before the module ctors are run.
114     Runtime.traceHandler(&defaultTraceHandler, &defaultTraceDeallocator);
115 }
116 
117 
118 ///////////////////////////////////////////////////////////////////////////////
119 // Runtime
120 ///////////////////////////////////////////////////////////////////////////////
121 
122 /**
123  * Stores the unprocessed arguments supplied when the
124  * process was started.
125  */
126 struct CArgs
127 {
128     int argc; /// The argument count.
129     char** argv; /// The arguments as a C array of strings.
130 }
131 
132 /**
133  * This struct encapsulates all functionality related to the underlying runtime
134  * module for the calling context.
135  */
136 struct Runtime
137 {
138     /**
139      * Initializes the runtime.  This call is to be used in instances where the
140      * standard program initialization process is not executed.  This is most
141      * often in shared libraries or in libraries linked to a C program.
142      * If the runtime was already successfully initialized this returns true.
143      * Each call to initialize must be paired by a call to $(LREF terminate).
144      *
145      * Returns:
146      *  true if initialization succeeded or false if initialization failed.
147      */
148     static bool initialize()
149     {
150         return !!rt_init();
151     }
152 
153     /**
154      * Terminates the runtime.  This call is to be used in instances where the
155      * standard program termination process will not be not executed.  This is
156      * most often in shared libraries or in libraries linked to a C program.
157      * If the runtime was not successfully initialized the function returns false.
158      *
159      * Returns:
160      *  true if termination succeeded or false if termination failed.
161      */
162     static bool terminate()
163     {
164         return !!rt_term();
165     }
166 
167     /**
168      * Returns the arguments supplied when the process was started.
169      *
170      * Returns:
171      *  The arguments supplied when this process was started.
172      */
173     extern(C) pragma(mangle, "rt_args") static @property string[] args();
174 
175     /**
176      * Returns the unprocessed C arguments supplied when the process was started.
177      * Use this when you need to supply argc and argv to C libraries.
178      *
179      * Returns:
180      *  A $(LREF CArgs) struct with the arguments supplied when this process was started.
181      *
182      * Example:
183      * ---
184      * import core.runtime;
185      *
186      * // A C library function requiring char** arguments
187      * extern(C) void initLibFoo(int argc, char** argv);
188      *
189      * void main()
190      * {
191      *     auto args = Runtime.cArgs;
192      *     initLibFoo(args.argc, args.argv);
193      * }
194      * ---
195      */
196     extern(C) pragma(mangle, "rt_cArgs") static @property CArgs cArgs() @nogc;
197 
198     /**
199      * Locates a dynamic library with the supplied library name and dynamically
200      * loads it into the caller's address space.  If the library contains a D
201      * runtime it will be integrated with the current runtime.
202      *
203      * Params:
204      *  name = The name of the dynamic library to load.
205      *
206      * Returns:
207      *  A reference to the library or null on error.
208      */
209     static void* loadLibrary()(const scope char[] name)
210     {
211         import core.stdc.stdlib : free, malloc;
212         version (Windows)
213         {
214             import core.sys.windows.winnls : CP_UTF8, MultiByteToWideChar;
215             import core.sys.windows.winnt : WCHAR;
216 
217             if (name.length == 0) return null;
218             // Load a DLL at runtime
219             auto len = MultiByteToWideChar(
220                 CP_UTF8, 0, name.ptr, cast(int)name.length, null, 0);
221             if (len == 0)
222                 return null;
223 
224             auto buf = cast(WCHAR*)malloc((len+1) * WCHAR.sizeof);
225             if (buf is null) return null;
226             scope (exit) free(buf);
227 
228             len = MultiByteToWideChar(
229                 CP_UTF8, 0, name.ptr, cast(int)name.length, buf, len);
230             if (len == 0)
231                 return null;
232 
233             buf[len] = '\0';
234 
235             return rt_loadLibraryW(buf);
236         }
237         else version (Posix)
238         {
239             /* Need a 0-terminated C string for the dll name
240              */
241             immutable len = name.length;
242             auto buf = cast(char*)malloc(len + 1);
243             if (!buf) return null;
244             scope (exit) free(buf);
245 
246             buf[0 .. len] = name[];
247             buf[len] = 0;
248 
249             return rt_loadLibrary(buf);
250         }
251     }
252 
253 
254     /**
255      * Unloads the dynamic library referenced by p.  If this library contains a
256      * D runtime then any necessary finalization or cleanup of that runtime
257      * will be performed.
258      *
259      * Params:
260      *  p = A reference to the library to unload.
261      */
262     static bool unloadLibrary()(void* p)
263     {
264         return !!rt_unloadLibrary(p);
265     }
266 
267 
268     /**
269      * Overrides the default trace mechanism with a user-supplied version.  A
270      * trace represents the context from which an exception was thrown, and the
271      * trace handler will be called when this occurs.  The pointer supplied to
272      * this routine indicates the base address from which tracing should occur.
273      * If the supplied pointer is null then the trace routine should determine
274      * an appropriate calling context from which to begin the trace.
275      *
276      * If the deallocator is set, then it is called with the traceinfo when the
277      * exception is finalized. The deallocator is only set in the exception if
278      * the default handler is used to generate the trace info.
279      *
280      * Params:
281      *  h = The new trace handler.  Set to null to disable exception backtracing.
282      *  d = The new trace deallocator. If non-null, this will be called on
283      *      exception destruction with the trace info, only when the trace
284      *      handler is used to generate TraceInfo.
285      */
286     extern(C) pragma(mangle, "rt_setTraceHandler") static @property void traceHandler(TraceHandler h,
287                     Throwable.TraceDeallocator d = null);
288 
289     /**
290      * Gets the current trace handler.
291      *
292      * Returns:
293      *  The current trace handler or null if none has been set.
294      */
295     extern(C) pragma(mangle, "rt_getTraceHandler") static @property TraceHandler traceHandler();
296 
297     /**
298      * Gets the current trace deallocator.
299      *
300      * Returns:
301      *  The current trace deallocator or null if none has been set.
302      */
303     extern(C) pragma(mangle, "rt_getTraceDeallocator") static @property Throwable.TraceDeallocator traceDeallocator();
304 
305     /**
306      * Overrides the default collect hander with a user-supplied version.  This
307      * routine will be called for each resource object that is finalized in a
308      * non-deterministic manner--typically during a garbage collection cycle.
309      * If the supplied routine returns true then the object's dtor will called
310      * as normal, but if the routine returns false than the dtor will not be
311      * called.  The default behavior is for all object dtors to be called.
312      *
313      * Params:
314      *  h = The new collect handler.  Set to null to use the default handler.
315      */
316     extern(C) pragma(mangle, "rt_setCollectHandler") static @property void collectHandler( CollectHandler h );
317 
318 
319     /**
320      * Gets the current collect handler.
321      *
322      * Returns:
323      *  The current collect handler or null if none has been set.
324      */
325     extern(C) pragma(mangle, "rt_getCollectHandler") static @property CollectHandler collectHandler();
326 
327 
328     /**
329      * Overrides the default module unit tester with a user-supplied version.
330      * This routine will be called once on program initialization.  The return
331      * value of this routine indicates to the runtime whether the tests ran
332      * without error.
333      *
334      * There are two options for handlers. The `bool` version is deprecated but
335      * will be kept for legacy support. Returning `true` from the handler is
336      * equivalent to returning `UnitTestResult.pass` from the extended version.
337      * Returning `false` from the handler is equivalent to returning
338      * `UnitTestResult.fail` from the extended version.
339      *
340      * See the documentation for `UnitTestResult` to see how you should set up
341      * the return structure.
342      *
343      * See the documentation for `runModuleUnitTests` for how the default
344      * algorithm works, or read the example below.
345      *
346      * Params:
347      *  h = The new unit tester.  Set both to null to use the default unit
348      *  tester.
349      *
350      * Example:
351      * ---------
352      * shared static this()
353      * {
354      *     import core.runtime;
355      *
356      *     Runtime.extendedModuleUnitTester = &customModuleUnitTester;
357      * }
358      *
359      * UnitTestResult customModuleUnitTester()
360      * {
361      *     import std.stdio;
362      *
363      *     writeln("Using customModuleUnitTester");
364      *
365      *     // Do the same thing as the default moduleUnitTester:
366      *     UnitTestResult result;
367      *     foreach (m; ModuleInfo)
368      *     {
369      *         if (m)
370      *         {
371      *             auto fp = m.unitTest;
372      *
373      *             if (fp)
374      *             {
375      *                 ++result.executed;
376      *                 try
377      *                 {
378      *                     fp();
379      *                     ++result.passed;
380      *                 }
381      *                 catch (Throwable e)
382      *                 {
383      *                     writeln(e);
384      *                 }
385      *             }
386      *         }
387      *     }
388      *     if (result.executed != result.passed)
389      *     {
390      *         result.runMain = false;  // don't run main
391      *         result.summarize = true; // print failure
392      *     }
393      *     else
394      *     {
395      *         result.runMain = true;    // all UT passed
396      *         result.summarize = false; // be quiet about it.
397      *     }
398      *     return result;
399      * }
400      * ---------
401      */
402     static @property void extendedModuleUnitTester( ExtendedModuleUnitTester h )
403     {
404         sm_extModuleUnitTester = h;
405     }
406 
407     /// Ditto
408     static @property void moduleUnitTester( ModuleUnitTester h )
409     {
410         sm_moduleUnitTester = h;
411     }
412 
413     /**
414      * Gets the current legacy module unit tester.
415      *
416      * This property should not be used, but is supported for legacy purposes.
417      *
418      * Note that if the extended unit test handler is set, this handler will
419      * be ignored.
420      *
421      * Returns:
422      *  The current legacy module unit tester handler or null if none has been
423      *  set.
424      */
425     static @property ModuleUnitTester moduleUnitTester()
426     {
427         return sm_moduleUnitTester;
428     }
429 
430     /**
431      * Gets the current module unit tester.
432      *
433      * This handler overrides any legacy module unit tester set by the
434      * moduleUnitTester property.
435      *
436      * Returns:
437      *  The current  module unit tester handler or null if none has been
438      *  set.
439      */
440     static @property ExtendedModuleUnitTester extendedModuleUnitTester()
441     {
442         return sm_extModuleUnitTester;
443     }
444 
445 private:
446 
447     // NOTE: This field will only ever be set in a static ctor and should
448     //       never occur within any but the main thread, so it is safe to
449     //       make it __gshared.
450     __gshared ExtendedModuleUnitTester sm_extModuleUnitTester = null;
451     __gshared ModuleUnitTester sm_moduleUnitTester = null;
452 }
453 
454 /**
455  * Set source file path for coverage reports.
456  *
457  * Params:
458  *  path = The new path name.
459  * Note:
460  *  This is a dmd specific setting.
461  */
462 extern (C) void dmd_coverSourcePath(string path);
463 
464 /**
465  * Set output path for coverage reports.
466  *
467  * Params:
468  *  path = The new path name.
469  * Note:
470  *  This is a dmd specific setting.
471  */
472 extern (C) void dmd_coverDestPath(string path);
473 
474 /**
475  * Enable merging of coverage reports with existing data.
476  *
477  * Params:
478  *  flag = enable/disable coverage merge mode
479  * Note:
480  *  This is a dmd specific setting.
481  */
482 extern (C) void dmd_coverSetMerge(bool flag);
483 
484 /**
485  * Set the output file name for profile reports (-profile switch).
486  * An empty name will set the output to stdout.
487  *
488  * Params:
489  *  name = file name
490  * Note:
491  *  This is a dmd specific setting.
492  */
493 extern (C) void trace_setlogfilename(string name);
494 
495 /**
496  * Set the output file name for the optimized profile linker DEF file (-profile switch).
497  * An empty name will set the output to stdout.
498  *
499  * Params:
500  *  name = file name
501  * Note:
502  *  This is a dmd specific setting.
503  */
504 extern (C) void trace_setdeffilename(string name);
505 
506 /**
507  * Set the output file name for memory profile reports (-profile=gc switch).
508  * An empty name will set the output to stdout.
509  *
510  * Params:
511  *  name = file name
512  * Note:
513  *  This is a dmd specific setting.
514  */
515 extern (C) void profilegc_setlogfilename(string name);
516 
517 ///////////////////////////////////////////////////////////////////////////////
518 // Overridable Callbacks
519 ///////////////////////////////////////////////////////////////////////////////
520 
521 
522 /**
523  * This routine is called by the runtime to run module unit tests on startup.
524  * The user-supplied unit tester will be called if one has been set,
525  * otherwise all unit tests will be run in sequence.
526  *
527  * If the extended unittest handler is registered, this function returns the
528  * result from that handler directly.
529  *
530  * If a legacy boolean returning custom handler is used, `false` maps to
531  * `UnitTestResult.fail`, and `true` maps to `UnitTestResult.pass`. This was
532  * the original behavior of the unit testing system.
533  *
534  * If no unittest custom handlers are registered, the following algorithm is
535  * executed (the behavior can be affected by the `--DRT-testmode` switch
536  * below):
537  * 1. Execute any unittests present. For each that fails, print the stack
538  *    trace and continue.
539  * 2. If no unittests were present, set summarize to false, and runMain to
540  *    true.
541  * 3. Otherwise, set summarize to true, and runMain to false.
542  *
543  * See the documentation for `UnitTestResult` for details on how the runtime
544  * treats the return value from this function.
545  *
546  * If the switch `--DRT-testmode` is passed to the executable, it can have
547  * one of 3 values:
548  * 1. "run-main": even if unit tests are run (and all pass), runMain is set
549       to true.
550  * 2. "test-or-main": any unit tests present will cause the program to
551  *    summarize the results and exit regardless of the result. This is the
552  *    default.
553  * 3. "test-only", runMain is set to false, even with no tests present.
554  *
555  * This command-line parameter does not affect custom unit test handlers.
556  *
557  * Returns:
558  *   A `UnitTestResult` struct indicating the result of running unit tests.
559  */
560 extern (C) UnitTestResult runModuleUnitTests() @system
561 {
562     version (Windows)
563         import core.sys.windows.stacktrace;
564 
565     static if (hasExecinfo)
566     {
567         import core.sys.posix.signal; // segv handler
568 
569         static extern (C) void unittestSegvHandler( int signum, siginfo_t* info, void* ptr ) nothrow
570         {
571             static enum MAXFRAMES = 128;
572             void*[MAXFRAMES]  callstack;
573 
574             auto numframes = backtrace( callstack.ptr, MAXFRAMES );
575             backtrace_symbols_fd( callstack.ptr, numframes, 2 );
576         }
577 
578         sigaction_t action = void;
579         sigaction_t oldseg = void;
580         sigaction_t oldbus = void;
581 
582         (cast(byte*) &action)[0 .. action.sizeof] = 0;
583         sigfillset( &action.sa_mask ); // block other signals
584         action.sa_flags = SA_SIGINFO | SA_RESETHAND;
585         action.sa_sigaction = &unittestSegvHandler;
586         sigaction( SIGSEGV, &action, &oldseg );
587         sigaction( SIGBUS, &action, &oldbus );
588         scope( exit )
589         {
590             sigaction( SIGSEGV, &oldseg, null );
591             sigaction( SIGBUS, &oldbus, null );
592         }
593     }
594 
595     if (Runtime.sm_extModuleUnitTester !is null)
596         return Runtime.sm_extModuleUnitTester();
597     else if (Runtime.sm_moduleUnitTester !is null)
598         return Runtime.sm_moduleUnitTester() ? UnitTestResult.pass : UnitTestResult.fail;
599     UnitTestResult results;
600     foreach ( m; ModuleInfo )
601     {
602         if ( !m )
603             continue;
604         auto fp = m.unitTest;
605         if ( !fp )
606             continue;
607 
608         import core.exception;
609         ++results.executed;
610         try
611         {
612             fp();
613             ++results.passed;
614         }
615         catch ( Throwable e )
616         {
617             if ( typeid(e) == typeid(AssertError) )
618             {
619                 // Crude heuristic to figure whether the assertion originates in
620                 // the unittested module. TODO: improve.
621                 auto moduleName = m.name;
622                 if (moduleName.length && e.file.length > moduleName.length
623                     && e.file[0 .. moduleName.length] == moduleName)
624                 {
625                     import core.stdc.stdio;
626                     printf("%.*s(%llu): [unittest] %.*s\n",
627                         cast(int) e.file.length, e.file.ptr, cast(ulong) e.line,
628                         cast(int) e.message.length, e.message.ptr);
629 
630                     // Exception originates in the same module, don't print
631                     // the stack trace.
632                     // TODO: omit stack trace only if assert was thrown
633                     // directly by the unittest.
634                     continue;
635                 }
636             }
637             // TODO: perhaps indent all of this stuff.
638             _d_print_throwable(e);
639         }
640     }
641 
642     import core.internal.parseoptions : rt_configOption;
643 
644     if (results.passed != results.executed)
645     {
646         // by default, we always print a summary if there are failures.
647         results.summarize = true;
648     }
649     else switch (rt_configOption("testmode", null, false))
650     {
651     case "run-main":
652         results.runMain = true;
653         break;
654     case "test-only":
655         // Never run main, always summarize
656         results.summarize = true;
657         break;
658     case "":
659         // By default, do not run main if tests are present.
660     case "test-or-main":
661         // only run main if there were no tests. Only summarize if we are not
662         // running main.
663         results.runMain = (results.executed == 0);
664         results.summarize = !results.runMain;
665         break;
666     default:
667         assert(0, "Unknown --DRT-testmode option: " ~ rt_configOption("testmode", null, false));
668     }
669 
670     return results;
671 }
672 
673 version (LDC) version (Darwin)
674 {
675     nothrow:
676 
677     extern (C)
678     {
679         enum _URC_NO_REASON = 0;
680         enum _URC_END_OF_STACK = 5;
681 
682         alias _Unwind_Context_Ptr = void*;
683         alias _Unwind_Trace_Fn = int function(_Unwind_Context_Ptr, void*);
684         int _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
685         ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context);
686     }
687 
688     // Use our own backtrce() based on _Unwind_Backtrace(), as the former (from
689     // execinfo) doesn't seem to handle missing frame pointers too well.
690     private int backtrace(void** buffer, int maxSize)
691     {
692         if (maxSize < 0) return 0;
693 
694         struct State
695         {
696             void** buffer;
697             int maxSize;
698             int entriesWritten = 0;
699         }
700 
701         static extern(C) int handler(_Unwind_Context_Ptr context, void* statePtr)
702         {
703             auto state = cast(State*)statePtr;
704             if (state.entriesWritten >= state.maxSize) return _URC_END_OF_STACK;
705 
706             auto instructionPtr = _Unwind_GetIP(context);
707             if (!instructionPtr) return _URC_END_OF_STACK;
708 
709             state.buffer[state.entriesWritten] = cast(void*)instructionPtr;
710             ++state.entriesWritten;
711 
712             return _URC_NO_REASON;
713         }
714 
715         State state;
716         state.buffer = buffer;
717         state.maxSize = maxSize;
718         _Unwind_Backtrace(&handler, &state);
719 
720         return state.entriesWritten;
721     }
722 }
723 
724 /**
725  * Get the default `Throwable.TraceInfo` implementation for the platform
726  *
727  * This functions returns a trace handler, allowing to inspect the
728  * current stack trace.
729  *
730  * IMPORTANT NOTE! the returned trace is potentially not GC allocated, and so
731  * you must call `defaultTraceDeallocator` when you are finished with the
732  * `TraceInfo`
733  *
734  * Params:
735  *   ptr = (Windows only) The context to get the stack trace from.
736  *         When `null` (the default), start from the current frame.
737  *
738  * Returns:
739  *   A `Throwable.TraceInfo` implementation suitable to iterate over the stack,
740  *   or `null`. If called from a finalizer (destructor), always returns `null`
741  *   as trace handlers allocate.
742  */
743 Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) // @nogc
744 {
745     // NOTE: with traces now being allocated using C malloc, no need to worry
746     // about GC reentrancy. This code left commented out for reference.
747     //
748     // avoid recursive GC calls in finalizer, trace handlers should be made @nogc instead
749     /*import core.memory : GC;
750     if (GC.inFinalizer)
751         return null;*/
752 
753     static T allocate(T, Args...)(auto ref Args args) @nogc
754     {
755         import core.lifetime : emplace;
756         import core.stdc.stdlib : malloc;
757         auto result = cast(T)malloc(__traits(classInstanceSize, T));
758         return emplace(result, args);
759     }
760     version (Windows)
761     {
762         import core.sys.windows.stacktrace;
763         static if (__traits(compiles, allocate!StackTrace(0, null)))
764         {
765             import core.sys.windows.winnt : CONTEXT;
766             version (LDC)
767                 enum FIRSTFRAME = 0;
768             else version (Win64)
769                 enum FIRSTFRAME = 4;
770             else version (Win32)
771                 enum FIRSTFRAME = 0;
772             return allocate!StackTrace(FIRSTFRAME, cast(CONTEXT*)ptr);
773         }
774         else
775             return null;
776     }
777     else static if (__traits(compiles, allocate!DefaultTraceInfo()))
778         return allocate!DefaultTraceInfo();
779     else
780         return null;
781 }
782 
783 /// Example of a simple program printing its stack trace
784 unittest
785 {
786     import core.runtime;
787     import core.stdc.stdio;
788 
789     void main()
790     {
791         auto trace = defaultTraceHandler(null);
792         foreach (line; trace)
793         {
794             printf("%.*s\n", cast(int)line.length, line.ptr);
795         }
796         defaultTraceDeallocator(trace);
797     }
798 }
799 
800 /***
801  * Deallocate a traceinfo generated by deaultTraceHander.
802  *
803  * Call this function on a TraceInfo generated via `defaultTraceHandler` when
804  * you are done with it. If necessary, this cleans up any manually managed
805  * resources from the `TraceInfo`, and invalidates it. After this, the object
806  * is no longer valid.
807  *
808  * Params:
809  *      info = The `TraceInfo` to deallocate. This should only be a value that
810  *             was returned by `defaultTraceHandler`.
811  */
812 void defaultTraceDeallocator(Throwable.TraceInfo info) nothrow
813 {
814     if (info is null)
815         return;
816     auto obj = cast(Object)info;
817     destroy(obj);
818     import core.stdc.stdlib : free;
819     free(cast(void *)obj);
820 }
821 
822 version (DRuntime_Use_Libunwind)
823 {
824     import core.internal.backtrace.handler;
825 
826     alias DefaultTraceInfo = LibunwindHandler;
827 }
828 /// Default implementation for most POSIX systems
829 else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInfo
830 {
831     import core.demangle;
832     import core.stdc.stdlib : free;
833     import core.stdc.string : strlen, memchr, memmove;
834 
835     this() @nogc @system
836     {
837         // it may not be 1 but it is good enough to get
838         // in CALL instruction address range for backtrace
839         enum CALL_INSTRUCTION_SIZE = 1;
840 
841         static if (__traits(compiles, backtrace((void**).init, int.init)))
842             numframes = cast(int) backtrace(this.callstack.ptr, MAXFRAMES);
843         // Backtrace succeeded, adjust the frame to point to the caller
844         if (numframes >= 2)
845             foreach (ref elem; this.callstack)
846                 elem -= CALL_INSTRUCTION_SIZE;
847         else // backtrace() failed, do it ourselves
848         {
849           version (LDC)
850           {
851             import ldc.intrinsics;
852             auto stackTop = cast(void**) llvm_frameaddress(0);
853           }
854           else
855           {
856             static void** getBasePtr() @nogc
857             {
858                 version (D_InlineAsm_X86)
859                     asm @nogc { naked; mov EAX, EBP; ret; }
860                 else
861                     version (D_InlineAsm_X86_64)
862                         asm @nogc { naked; mov RAX, RBP; ret; }
863                 else
864                     return null;
865             }
866 
867             auto  stackTop    = getBasePtr();
868           }
869             auto  stackBottom = cast(void**) thread_stackBottom();
870             void* dummy;
871 
872             if ( stackTop && &dummy < stackTop && stackTop < stackBottom )
873             {
874                 auto stackPtr = stackTop;
875 
876                 for ( numframes = 0; stackTop <= stackPtr &&
877                           stackPtr < stackBottom &&
878                           numframes < MAXFRAMES; )
879                 {
880                     callstack[numframes++] = *(stackPtr + 1) - CALL_INSTRUCTION_SIZE;
881                     stackPtr = cast(void**) *stackPtr;
882                 }
883             }
884         }
885     }
886 
887     override int opApply( scope int delegate(ref const(char[])) dg ) const
888     {
889         return opApply( (ref size_t, ref const(char[]) buf)
890                         {
891                             return dg( buf );
892                         } );
893     }
894 
895     override int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const
896     {
897         version (linux) enum enableDwarf = true;
898         else version (FreeBSD) enum enableDwarf = true;
899         else version (DragonFlyBSD) enum enableDwarf = true;
900         else version (OpenBSD) enum enableDwarf = true;
901         else version (Darwin) enum enableDwarf = true;
902         else enum enableDwarf = false;
903 
904         const framelist = backtrace_symbols( callstack.ptr, numframes );
905         scope(exit) free(cast(void*) framelist);
906 
907         static if (enableDwarf)
908         {
909             import core.internal.backtrace.dwarf;
910             return traceHandlerOpApplyImpl(numframes,
911                 i => callstack[i],
912                 (i) { auto str = framelist[i][0 .. strlen(framelist[i])]; return getMangledSymbolName(str); },
913                 dg);
914         }
915         else
916         {
917             int ret = 0;
918             for (size_t pos = 0; pos < numframes; ++pos)
919             {
920                 char[4096] fixbuf = void;
921                 auto buf = framelist[pos][0 .. strlen(framelist[pos])];
922                 buf = fixline( buf, fixbuf );
923                 ret = dg( pos, buf );
924                 if ( ret )
925                     break;
926             }
927             return ret;
928         }
929     }
930 
931     override string toString() const
932     {
933         string buf;
934         foreach ( i, line; this )
935             buf ~= i ? "\n" ~ line : line;
936         return buf;
937     }
938 
939 private:
940     int     numframes;
941     static enum MAXFRAMES = 128;
942     void*[MAXFRAMES]  callstack = void;
943 
944 private:
945     const(char)[] fixline( const(char)[] buf, return ref char[4096] fixbuf ) const @system
946     {
947         size_t symBeg, symEnd;
948 
949         getMangledSymbolName(buf, symBeg, symEnd);
950 
951         enum min = (size_t a, size_t b) => a <= b ? a : b;
952         if (symBeg == symEnd || symBeg >= fixbuf.length)
953         {
954             immutable len = min(buf.length, fixbuf.length);
955             fixbuf[0 .. len] = buf[0 .. len];
956             return fixbuf[0 .. len];
957         }
958         else
959         {
960             fixbuf[0 .. symBeg] = buf[0 .. symBeg];
961 
962             auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $], getCXXDemangler());
963 
964             if (sym.ptr !is fixbuf.ptr + symBeg)
965             {
966                 // demangle reallocated the buffer, copy the symbol to fixbuf
967                 immutable len = min(fixbuf.length - symBeg, sym.length);
968                 memmove(fixbuf.ptr + symBeg, sym.ptr, len);
969                 if (symBeg + len == fixbuf.length)
970                     return fixbuf[];
971             }
972 
973             immutable pos = symBeg + sym.length;
974             assert(pos < fixbuf.length);
975             immutable tail = buf.length - symEnd;
976             immutable len = min(fixbuf.length - pos, tail);
977             fixbuf[pos .. pos + len] = buf[symEnd .. symEnd + len];
978             return fixbuf[0 .. pos + len];
979         }
980     }
981 }