|  | // Copyright (c) 2017, Patrick Quist | 
|  | // All rights reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright notice, | 
|  | //       this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above copyright | 
|  | //       notice, this list of conditions and the following disclaimer in the | 
|  | //       documentation and/or other materials provided with the distribution. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
|  | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | 
|  | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
|  | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
|  | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
|  | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
|  | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
|  | // POSSIBILITY OF SUCH DAMAGE. | 
|  | "use strict"; | 
|  |  | 
|  | const SymbolStore = require("./symbol-store").SymbolStore; | 
|  | const Demangler = require("./demangler").Demangler; | 
|  |  | 
|  | class PascalDemangler extends Demangler { | 
|  | constructor(demanglerExe, symbolstore) { | 
|  | super(demanglerExe, symbolstore); | 
|  |  | 
|  | this.symbolStore = new SymbolStore(); | 
|  | this.fixedsymbols = {}; | 
|  | this.ignoredsymbols = []; | 
|  |  | 
|  | this.initBasicSymbols(); | 
|  | } | 
|  |  | 
|  | initBasicSymbols() { | 
|  | this.fixedsymbols.OUTPUT_$$_init = 'unit_initialization'; | 
|  | this.fixedsymbols.OUTPUT_$$_finalize = 'unit_finalization'; | 
|  | this.fixedsymbols.OUTPUT_$$_init_implicit = 'unit_initialization_implicit'; | 
|  | this.fixedsymbols.OUTPUT_$$_finalize_implicit = 'unit_finalization_implicit'; | 
|  | this.fixedsymbols.OUTPUT_init = 'unit_initialization'; | 
|  | this.fixedsymbols.OUTPUT_finalize = 'unit_finalization'; | 
|  | this.fixedsymbols.OUTPUT_init_implicit = 'unit_initialization_implicit'; | 
|  | this.fixedsymbols.OUTPUT_finalize_implicit = 'unit_finalization_implicit'; | 
|  |  | 
|  | this.ignoredsymbols = [ | 
|  | ".L", | 
|  | "VMT_$", "INIT_$", "INIT$_$", "FINALIZE$_$", "RTTI_$", | 
|  | "VMT_OUTPUT_", "INIT$_OUTPUT", "RTTI_OUTPUT_", "FINALIZE$_OUTPUT", | 
|  | "_$", | 
|  | "DEBUGSTART_$", "DEBUGEND_$", "DBG_$", "DBG2_$", "DBGREF_$", | 
|  | "DEBUGSTART_OUTPUT", "DEBUGEND_OUTPUT", "DBG_OUTPUT_", "DBG2_OUTPUT_", "DBGREF_OUTPUT_" | 
|  | ]; | 
|  | } | 
|  |  | 
|  | shouldIgnoreSymbol(text) { | 
|  | for (let k in this.ignoredsymbols) { | 
|  | if (text.startsWith(this.ignoredsymbols[k])) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | composeReadableMethodSignature(unitname, classname, methodname, params) { | 
|  | let signature = ""; | 
|  |  | 
|  | if (classname !== "") signature = classname.toLowerCase() + "."; | 
|  |  | 
|  | signature = signature + methodname.toLowerCase(); | 
|  | signature = signature + "(" + params.toLowerCase() + ")"; | 
|  |  | 
|  | return signature; | 
|  | } | 
|  |  | 
|  | demangle(text) { | 
|  | if (!text.endsWith(':')) return false; | 
|  | if (this.shouldIgnoreSymbol(text)) return false; | 
|  |  | 
|  | text = text.substr(0, text.length - 1); | 
|  |  | 
|  | for (let k in this.fixedsymbols) { | 
|  | if (text === k) { | 
|  | text = text.replace(k, this.fixedsymbols[k]); | 
|  | this.symbolStore.add(k, this.fixedsymbols[k]); | 
|  | return this.fixedsymbols[k]; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (text.startsWith("U_$OUTPUT_$$_")) { | 
|  | let unmangledGlobalVar = text.substr(13).toLowerCase(); | 
|  | this.symbolStore.add(text, unmangledGlobalVar); | 
|  | return unmangledGlobalVar; | 
|  | } else if (text.startsWith("U_OUTPUT_")) { | 
|  | let unmangledGlobalVar = text.substr(9).toLowerCase(); | 
|  | this.symbolStore.add(text, unmangledGlobalVar); | 
|  | return unmangledGlobalVar; | 
|  | } | 
|  |  | 
|  | let idx, paramtype = "", phase = 0; | 
|  | let unitname = "", classname = "", methodname = "", params = "", resulttype = ""; | 
|  |  | 
|  | idx = text.indexOf("$_$"); | 
|  | if (idx !== -1) { | 
|  | unitname = text.substr(0, idx - 1); | 
|  | classname = text.substr(idx + 3, text.indexOf("_$_", idx + 2) - idx - 3); | 
|  | } | 
|  |  | 
|  | let signature = ""; | 
|  | idx = text.indexOf("_$$_"); | 
|  | if (idx !== -1) { | 
|  | if (unitname === "") unitname = text.substr(0, idx - 1); | 
|  | signature = text.substr(idx + 3); | 
|  | } | 
|  |  | 
|  | if (unitname === "") { | 
|  | idx = text.indexOf("OUTPUT_"); | 
|  | if (idx !== -1) { | 
|  | unitname = "OUTPUT"; | 
|  |  | 
|  | idx = text.indexOf("_$__"); | 
|  | if (idx !== -1) { | 
|  | classname = text.substr(7, idx - 7); | 
|  | signature = text.substr(idx + 3); | 
|  | } else { | 
|  | signature = text.substr(6); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (signature !== "") { | 
|  | for (idx = 1; idx < signature.length; idx++) { | 
|  | if (signature[idx] === '$') { | 
|  | if (phase === 0) phase = 1; | 
|  | else if (phase === 1) { | 
|  | if (paramtype === "") phase = 2; | 
|  | else if (params !== "") { | 
|  | params = params + "," + paramtype; | 
|  | paramtype = ""; | 
|  | } else if (params === "") { | 
|  | params = paramtype; | 
|  | paramtype = ""; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | if (phase === 0) methodname = methodname + signature[idx]; | 
|  | else if (phase === 1) paramtype = paramtype + signature[idx]; | 
|  | else if (phase === 2) resulttype = resulttype + signature[idx]; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (paramtype !== "") { | 
|  | if (params !== "") params = params + "," + paramtype; | 
|  | else params = paramtype; | 
|  | } | 
|  | } | 
|  |  | 
|  | const unmangled = this.composeReadableMethodSignature(unitname, classname, methodname, params); | 
|  | this.symbolStore.add(text, unmangled); | 
|  |  | 
|  | return unmangled; | 
|  | } | 
|  |  | 
|  | addDemangleToCache(text) { | 
|  | this.demangle(text); | 
|  | } | 
|  |  | 
|  | demangleIfNeeded(text) { | 
|  | if (text.includes('$')) { | 
|  | if (this.shouldIgnoreSymbol(text)) { | 
|  | return text; | 
|  | } | 
|  |  | 
|  | const translations = this.symbolStore.listTranslations(); | 
|  | for (let idx in translations) { | 
|  | text = text.replace(translations[idx][0], translations[idx][1]); | 
|  | } | 
|  |  | 
|  | return text; | 
|  | } else { | 
|  | return text; | 
|  | } | 
|  | } | 
|  |  | 
|  | process(result, execOptions) { | 
|  | let options = execOptions || {}; | 
|  | this.result = result; | 
|  |  | 
|  | if (!this.symbolstore) { | 
|  | this.symbolstore = new SymbolStore(); | 
|  | this.collectLabels(); | 
|  | } | 
|  |  | 
|  | options.input = this.getInput(); | 
|  |  | 
|  | return options.input; | 
|  | } | 
|  | } | 
|  |  | 
|  | exports.Demangler = PascalDemangler; |