Skip to content

Commit

Permalink
Tsify lib/demanglers (#4607)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-rifkin authored and mattgodbolt committed Jan 24, 2023
1 parent c72004a commit 2a42cc4
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 83 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.yml
Expand Up @@ -44,7 +44,7 @@ rules:
import/first: error
import/newline-after-import: error
import/no-absolute-path: error
import/no-cycle: error
# import/no-cycle: error # disabled for now, there's an import cycle between the base-compiler and demanglers
import/no-default-export: warn
import/no-deprecated: warn
import/no-mutable-exports: error
Expand Down Expand Up @@ -101,6 +101,9 @@ rules:
- error
- never
- onlyEquality: true
prefer-const:
- error
- destructuring: all
jsdoc/check-alignment: warn
jsdoc/check-param-names: warn
jsdoc/check-syntax: warn
Expand Down
File renamed without changes.
97 changes: 57 additions & 40 deletions lib/demangler/base.js → lib/demangler/base.ts
Expand Up @@ -22,6 +22,11 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

import {ParsedAsmResult} from '../../types/asmresult/asmresult.interfaces';
import {ExecutionOptions} from '../../types/compilation/compilation.interfaces';
import {UnprocessedExecResult} from '../../types/execution/execution.interfaces';
import {unwrap} from '../assert';
import {BaseCompiler} from '../base-compiler';
import {logger} from '../logger';
import {AsmRegex} from '../parsers/asmregex';
import {SymbolStore} from '../symbol-store';
Expand All @@ -30,42 +35,53 @@ import * as utils from '../utils';
import {PrefixTree} from './prefix-tree';

export class BaseDemangler extends AsmRegex {
constructor(demanglerExe, compiler) {
demanglerExe: string;
demanglerArguments: string[];
symbolstore: SymbolStore | null;
othersymbols: SymbolStore;
result: ParsedAsmResult;
input: string[];
includeMetadata: boolean;
compiler: BaseCompiler;

readonly jumpDef = /(j\w+|b|bl|blx)\s+([$_a-z][\w$@]*)/i;
readonly callDef = /callq?\s+([$._a-z][\w$.@]*)/i;
readonly callPtrDef1 = /callq?.*ptr\s\[[a-z]*\s\+\s([$._a-z][\w$.@]*)]/i;
readonly callPtrDef2 = /callq?\s+([$*._a-z][\w$.@]*)/i;
readonly callPtrDef3 = /callq?.*\[qword ptr\s([$._a-z][\w$.@]*).*]/i;
readonly callPtrDef4 = /callq?.*qword\sptr\s\[[a-z]*\s\+\s([$._a-z][\w$.@]*)\+?\d?]/i;

// symbols in a mov or lea command starting with an underscore
readonly movUnderscoreDef = /mov.*\s(_[\w$.@]*)/i;
readonly leaUnderscoreDef = /lea.*\s(_[\w$.@]*)/i;
readonly quadUnderscoreDef = /\.quad\s*(_[\w$.@]*)/i;

// E.g., ".entry _Z6squarePii("
// E.g., ".func (.param .b32 func_retval0) bar("
readonly ptxFuncDef = /\.(entry|func)\s+(?:\([^)]*\)\s*)?([$.A-Z_a-z][\w$.]*)\(/;
// E.g., ".const .attribute(.managed) .align 4 .v4 .u32 myvar"
// E.g., ".global .texref mytex"
readonly ptxVarDef =
/^\.(global|const)\s+(?:\.(tex|sampler|surf)ref\s+)?(?:\.attribute\([^)]*\)\s+)?(?:\.align\s+\d+\s+)?(?:\.v\d+\s+)?(?:\.[a-z]\d+\s+)?([$.A-Z_a-z][\w$.]*)/;

constructor(demanglerExe: string, compiler: BaseCompiler) {
super();

this.demanglerExe = demanglerExe;
this.demanglerArguments = [];
this.symbolstore = null;
this.othersymbols = new SymbolStore();
this.result = {};
this.result = {
asm: [],
};
this.input = [];
this.includeMetadata = true;
this.compiler = compiler;

this.jumpDef = /(j\w+|b|bl|blx)\s+([$_a-z][\w$@]*)/i;
this.callDef = /callq?\s+([$._a-z][\w$.@]*)/i;
this.callPtrDef1 = /callq?.*ptr\s\[[a-z]*\s\+\s([$._a-z][\w$.@]*)]/i;
this.callPtrDef2 = /callq?\s+([$*._a-z][\w$.@]*)/i;
this.callPtrDef3 = /callq?.*\[qword ptr\s([$._a-z][\w$.@]*).*]/i;
this.callPtrDef4 = /callq?.*qword\sptr\s\[[a-z]*\s\+\s([$._a-z][\w$.@]*)\+?\d?]/i;

// symbols in a mov or lea command starting with an underscore
this.movUnderscoreDef = /mov.*\s(_[\w$.@]*)/i;
this.leaUnderscoreDef = /lea.*\s(_[\w$.@]*)/i;
this.quadUnderscoreDef = /\.quad\s*(_[\w$.@]*)/i;

// E.g., ".entry _Z6squarePii("
// E.g., ".func (.param .b32 func_retval0) bar("
this.ptxFuncDef = /\.(entry|func)\s+(?:\([^)]*\)\s*)?([$.A-Z_a-z][\w$.]*)\(/;
// E.g., ".const .attribute(.managed) .align 4 .v4 .u32 myvar"
// E.g., ".global .texref mytex"
this.ptxVarDef =
/^\.(global|const)\s+(?:\.(tex|sampler|surf)ref\s+)?(?:\.attribute\([^)]*\)\s+)?(?:\.align\s+\d+\s+)?(?:\.v\d+\s+)?(?:\.[a-z]\d+\s+)?([$.A-Z_a-z][\w$.]*)/;
}

// Iterates over the labels, demangle the label names and updates the start and
// end position of the label.
demangleLabels(labels, tree) {
protected demangleLabels(labels, tree: PrefixTree) {
if (!Array.isArray(labels) || labels.length === 0) return;

for (const [index, label] of labels.entries()) {
Expand All @@ -83,7 +99,7 @@ export class BaseDemangler extends AsmRegex {
}
}

demangleLabelDefinitions(labelDefinitions, translations) {
protected demangleLabelDefinitions(labelDefinitions, translations: [string, string][]) {
if (!labelDefinitions) return;

for (const [oldValue, newValue] of translations) {
Expand All @@ -95,7 +111,7 @@ export class BaseDemangler extends AsmRegex {
}
}

collectLabels() {
protected collectLabels() {
const symbolMatchers = [
this.jumpDef,
this.callPtrDef4,
Expand All @@ -114,7 +130,7 @@ export class BaseDemangler extends AsmRegex {
if (!line) continue;

const labelMatch = line.match(this.labelDef);
if (labelMatch) this.symbolstore.add(labelMatch[labelMatch.length - 1]);
if (labelMatch) unwrap(this.symbolstore).add(labelMatch[labelMatch.length - 1]);

for (const reToMatch of symbolMatchers) {
const matches = line.match(reToMatch);
Expand All @@ -125,36 +141,36 @@ export class BaseDemangler extends AsmRegex {
}
}

this.othersymbols.exclude(this.symbolstore);
this.othersymbols.exclude(unwrap(this.symbolstore));
}

getInput() {
protected getInput() {
this.input = [];
this.input = this.input.concat(this.symbolstore.listSymbols());
this.input = this.input.concat(unwrap(this.symbolstore).listSymbols());
this.input = this.input.concat(this.othersymbols.listSymbols());

return this.input.join('\n');
}

getMetadata() {
protected getMetadata(symbol: string): {ident: RegExp; description: string}[] {
return [];
}

addTranslation(symbol, translation) {
protected addTranslation(symbol: string, translation: string) {
if (this.includeMetadata) {
translation += this.getMetadata(symbol)
.map(meta => ' [' + meta.description + ']')
.map(meta => ` [${meta.description}]`)
.join(',');
}

if (this.symbolstore.contains(symbol)) {
this.symbolstore.add(symbol, translation);
if (unwrap(this.symbolstore).contains(symbol)) {
unwrap(this.symbolstore).add(symbol, translation);
} else {
this.othersymbols.add(symbol, translation);
}
}

processOutput(output) {
protected processOutput(output: UnprocessedExecResult) {
if (output.stdout.length === 0 && output.stderr.length > 0) {
logger.error(`Error executing demangler ${this.demanglerExe}`, output);
return this.result;
Expand All @@ -167,9 +183,10 @@ export class BaseDemangler extends AsmRegex {
}
for (let i = 0; i < lines.length; ++i) this.addTranslation(this.input[i], lines[i]);

const translations = [...this.symbolstore.listTranslations(), ...this.othersymbols.listTranslations()].filter(
elem => elem[0] !== elem[1],
);
const translations = [
...unwrap(this.symbolstore).listTranslations(),
...this.othersymbols.listTranslations(),
].filter(elem => elem[0] !== elem[1]);
if (translations.length > 0) {
const tree = new PrefixTree(translations);

Expand All @@ -183,13 +200,13 @@ export class BaseDemangler extends AsmRegex {
return this.result;
}

execDemangler(options) {
protected execDemangler(options: ExecutionOptions) {
options.maxOutput = -1;

return this.compiler.exec(this.demanglerExe, this.demanglerArguments, options);
}

async process(result, execOptions) {
public async process(result: ParsedAsmResult, execOptions?: ExecutionOptions) {
const options = execOptions || {};
this.result = result;

Expand Down
2 changes: 1 addition & 1 deletion lib/demangler/cpp.js → lib/demangler/cpp.ts
Expand Up @@ -38,7 +38,7 @@ export class CppDemangler extends BaseDemangler {
return 'cpp';
}

getMetadata(symbol) {
protected override getMetadata(symbol: string) {
return LabelMetadata.filter(metadata => metadata.ident.test(symbol));
}
}
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions lib/demangler/llvm.ts
Expand Up @@ -38,7 +38,7 @@ export class LLVMIRDemangler extends BaseDemangler {
return 'llvm-ir';
}

override collectLabels() {
protected override collectLabels() {
for (const line of this.result.asm) {
const text = line.text;
if (!text) continue;
Expand All @@ -51,15 +51,15 @@ export class LLVMIRDemangler extends BaseDemangler {
}
}

collect(result: {asm: ResultLine[]}) {
public collect(result: {asm: ResultLine[]}) {
this.result = result;
if (!this.symbolstore) {
this.symbolstore = new SymbolStore();
this.collectLabels();
}
}

processPassOutput(passOutput: LLVMOptPipelineResults, demanglerOutput) {
protected processPassOutput(passOutput: LLVMOptPipelineResults, demanglerOutput) {
if (demanglerOutput.stdout.length === 0 && demanglerOutput.stderr.length > 0) {
logger.error(`Error executing demangler ${this.demanglerExe}`, demanglerOutput);
return passOutput;
Expand Down Expand Up @@ -95,7 +95,7 @@ export class LLVMIRDemangler extends BaseDemangler {
return passOutput;
}

async demangleLLVMPasses(passOutput: LLVMOptPipelineResults) {
public async demangleLLVMPasses(passOutput: LLVMOptPipelineResults) {
const options = {
input: this.getInput(),
};
Expand Down
2 changes: 1 addition & 1 deletion lib/demangler/nvhpc.ts
Expand Up @@ -37,7 +37,7 @@ export class NVHPCDemangler extends BaseDemangler {
this.llvmDemangler = new LLVMIRDemangler(demanglerExe, compiler);
}

override collectLabels() {
protected override collectLabels() {
this.llvmDemangler.collect(this.result as any);
this.symbolstore = this.llvmDemangler.symbolstore;
}
Expand Down
24 changes: 15 additions & 9 deletions lib/demangler/pascal.js → lib/demangler/pascal.ts
Expand Up @@ -22,6 +22,8 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

import {ParsedAsmResult} from '../../types/asmresult/asmresult.interfaces';
import {ExecutionOptions} from '../../types/compilation/compilation.interfaces';
import {SymbolStore} from '../symbol-store';

import {BaseDemangler} from './base';
Expand All @@ -31,6 +33,10 @@ export class PascalDemangler extends BaseDemangler {
return 'pascal';
}

symbolStore: SymbolStore;
fixedsymbols: Record<string, string>;
ignoredsymbols: string[];

constructor(demanglerExe, compiler) {
super(demanglerExe, compiler);

Expand All @@ -41,7 +47,7 @@ export class PascalDemangler extends BaseDemangler {
this.initBasicSymbols();
}

initBasicSymbols() {
protected initBasicSymbols() {
this.fixedsymbols.OUTPUT_$$_init = 'unit_initialization';
this.fixedsymbols.OUTPUT_$$_finalize = 'unit_finalization';
this.fixedsymbols.OUTPUT_$$_init_implicit = 'unit_initialization_implicit';
Expand Down Expand Up @@ -76,8 +82,8 @@ export class PascalDemangler extends BaseDemangler {
];
}

shouldIgnoreSymbol(text) {
for (let k in this.ignoredsymbols) {
protected shouldIgnoreSymbol(text: string) {
for (const k in this.ignoredsymbols) {
if (text.startsWith(this.ignoredsymbols[k])) {
return true;
}
Expand All @@ -86,7 +92,7 @@ export class PascalDemangler extends BaseDemangler {
return false;
}

composeReadableMethodSignature(unitname, classname, methodname, params) {
protected composeReadableMethodSignature(unitname, classname, methodname, params) {
let signature = '';

if (classname !== '') signature = classname.toLowerCase() + '.';
Expand All @@ -97,7 +103,7 @@ export class PascalDemangler extends BaseDemangler {
return signature;
}

demangle(text) {
protected demangle(text) {
if (!text.endsWith(':')) return false;
if (this.shouldIgnoreSymbol(text)) return false;

Expand Down Expand Up @@ -194,11 +200,11 @@ export class PascalDemangler extends BaseDemangler {
return unmangled;
}

addDemangleToCache(text) {
protected addDemangleToCache(text) {
this.demangle(text);
}

demangleIfNeeded(text) {
protected demangleIfNeeded(text) {
if (text.includes('$')) {
if (this.shouldIgnoreSymbol(text)) {
return text;
Expand All @@ -215,8 +221,8 @@ export class PascalDemangler extends BaseDemangler {
}
}

async process(result, execOptions) {
let options = execOptions || {};
public override async process(result: ParsedAsmResult, execOptions?: ExecutionOptions) {
const options = execOptions || {};
this.result = result;

if (!this.symbolstore) {
Expand Down

0 comments on commit 2a42cc4

Please sign in to comment.