/** * The demangle module converts mangled D symbols to a representation similar * to what would have existed in code. * * Copyright: Copyright Sean Kelly 2010 - 2014. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/_demangle.d) */ module core.demangle; version (OSX) version = Darwin;else version (iOS) version = Darwin;else version (TVOS) version = Darwin;else version (WatchOS) version = Darwin; debug (trace) debug = needPrintf;debug (info) debug = needPrintf; debug (needPrintf)private int printf(Args...)(scope const char* fmt, scope const Args args) => __ctfe ? 0 : imported!"core.stdc.stdio".printf(fmt, args); extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name, char* output_buffer, size_t* length, int* status) nothrow pure @trusted; private struct NoHooks{ // supported hooks // static bool parseLName(ref Demangle); // static char[] parseType(ref Demangle, char[])} private struct Demangle(Hooks = NoHooks){ // NOTE: This implementation currently only works with mangled function // names as they exist in an object file. Type names mangled via // the .mangleof property are effectively incomplete as far as the // ABI is concerned and so are not considered to be mangled symbol // names. // NOTE: This implementation builds the demangled buffer in place by // writing data as it is decoded and then rearranging it later as // needed. In practice this results in very little data movement, // and the performance cost is more than offset by the gain from // not allocating dynamic memory to assemble the name piecemeal. // // If the destination buffer is too small, parsing will restart // with a larger buffer. Since this generally means only one // allocation during the course of a parsing run, this is still // faster than assembling the result piecemeal. pure @safe: enum AddType { no, yes } this( return scope const(char)[] buf_, return scope char[] dst_ = null ) { this( buf_, AddType.yes, dst_ ); } this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null ) { buf = buf_; addType = addType_; dst.dst = dst_; } const(char)[] buf = null; Buffer dst; size_t pos = 0; size_t brp = 0; // current back reference pos AddType addType = AddType.yes; bool mute = false; Hooks hooks; ////////////////////////////////////////////////////////////////////////// // Type Testing and Conversion ////////////////////////////////////////////////////////////////////////// static bool isAlpha( char val ) { return ('a' <= val && 'z' >= val) || ('A' <= val && 'Z' >= val) || (0x80 & val); // treat all unicode as alphabetic } static bool isDigit( char val ) nothrow { return '0' <= val && '9' >= val; } static bool isHexDigit( char val ) { return ('0' <= val && '9' >= val) || ('a' <= val && 'f' >= val) || ('A' <= val && 'F' >= val); } static ubyte ascii2hex( out bool errStatus, char val ) nothrow { if (val >= 'a' && val <= 'f') return cast(ubyte)(val - 'a' + 10); if (val >= 'A' && val <= 'F') return cast(ubyte)(val - 'A' + 10); if (val >= '0' && val <= '9') return cast(ubyte)(val - '0'); errStatus = true; return 0; } BufSlice shift(scope const BufSlice val) return scope { if (mute) return dst.bslice_empty; return dst.shift(val); } void putComma(size_t n) { version (DigitalMars) pragma(inline, false); if (n) put(", "); } void put(char c) return scope { char[1] val = c; put(val[]); } void put(scope BufSlice val) return scope { put(val.getSlice); } void put(scope const(char)[] val) return scope nothrow { if (mute) return; dst.append(val); } void putAsHex( size_t val, int width = 0 ) { import core.internal.string; UnsignedStringBuf buf = void; auto s = unsignedToTempString!16(val, buf); int slen = cast(int)s.length; if (slen < width) { foreach (i; slen .. width) put('0'); } put(s); } void pad( const(char)[] val ) { if ( val.length ) { put(" "); put( val ); } } void silent( out bool err_status, void delegate(out bool err_status) pure @safe nothrow dg ) nothrow { debug(trace) printf( "silent+\n" ); debug(trace) scope(success) printf( "silent-\n" ); auto n = dst.length; dg(err_status); if(!err_status) dst.len = n; } ////////////////////////////////////////////////////////////////////////// // Parsing Utility ////////////////////////////////////////////////////////////////////////// @property bool empty() { return pos >= buf.length; } @property char front() { if ( pos < buf.length ) return buf[pos]; return char.init; } char peek( size_t n ) { if ( pos + n < buf.length ) return buf[pos + n]; return char.init; } bool test( char val ) nothrow { return val == front; } void popFront() nothrow { if ( pos++ >= buf.length ) assert(false); } void popFront(int i) nothrow { while (i--) popFront(); } bool match( char val ) nothrow { if (!test(val)) return false; else { popFront(); return true; } } bool match( const(char)[] val ) nothrow { foreach (char e; val ) if (!match( e )) return false; return true; } void eat( char val ) { if ( val == front ) popFront(); } bool isSymbolNameFront(out bool errStatus) nothrow { char val = front; if ( isDigit( val ) || val == '_' ) return true; if ( val != 'Q' ) return false; // check the back reference encoding after 'Q' val = peekBackref(); if (val == 0) { // invalid back reference errStatus = true; return false; } return isDigit( val ); // identifier ref } // return the first character at the back reference char peekBackref() nothrow { assert( front == 'Q' ); auto n = decodeBackref!1(); if (!n || n > pos) return 0; // invalid back reference return buf[pos - n]; } size_t decodeBackref(size_t peekAt = 0)() nothrow { enum base = 26; size_t n = 0; for (size_t p; ; p++) { char t; static if (peekAt > 0) { t = peek(peekAt + p); } else { t = front; popFront(); } if (t < 'A' || t > 'Z') { if (t < 'a' || t > 'z') return 0; // invalid back reference n = base * n + t - 'a'; return n; } n = base * n + t - 'A'; } } ////////////////////////////////////////////////////////////////////////// // Parsing Implementation ////////////////////////////////////////////////////////////////////////// /* Number: Digit Digit Number */ const(char)[] sliceNumber() return scope { debug(trace) printf( "sliceNumber+\n" ); debug(trace) scope(success) printf( "sliceNumber-\n" ); auto beg = pos; while ( true ) { auto t = front; if (t >= '0' && t <= '9') popFront(); else return buf[beg .. pos]; } } size_t decodeNumber(out bool errStatus) scope nothrow { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); return decodeNumber( errStatus, sliceNumber() ); } size_t decodeNumber( out bool errStatus, scope const(char)[] num ) scope nothrow { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); size_t val = 0; foreach ( c; num ) { import core.checkedint : mulu, addu; bool overflow = false; val = mulu(val, 10, overflow); val = addu(val, c - '0', overflow); if (overflow) { errStatus = true; return 0; } } return val; } void parseReal(out bool errStatus) scope nothrow { debug(trace) printf( "parseReal+\n" ); debug(trace) scope(success) printf( "parseReal-\n" ); char[64] tbuf = void; size_t tlen = 0; real val = void; void onError() { errStatus = true; } if ( 'I' == front ) { if (!match("INF")) return onError(); put( "real.infinity" ); return; } if ( 'N' == front ) { popFront(); if ( 'I' == front ) { if (!match("INF")) return onError(); put( "-real.infinity" ); return; } if ( 'A' == front ) { if (!match("AN")) return onError(); put( "real.nan" ); return; } tbuf[tlen++] = '-'; } tbuf[tlen++] = '0'; tbuf[tlen++] = 'X'; errStatus = !isHexDigit( front ); if (errStatus) return; // Expected hex digit tbuf[tlen++] = front; tbuf[tlen++] = '.'; popFront(); while ( isHexDigit( front ) ) { if (tlen >= tbuf.length) return onError(); // Too many hex float digits tbuf[tlen++] = front; popFront(); } if (!match('P')) return onError(); tbuf[tlen++] = 'p'; if ( 'N' == front ) { tbuf[tlen++] = '-'; popFront(); } else { tbuf[tlen++] = '+'; } while ( isDigit( front ) ) { tbuf[tlen++] = front; popFront(); } tbuf[tlen] = 0; debug(info) printf( "got (%s)\n", tbuf.ptr ); pureReprintReal( tbuf[] ); debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr ); put( tbuf[0 .. tlen] ); } /* LName: Number Name Name: Namestart Namestart Namechars Namestart: _ Alpha Namechar: Namestart Digit Namechars: Namechar Namechar Namechars */ void parseLName(out string errMsg) scope nothrow { debug(trace) printf( "parseLName+\n" ); debug(trace) scope(success) printf( "parseLName-\n" ); static if (__traits(hasMember, Hooks, "parseLName")) { auto r = hooks.parseLName(errMsg, this); if (errMsg !is null) return; if (r) return;Lines 1–500 of 3224. Load more
/** * The demangle module converts mangled D symbols to a representation similar * to what would have existed in code. * * Copyright: Copyright Sean Kelly 2010 - 2014. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly * Source: $(DRUNTIMESRC core/_demangle.d) */ module core.demangle; version (OSX) version = Darwin; else version (iOS) version = Darwin; else version (TVOS) version = Darwin; else version (WatchOS) version = Darwin; debug (trace) debug = needPrintf; debug (info) debug = needPrintf; debug (needPrintf) private int printf(Args...)(scope const char* fmt, scope const Args args) => __ctfe ? 0 : imported!"core.stdc.stdio".printf(fmt, args); extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name, char* output_buffer, size_t* length, int* status) nothrow pure @trusted; private struct NoHooks { // supported hooks // static bool parseLName(ref Demangle); // static char[] parseType(ref Demangle, char[]) } private struct Demangle(Hooks = NoHooks) { // NOTE: This implementation currently only works with mangled function // names as they exist in an object file. Type names mangled via // the .mangleof property are effectively incomplete as far as the // ABI is concerned and so are not considered to be mangled symbol // names. // NOTE: This implementation builds the demangled buffer in place by // writing data as it is decoded and then rearranging it later as // needed. In practice this results in very little data movement, // and the performance cost is more than offset by the gain from // not allocating dynamic memory to assemble the name piecemeal. // // If the destination buffer is too small, parsing will restart // with a larger buffer. Since this generally means only one // allocation during the course of a parsing run, this is still // faster than assembling the result piecemeal. pure @safe: enum AddType { no, yes } this( return scope const(char)[] buf_, return scope char[] dst_ = null ) { this( buf_, AddType.yes, dst_ ); } this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null ) { buf = buf_; addType = addType_; dst.dst = dst_; } const(char)[] buf = null; Buffer dst; size_t pos = 0; size_t brp = 0; // current back reference pos AddType addType = AddType.yes; bool mute = false; Hooks hooks; ////////////////////////////////////////////////////////////////////////// // Type Testing and Conversion ////////////////////////////////////////////////////////////////////////// static bool isAlpha( char val ) { return ('a' <= val && 'z' >= val) || ('A' <= val && 'Z' >= val) || (0x80 & val); // treat all unicode as alphabetic } static bool isDigit( char val ) nothrow { return '0' <= val && '9' >= val; } static bool isHexDigit( char val ) { return ('0' <= val && '9' >= val) || ('a' <= val && 'f' >= val) || ('A' <= val && 'F' >= val); } static ubyte ascii2hex( out bool errStatus, char val ) nothrow { if (val >= 'a' && val <= 'f') return cast(ubyte)(val - 'a' + 10); if (val >= 'A' && val <= 'F') return cast(ubyte)(val - 'A' + 10); if (val >= '0' && val <= '9') return cast(ubyte)(val - '0'); errStatus = true; return 0; } BufSlice shift(scope const BufSlice val) return scope { if (mute) return dst.bslice_empty; return dst.shift(val); } void putComma(size_t n) { version (DigitalMars) pragma(inline, false); if (n) put(", "); } void put(char c) return scope { char[1] val = c; put(val[]); } void put(scope BufSlice val) return scope { put(val.getSlice); } void put(scope const(char)[] val) return scope nothrow { if (mute) return; dst.append(val); } void putAsHex( size_t val, int width = 0 ) { import core.internal.string; UnsignedStringBuf buf = void; auto s = unsignedToTempString!16(val, buf); int slen = cast(int)s.length; if (slen < width) { foreach (i; slen .. width) put('0'); } put(s); } void pad( const(char)[] val ) { if ( val.length ) { put(" "); put( val ); } } void silent( out bool err_status, void delegate(out bool err_status) pure @safe nothrow dg ) nothrow { debug(trace) printf( "silent+\n" ); debug(trace) scope(success) printf( "silent-\n" ); auto n = dst.length; dg(err_status); if(!err_status) dst.len = n; } ////////////////////////////////////////////////////////////////////////// // Parsing Utility ////////////////////////////////////////////////////////////////////////// @property bool empty() { return pos >= buf.length; } @property char front() { if ( pos < buf.length ) return buf[pos]; return char.init; } char peek( size_t n ) { if ( pos + n < buf.length ) return buf[pos + n]; return char.init; } bool test( char val ) nothrow { return val == front; } void popFront() nothrow { if ( pos++ >= buf.length ) assert(false); } void popFront(int i) nothrow { while (i--) popFront(); } bool match( char val ) nothrow { if (!test(val)) return false; else { popFront(); return true; } } bool match( const(char)[] val ) nothrow { foreach (char e; val ) if (!match( e )) return false; return true; } void eat( char val ) { if ( val == front ) popFront(); } bool isSymbolNameFront(out bool errStatus) nothrow { char val = front; if ( isDigit( val ) || val == '_' ) return true; if ( val != 'Q' ) return false; // check the back reference encoding after 'Q' val = peekBackref(); if (val == 0) { // invalid back reference errStatus = true; return false; } return isDigit( val ); // identifier ref } // return the first character at the back reference char peekBackref() nothrow { assert( front == 'Q' ); auto n = decodeBackref!1(); if (!n || n > pos) return 0; // invalid back reference return buf[pos - n]; } size_t decodeBackref(size_t peekAt = 0)() nothrow { enum base = 26; size_t n = 0; for (size_t p; ; p++) { char t; static if (peekAt > 0) { t = peek(peekAt + p); } else { t = front; popFront(); } if (t < 'A' || t > 'Z') { if (t < 'a' || t > 'z') return 0; // invalid back reference n = base * n + t - 'a'; return n; } n = base * n + t - 'A'; } } ////////////////////////////////////////////////////////////////////////// // Parsing Implementation ////////////////////////////////////////////////////////////////////////// /* Number: Digit Digit Number */ const(char)[] sliceNumber() return scope { debug(trace) printf( "sliceNumber+\n" ); debug(trace) scope(success) printf( "sliceNumber-\n" ); auto beg = pos; while ( true ) { auto t = front; if (t >= '0' && t <= '9') popFront(); else return buf[beg .. pos]; } } size_t decodeNumber(out bool errStatus) scope nothrow { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); return decodeNumber( errStatus, sliceNumber() ); } size_t decodeNumber( out bool errStatus, scope const(char)[] num ) scope nothrow { debug(trace) printf( "decodeNumber+\n" ); debug(trace) scope(success) printf( "decodeNumber-\n" ); size_t val = 0; foreach ( c; num ) { import core.checkedint : mulu, addu; bool overflow = false; val = mulu(val, 10, overflow); val = addu(val, c - '0', overflow); if (overflow) { errStatus = true; return 0; } } return val; } void parseReal(out bool errStatus) scope nothrow { debug(trace) printf( "parseReal+\n" ); debug(trace) scope(success) printf( "parseReal-\n" ); char[64] tbuf = void; size_t tlen = 0; real val = void; void onError() { errStatus = true; } if ( 'I' == front ) { if (!match("INF")) return onError(); put( "real.infinity" ); return; } if ( 'N' == front ) { popFront(); if ( 'I' == front ) { if (!match("INF")) return onError(); put( "-real.infinity" ); return; } if ( 'A' == front ) { if (!match("AN")) return onError(); put( "real.nan" ); return; } tbuf[tlen++] = '-'; } tbuf[tlen++] = '0'; tbuf[tlen++] = 'X'; errStatus = !isHexDigit( front ); if (errStatus) return; // Expected hex digit tbuf[tlen++] = front; tbuf[tlen++] = '.'; popFront(); while ( isHexDigit( front ) ) { if (tlen >= tbuf.length) return onError(); // Too many hex float digits tbuf[tlen++] = front; popFront(); } if (!match('P')) return onError(); tbuf[tlen++] = 'p'; if ( 'N' == front ) { tbuf[tlen++] = '-'; popFront(); } else { tbuf[tlen++] = '+'; } while ( isDigit( front ) ) { tbuf[tlen++] = front; popFront(); } tbuf[tlen] = 0; debug(info) printf( "got (%s)\n", tbuf.ptr ); pureReprintReal( tbuf[] ); debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr ); put( tbuf[0 .. tlen] ); } /* LName: Number Name Name: Namestart Namestart Namechars Namestart: _ Alpha Namechar: Namestart Digit Namechars: Namechar Namechar Namechars */ void parseLName(out string errMsg) scope nothrow { debug(trace) printf( "parseLName+\n" ); debug(trace) scope(success) printf( "parseLName-\n" ); static if (__traits(hasMember, Hooks, "parseLName")) { auto r = hooks.parseLName(errMsg, this); if (errMsg !is null) return; if (r) return;