| // Copyright (c) 2017, Compiler Explorer Authors |
| // 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. |
| |
| import {SymbolStore} from '../symbol-store'; |
| |
| import {BaseDemangler} from './base'; |
| |
| export class PascalDemangler extends BaseDemangler { |
| static get key() { |
| return 'pascal'; |
| } |
| |
| constructor(demanglerExe, compiler) { |
| super(demanglerExe, compiler); |
| |
| 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 (const 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_$$_')) { |
| const unmangledGlobalVar = text.substr(13).toLowerCase(); |
| this.symbolStore.add(text, unmangledGlobalVar); |
| return unmangledGlobalVar; |
| } else if (text.startsWith('U_OUTPUT_')) { |
| const 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) { |
| signature = text.substr(6); |
| } else { |
| classname = text.substr(7, idx - 7); |
| signature = text.substr(idx + 3); |
| } |
| } |
| } |
| |
| 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 = paramtype; |
| } else { |
| params = 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 (const idx in translations) { |
| text = text.replace(translations[idx][0], translations[idx][1]); |
| } |
| |
| return text; |
| } else { |
| return text; |
| } |
| } |
| |
| async 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; |
| } |
| } |