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() 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 /** 674 * Get the default `Throwable.TraceInfo` implementation for the platform 675 * 676 * This functions returns a trace handler, allowing to inspect the 677 * current stack trace. 678 * 679 * IMPORTANT NOTE! the returned trace is potentially not GC allocated, and so 680 * you must call `defaultTraceDeallocator` when you are finished with the 681 * `TraceInfo` 682 * 683 * Params: 684 * ptr = (Windows only) The context to get the stack trace from. 685 * When `null` (the default), start from the current frame. 686 * 687 * Returns: 688 * A `Throwable.TraceInfo` implementation suitable to iterate over the stack, 689 * or `null`. If called from a finalizer (destructor), always returns `null` 690 * as trace handlers allocate. 691 */ 692 Throwable.TraceInfo defaultTraceHandler( void* ptr = null ) // @nogc 693 { 694 // NOTE: with traces now being allocated using C malloc, no need to worry 695 // about GC reentrancy. This code left commented out for reference. 696 // 697 // avoid recursive GC calls in finalizer, trace handlers should be made @nogc instead 698 /*import core.memory : GC; 699 if (GC.inFinalizer) 700 return null;*/ 701 702 static T allocate(T, Args...)(auto ref Args args) @nogc 703 { 704 import core.lifetime : emplace; 705 import core.stdc.stdlib : malloc; 706 auto result = cast(T)malloc(__traits(classInstanceSize, T)); 707 return emplace(result, args); 708 } 709 version (Windows) 710 { 711 import core.sys.windows.stacktrace; 712 static if (__traits(compiles, allocate!StackTrace(0, null))) 713 { 714 import core.sys.windows.winnt : CONTEXT; 715 version (Win64) 716 enum FIRSTFRAME = 4; 717 else version (Win32) 718 enum FIRSTFRAME = 0; 719 return allocate!StackTrace(FIRSTFRAME, cast(CONTEXT*)ptr); 720 } 721 else 722 return null; 723 } 724 else static if (__traits(compiles, allocate!DefaultTraceInfo())) 725 return allocate!DefaultTraceInfo(); 726 else 727 return null; 728 } 729 730 /// Example of a simple program printing its stack trace 731 unittest 732 { 733 import core.runtime; 734 import core.stdc.stdio; 735 736 void main() 737 { 738 auto trace = defaultTraceHandler(null); 739 foreach (line; trace) 740 { 741 printf("%.*s\n", cast(int)line.length, line.ptr); 742 } 743 defaultTraceDeallocator(trace); 744 } 745 } 746 747 /*** 748 * Deallocate a traceinfo generated by deaultTraceHander. 749 * 750 * Call this function on a TraceInfo generated via `defaultTraceHandler` when 751 * you are done with it. If necessary, this cleans up any manually managed 752 * resources from the `TraceInfo`, and invalidates it. After this, the object 753 * is no longer valid. 754 * 755 * Params: 756 * info = The `TraceInfo` to deallocate. This should only be a value that 757 * was returned by `defaultTraceHandler`. 758 */ 759 void defaultTraceDeallocator(Throwable.TraceInfo info) nothrow 760 { 761 if (info is null) 762 return; 763 auto obj = cast(Object)info; 764 destroy(obj); 765 import core.stdc.stdlib : free; 766 free(cast(void *)obj); 767 } 768 769 version (DRuntime_Use_Libunwind) 770 { 771 import core.internal.backtrace.handler; 772 773 alias DefaultTraceInfo = LibunwindHandler; 774 } 775 /// Default implementation for most POSIX systems 776 else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInfo 777 { 778 import core.demangle; 779 import core.stdc.stdlib : free; 780 import core.stdc.string : strlen, memchr, memmove; 781 782 this() @nogc 783 { 784 // it may not be 1 but it is good enough to get 785 // in CALL instruction address range for backtrace 786 enum CALL_INSTRUCTION_SIZE = 1; 787 788 static if (__traits(compiles, backtrace((void**).init, int.init))) 789 numframes = cast(int) backtrace(this.callstack.ptr, MAXFRAMES); 790 // Backtrace succeeded, adjust the frame to point to the caller 791 if (numframes >= 2) 792 foreach (ref elem; this.callstack) 793 elem -= CALL_INSTRUCTION_SIZE; 794 else // backtrace() failed, do it ourselves 795 { 796 static void** getBasePtr() @nogc 797 { 798 version (D_InlineAsm_X86) 799 asm @nogc { naked; mov EAX, EBP; ret; } 800 else 801 version (D_InlineAsm_X86_64) 802 asm @nogc { naked; mov RAX, RBP; ret; } 803 else 804 return null; 805 } 806 807 auto stackTop = getBasePtr(); 808 auto stackBottom = cast(void**) thread_stackBottom(); 809 void* dummy; 810 811 if ( stackTop && &dummy < stackTop && stackTop < stackBottom ) 812 { 813 auto stackPtr = stackTop; 814 815 for ( numframes = 0; stackTop <= stackPtr && 816 stackPtr < stackBottom && 817 numframes < MAXFRAMES; ) 818 { 819 callstack[numframes++] = *(stackPtr + 1) - CALL_INSTRUCTION_SIZE; 820 stackPtr = cast(void**) *stackPtr; 821 } 822 } 823 } 824 } 825 826 override int opApply( scope int delegate(ref const(char[])) dg ) const 827 { 828 return opApply( (ref size_t, ref const(char[]) buf) 829 { 830 return dg( buf ); 831 } ); 832 } 833 834 override int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const 835 { 836 version (linux) enum enableDwarf = true; 837 else version (FreeBSD) enum enableDwarf = true; 838 else version (DragonFlyBSD) enum enableDwarf = true; 839 else version (OpenBSD) enum enableDwarf = true; 840 else version (Darwin) enum enableDwarf = true; 841 else enum enableDwarf = false; 842 843 const framelist = backtrace_symbols( callstack.ptr, numframes ); 844 scope(exit) free(cast(void*) framelist); 845 846 static if (enableDwarf) 847 { 848 import core.internal.backtrace.dwarf; 849 return traceHandlerOpApplyImpl(numframes, 850 i => callstack[i], 851 (i) { auto str = framelist[i][0 .. strlen(framelist[i])]; return getMangledSymbolName(str); }, 852 dg); 853 } 854 else 855 { 856 int ret = 0; 857 for (size_t pos = 0; pos < numframes; ++pos) 858 { 859 char[4096] fixbuf = void; 860 auto buf = framelist[pos][0 .. strlen(framelist[pos])]; 861 buf = fixline( buf, fixbuf ); 862 ret = dg( pos, buf ); 863 if ( ret ) 864 break; 865 } 866 return ret; 867 } 868 } 869 870 override string toString() const 871 { 872 string buf; 873 foreach ( i, line; this ) 874 buf ~= i ? "\n" ~ line : line; 875 return buf; 876 } 877 878 private: 879 int numframes; 880 static enum MAXFRAMES = 128; 881 void*[MAXFRAMES] callstack = void; 882 883 private: 884 const(char)[] fixline( const(char)[] buf, return ref char[4096] fixbuf ) const 885 { 886 size_t symBeg, symEnd; 887 888 getMangledSymbolName(buf, symBeg, symEnd); 889 890 enum min = (size_t a, size_t b) => a <= b ? a : b; 891 if (symBeg == symEnd || symBeg >= fixbuf.length) 892 { 893 immutable len = min(buf.length, fixbuf.length); 894 fixbuf[0 .. len] = buf[0 .. len]; 895 return fixbuf[0 .. len]; 896 } 897 else 898 { 899 fixbuf[0 .. symBeg] = buf[0 .. symBeg]; 900 901 auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $], getCXXDemangler()); 902 903 if (sym.ptr !is fixbuf.ptr + symBeg) 904 { 905 // demangle reallocated the buffer, copy the symbol to fixbuf 906 immutable len = min(fixbuf.length - symBeg, sym.length); 907 memmove(fixbuf.ptr + symBeg, sym.ptr, len); 908 if (symBeg + len == fixbuf.length) 909 return fixbuf[]; 910 } 911 912 immutable pos = symBeg + sym.length; 913 assert(pos < fixbuf.length); 914 immutable tail = buf.length - symEnd; 915 immutable len = min(fixbuf.length - pos, tail); 916 fixbuf[pos .. pos + len] = buf[symEnd .. symEnd + len]; 917 return fixbuf[0 .. pos + len]; 918 } 919 } 920 }