From ac8f4445059830e22224e5034272f6931a943649 Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:28:38 -0500 Subject: [PATCH] Convert, modernize, and refactor cfg generation (#4657) --- lib/base-compiler.ts | 4 +- lib/cfg.js | 352 -------------------- lib/cfg/cfg-parsers/base.ts | 91 +++++ lib/cfg/cfg-parsers/clang.ts | 55 +++ lib/cfg/cfg-parsers/gcc.ts | 45 +++ lib/cfg/cfg.ts | 297 +++++++++++++++++ lib/cfg/instruction-sets/base.ts | 50 +++ lib/handlers/compile.ts | 8 +- lib/keyed-type.ts | 21 +- test/cfg-cases/cfg-clang.if-else.json | 20 +- test/cfg-cases/cfg-clang.loop.json | 40 +-- test/cfg-cases/cfg-clang.single-block.json | 8 +- test/cfg-cases/cfg-clang.split.json | 48 +-- test/cfg-cases/cfg-clang.symbol-filter.json | 20 +- test/cfg-cases/cfg-gcc.binary.json | 40 +-- test/cfg-cases/cfg-gcc.if-else.json | 84 ++--- test/cfg-cases/cfg-gcc.loop.json | 92 ++--- test/cfg-cases/cfg-gcc.single-block.json | 8 +- test/cfg-cases/cfg-gcc.symbol-filter.json | 20 +- test/cfg-tests.js | 10 +- 20 files changed, 675 insertions(+), 638 deletions(-) delete mode 100644 lib/cfg.js create mode 100644 lib/cfg/cfg-parsers/base.ts create mode 100644 lib/cfg/cfg-parsers/clang.ts create mode 100644 lib/cfg/cfg-parsers/gcc.ts create mode 100644 lib/cfg/cfg.ts create mode 100644 lib/cfg/instruction-sets/base.ts diff --git a/lib/base-compiler.ts b/lib/base-compiler.ts index 1fa50a01d42..5b22aa06ac9 100644 --- a/lib/base-compiler.ts +++ b/lib/base-compiler.ts @@ -56,7 +56,7 @@ import {Artifact, ToolResult, ToolTypeKey} from '../types/tool.interfaces'; import {BuildEnvSetupBase, getBuildEnvTypeByKey} from './buildenvsetup'; import {BuildEnvDownloadInfo} from './buildenvsetup/buildenv.interfaces'; -import * as cfg from './cfg'; +import * as cfg from './cfg/cfg'; import {CompilationEnvironment} from './compilation-env'; import {CompilerArguments} from './compiler-arguments'; import {ClangParser, GCCParser} from './compilers/argument-parsers'; @@ -2379,7 +2379,7 @@ export class BaseCompiler implements ICompiler { // for now do not generate a cfg for llvm ir result.cfg = {}; } else { - result.cfg = cfg.generateStructure(this.compiler.compilerType, this.compiler.version, result.asm); + result.cfg = cfg.generateStructure(this.compiler, result.asm); } } } diff --git a/lib/cfg.js b/lib/cfg.js deleted file mode 100644 index 7b14cddcc5e..00000000000 --- a/lib/cfg.js +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (c) 2017, Najjar Chedy -// 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 _ from 'underscore'; - -import {logger} from './logger'; -import * as utils from './utils'; - -const InstructionType_jmp = 0; -const InstructionType_conditionalJmpInst = 1; -const InstructionType_notRetInst = 2; -const InstructionType_retInst = 3; - -// deal with typeinfo name for, typeinfo for, vtable for -const isFunctionName = x => x.text.trim().indexOf('.') !== 0; - -function getAsmDirective(txt) { - const pattern = /^\s*(\.[^ L]\S*)/; - const match = txt.match(pattern); - if (match !== null) { - return match[1]; - } - return null; -} - -function filterTextSection(data) { - let useCurrentSection = true; - const result = []; - for (const i in data) { - const x = data[i]; - const directive = getAsmDirective(x.text); - if (directive != null) { - if (directive === '.text' || directive === '.data') { - useCurrentSection = directive === '.text'; - } else if (directive === '.section') { - // Only patttern match for now. - // Extracting section name would require adjusting demangling code - // as demangled name could contain various symbols including ','. - useCurrentSection = /\.section\s*"?\.text/.test(x.text); - } else if (useCurrentSection) { - result.push(x); - } - } else if (useCurrentSection) { - result.push(x); - } - } - return result; -} - -const gcc = { - filterData: asmArr => { - const jmpLabelRegex = /\.L\d+:/; - const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || isFunctionName(x)); - return _.chain(filterTextSection(asmArr)).map(_.clone).filter(isCode).value(); - }, - isFunctionEnd: x => x[0] !== ' ' && x[0] !== '.' && x.includes(':'), - - isBasicBlockEnd: (inst, prevInst) => inst[0] === '.' || prevInst.includes(' ret'), - - isJmpInstruction: x => x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/), - - getInstructionType: inst => { - if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType_jmp; - else if (gcc.isJmpInstruction(inst)) return InstructionType_conditionalJmpInst; - else if (inst.includes(' ret')) { - return InstructionType_retInst; - } else { - return InstructionType_notRetInst; - } - }, - - extractNodeName: inst => inst.match(/\.L\d+/) + ':', -}; - -const clang = { - filterData: asmArr => { - const jmpLabelRegex = /\.LBB\d+_\d+:/; - const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || isFunctionName(x)); - - const removeComments = x => { - const pos_x86 = x.text.indexOf('# '); - const pos_arm = x.text.indexOf('// '); - if (pos_x86 !== -1) x.text = utils.trimRight(x.text.substring(0, pos_x86)); - if (pos_arm !== -1) x.text = utils.trimRight(x.text.substring(0, pos_arm)); - return x; - }; - - return _.chain(filterTextSection(asmArr)).map(_.clone).filter(isCode).map(removeComments).value(); - }, - isFunctionEnd: x => x[0] !== ' ' && x[0] !== '.' && x.includes(':'), - - isBasicBlockEnd: (inst, prevInst) => inst[0] === '.' || prevInst.includes(' ret'), - - isJmpInstruction: x => x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/), - - getInstructionType: function (inst) { - if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType_jmp; - else if (clang.isJmpInstruction(inst)) return InstructionType_conditionalJmpInst; - else if (inst.includes(' ret')) { - return InstructionType_retInst; - } else { - return InstructionType_notRetInst; - } - }, - - extractNodeName: inst => inst.match(/\.LBB\d+_\d+/) + ':', -}; - -function splitToFunctions(asmArr, isEnd) { - if (asmArr.length === 0) return []; - const result = []; - let first = 1; - const last = asmArr.length; - const fnRange = {start: 0, end: null}; - while (first !== last) { - if (isEnd(asmArr[first].text)) { - fnRange.end = first; - result.push(_.clone(fnRange)); - fnRange.start = first; - } - ++first; - } - - fnRange.end = last; - result.push(_.clone(fnRange)); - return result; -} - -function splitToBasicBlocks(asmArr, range, isEnd, isJmp) { - let first = range.start; - const last = range.end; - if (first === last) return []; - const functionName = asmArr[first].text; - ++first; - - let rangeBb = {nameId: functionName, start: first, end: null, actionPos: []}; - const result = []; - - const newRangeWith = function (oldRange, nameId, start) { - return {nameId: nameId, start: start, actionPos: [], end: oldRange.end}; - }; - - while (first < last) { - const inst = asmArr[first].text; - if (isEnd(inst, asmArr[first - 1] ? asmArr[first - 1].text : '')) { - rangeBb.end = first; - result.push(_.clone(rangeBb)); - //inst is expected to be .L*: where * in 1,2,... - rangeBb = newRangeWith(rangeBb, inst, first + 1); - } else if (isJmp(inst)) { - rangeBb.actionPos.push(first); - } - ++first; - } - - rangeBb.end = last; - result.push(_.clone(rangeBb)); - return result; -} - -function splitToCanonicalBasicBlock(basicBlock) { - const actionPos = basicBlock.actionPos; - let actPosSz = actionPos.length; - if (actionPos[actPosSz - 1] + 1 === basicBlock.end) { - --actPosSz; - } - - if (actPosSz === 0) - return [ - { - nameId: basicBlock.nameId, - start: basicBlock.start, - end: basicBlock.end, - }, - ]; - else if (actPosSz === 1) - return [ - {nameId: basicBlock.nameId, start: basicBlock.start, end: actionPos[0] + 1}, - {nameId: basicBlock.nameId + '@' + (actionPos[0] + 1), start: actionPos[0] + 1, end: basicBlock.end}, - ]; - else { - let first = 0; - const last = actPosSz; - const blockName = basicBlock.nameId; - let tmp = {nameId: blockName, start: basicBlock.start, end: actionPos[first] + 1}; - const result = []; - result.push(_.clone(tmp)); - while (first !== last - 1) { - tmp.nameId = blockName + '@' + (actionPos[first] + 1); - tmp.start = actionPos[first] + 1; - ++first; - tmp.end = actionPos[first] + 1; - result.push(_.clone(tmp)); - } - - tmp = {nameId: blockName + '@' + (actionPos[first] + 1), start: actionPos[first] + 1, end: basicBlock.end}; - result.push(_.clone(tmp)); - - return result; - } -} - -function concatInstructions(asmArr, first, last) { - return _.chain(asmArr.slice(first, last)) - .map(x => x.text) - .value() - .join('\n'); -} - -function makeNodes(asms, arrOfCanonicalBasicBlock) { - return _.map(arrOfCanonicalBasicBlock, e => { - return { - id: e.nameId, - label: `${e.nameId}${e.nameId.includes(':') ? '' : ':'}\n${concatInstructions(asms, e.start, e.end)}`, - color: '#99ccff', - shape: 'box', - }; - }); -} - -function makeEdges(asmArr, arrOfCanonicalBasicBlock, rules) { - const edge = {}; - const edges = []; - - const setEdge = function (edge, sourceNode, targetNode, color) { - edge.from = sourceNode; - edge.to = targetNode; - edge.arrows = 'to'; - edge.color = color; - }; - const isBasicBlockEnd = rules.isBasicBlockEnd; - - const hasName = function (asmArr, cbb) { - const asm = asmArr[cbb.end]; - return asm ? isBasicBlockEnd(asm.text, '') : false; - }; - - const generateName = function (name, suffix) { - const pos = name.indexOf('@'); - if (pos === -1) return name + '@' + suffix; - - return name.substring(0, pos + 1) + suffix; - }; - /* note: x.end-1 possible values: - jmp .L*, {jne,je,jg,...} .L*, ret/rep ret, call and any other instruction that doesn't change control flow - */ - - _.each(arrOfCanonicalBasicBlock, function (x) { - let targetNode; - const lastInst = asmArr[x.end - 1].text; - switch (rules.getInstructionType(lastInst)) { - case InstructionType_jmp: { - //we have to deal only with jmp destination, jmp instruction are always taken. - //edge from jump inst - targetNode = rules.extractNodeName(lastInst); - setEdge(edge, x.nameId, targetNode, 'blue'); - edges.push(_.clone(edge)); - break; - } - case InstructionType_conditionalJmpInst: { - //deal with : branch taken, branch not taken - targetNode = rules.extractNodeName(lastInst); - setEdge(edge, x.nameId, targetNode, 'green'); - edges.push(_.clone(edge)); - targetNode = hasName(asmArr, x) ? asmArr[x.end].text : generateName(x.nameId, x.end); - setEdge(edge, x.nameId, targetNode, 'red'); - edges.push(_.clone(edge)); - logger.debug(edge); - break; - } - case InstructionType_notRetInst: { - //precondition: lastInst is not last instruction in asmArr (but it is in canonical basic block) - //note : asmArr[x.end] expected to be .L*:(name of a basic block) - // this .L*: has to be exactly after the last instruction in the current canonical basic block - if (asmArr[x.end]) { - targetNode = asmArr[x.end].text; - setEdge(edge, x.nameId, targetNode, 'grey'); - edges.push(_.clone(edge)); - } - break; - } - case InstructionType_retInst: { - break; - } - } - }); - logger.debug(edges); - return edges; -} - -function isLLVMBased(compilerType, version) { - return ( - version.includes('clang') || - version.includes('LLVM') || - version.includes('rustc') || - compilerType === 'swift' || - compilerType === 'zig' || - compilerType === 'ispc' - ); -} - -export function generateStructure(compilerType, version, asmArr) { - const rules = isLLVMBased(compilerType, version) ? clang : gcc; - const code = rules.filterData(asmArr); - const funcs = splitToFunctions(code, rules.isFunctionEnd); - if (funcs.length === 0) { - return funcs; - } - const result = {}; - _.each( - funcs, - _.bind(function (rng) { - const basicBlocks = splitToBasicBlocks(code, rng, rules.isBasicBlockEnd, rules.isJmpInstruction); - let arrOfCanonicalBasicBlock = []; - _.each( - basicBlocks, - _.bind(function (elm) { - const tmp = splitToCanonicalBasicBlock(elm); - arrOfCanonicalBasicBlock = arrOfCanonicalBasicBlock.concat(tmp); - }, this), - ); - - result[code[rng.start].text] = { - nodes: makeNodes(code, arrOfCanonicalBasicBlock), - edges: makeEdges(code, arrOfCanonicalBasicBlock, rules), - }; - }, this), - ); - - return result; -} diff --git a/lib/cfg/cfg-parsers/base.ts b/lib/cfg/cfg-parsers/base.ts new file mode 100644 index 00000000000..54b2574ff3f --- /dev/null +++ b/lib/cfg/cfg-parsers/base.ts @@ -0,0 +1,91 @@ +// Copyright (c) 2023, 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 _ from 'underscore'; + +import {ResultLine} from '../../../types/resultline/resultline.interfaces'; +import {BaseInstructionSetInfo} from '../instruction-sets/base'; + +export class BaseCFGParser { + static get key() { + return 'base'; + } + + constructor(public readonly instructionSetInfo: BaseInstructionSetInfo) {} + + isFunctionName(line: ResultLine) { + return line.text.trim().indexOf('.') !== 0; + } + + getAsmDirective(txt: string) { + const pattern = /^\s*(\.[^ L]\S*)/; + const match = txt.match(pattern); + if (match !== null) { + return match[1]; + } + return null; + } + + filterTextSection(data: ResultLine[]) { + let useCurrentSection = true; + const result: ResultLine[] = []; + for (const i in data) { + const x = data[i]; + const directive = this.getAsmDirective(x.text); + if (directive != null) { + if (directive === '.text' || directive === '.data') { + useCurrentSection = directive === '.text'; + } else if (directive === '.section') { + // Only patttern match for now. + // Extracting section name would require adjusting demangling code + // as demangled name could contain various symbols including ','. + useCurrentSection = /\.section\s*"?\.text/.test(x.text); + } else if (useCurrentSection) { + result.push(x); + } + } else if (useCurrentSection) { + result.push(x); + } + } + return result; + } + + filterData(assembly: ResultLine[]) { + const jmpLabelRegex = /\.L\d+:/; + const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x)); + return this.filterTextSection(assembly).map(_.clone).filter(isCode); + } + + isFunctionEnd(x: string) { + return x[0] !== ' ' && x[0] !== '.' && x.includes(':'); + } + + isBasicBlockEnd(inst: string, prevInst: string) { + return inst[0] === '.' || prevInst.includes(' ret'); + } + + extractNodeName(inst: string) { + return inst.match(/\.L\d+/) + ':'; + } +} diff --git a/lib/cfg/cfg-parsers/clang.ts b/lib/cfg/cfg-parsers/clang.ts new file mode 100644 index 00000000000..fcb18246cd3 --- /dev/null +++ b/lib/cfg/cfg-parsers/clang.ts @@ -0,0 +1,55 @@ +// Copyright (c) 2023, 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 _ from 'underscore'; + +import {ResultLine} from '../../../types/resultline/resultline.interfaces'; +import * as utils from '../../utils'; + +import {BaseCFGParser} from './base'; + +export class ClangCFGParser extends BaseCFGParser { + static override get key() { + return 'clang'; + } + + override filterData(assembly: ResultLine[]) { + const jmpLabelRegex = /\.LBB\d+_\d+:/; + const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x)); + + const removeComments = (x: ResultLine) => { + const pos_x86 = x.text.indexOf('# '); + const pos_arm = x.text.indexOf('// '); + if (pos_x86 !== -1) x.text = utils.trimRight(x.text.substring(0, pos_x86)); + if (pos_arm !== -1) x.text = utils.trimRight(x.text.substring(0, pos_arm)); + return x; + }; + + return this.filterTextSection(assembly).map(_.clone).filter(isCode).map(removeComments); + } + + override extractNodeName(inst: string) { + return inst.match(/\.LBB\d+_\d+/) + ':'; + } +} diff --git a/lib/cfg/cfg-parsers/gcc.ts b/lib/cfg/cfg-parsers/gcc.ts new file mode 100644 index 00000000000..f3e8e538141 --- /dev/null +++ b/lib/cfg/cfg-parsers/gcc.ts @@ -0,0 +1,45 @@ +// Copyright (c) 2023, 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 _ from 'underscore'; + +import {ResultLine} from '../../../types/resultline/resultline.interfaces'; + +import {BaseCFGParser} from './base'; + +export class GccCFGParser extends BaseCFGParser { + static override get key() { + return 'gcc'; + } + + override filterData(assembly: ResultLine[]) { + const jmpLabelRegex = /\.L\d+:/; + const isCode = x => x && x.text && (x.source !== null || jmpLabelRegex.test(x.text) || this.isFunctionName(x)); + return this.filterTextSection(assembly).map(_.clone).filter(isCode); + } + + override extractNodeName(inst: string) { + return inst.match(/\.L\d+/) + ':'; + } +} diff --git a/lib/cfg/cfg.ts b/lib/cfg/cfg.ts new file mode 100644 index 00000000000..2ac84a87b14 --- /dev/null +++ b/lib/cfg/cfg.ts @@ -0,0 +1,297 @@ +// Copyright (c) 2023, 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 _ from 'underscore'; + +import {CompilerInfo} from '../../types/compiler.interfaces'; +import {ResultLine} from '../../types/resultline/resultline.interfaces'; +import {BaseCompiler} from '../base-compiler'; +import {makeDefaultedKeyedTypeGetter} from '../keyed-type'; +import {logger} from '../logger'; + +import {BaseCFGParser} from './cfg-parsers/base'; +import {ClangCFGParser} from './cfg-parsers/clang'; +import {GccCFGParser} from './cfg-parsers/gcc'; +import {BaseInstructionSetInfo, InstructionType} from './instruction-sets/base'; + +// TODO(jeremy-rifkin): +// I've done some work to split out the compiler / instruction set logic +// We'll want to do some work to fill in information for instruction sets and other compilers +// A good comparison https://godbolt.org/z/8EvqoWhYo +// MSVC especially is a little weird, LLVM is also a much different structure than normal asm + +const parsers = makeDefaultedKeyedTypeGetter( + 'cfg parser provider', + { + ClangCFGParser, + GccCFGParser, + }, + BaseCFGParser, +); +const instructionSets = makeDefaultedKeyedTypeGetter('instruction set info provider', {}, BaseInstructionSetInfo); + +type Range = { + start: number; + end: number; +}; + +function splitToFunctions(asmArr: ResultLine[], parser: BaseCFGParser) { + if (asmArr.length === 0) return []; + const result: Range[] = []; + let first = 1; + const last = asmArr.length; + const fnRange: Range = {start: 0, end: 0}; + while (first !== last) { + if (parser.isFunctionEnd(asmArr[first].text)) { + fnRange.end = first; + result.push(_.clone(fnRange)); + fnRange.start = first; + } + ++first; + } + + fnRange.end = last; + result.push(_.clone(fnRange)); + return result; +} + +type BBRange = { + nameId: string; + start: number; + end: number; + actionPos: number[]; +}; + +function splitToBasicBlocks(asmArr: ResultLine[], range: Range, parser: BaseCFGParser) { + let first = range.start; + const last = range.end; + if (first === last) return []; + const functionName = asmArr[first].text; + ++first; + + let rangeBb: BBRange = {nameId: functionName, start: first, end: 0, actionPos: []}; + const result: BBRange[] = []; + + const newRangeWith = function (oldRange, nameId, start) { + return {nameId: nameId, start: start, actionPos: [], end: oldRange.end}; + }; + + while (first < last) { + const inst = asmArr[first].text; + if (parser.isBasicBlockEnd(inst, asmArr[first - 1] ? asmArr[first - 1].text : '')) { + rangeBb.end = first; + result.push(_.clone(rangeBb)); + //inst is expected to be .L*: where * in 1,2,... + rangeBb = newRangeWith(rangeBb, inst, first + 1); + } else if (parser.instructionSetInfo.isJmpInstruction(inst)) { + rangeBb.actionPos.push(first); + } + ++first; + } + + rangeBb.end = last; + result.push(_.clone(rangeBb)); + return result; +} + +type CanonicalBB = { + nameId: string; + start: number; + end: number; +}; + +function splitToCanonicalBasicBlock(basicBlock: BBRange): CanonicalBB[] { + const actionPos = basicBlock.actionPos; + let actPosSz = actionPos.length; + if (actionPos[actPosSz - 1] + 1 === basicBlock.end) { + --actPosSz; + } + + if (actPosSz === 0) + return [ + { + nameId: basicBlock.nameId, + start: basicBlock.start, + end: basicBlock.end, + }, + ]; + else if (actPosSz === 1) + return [ + {nameId: basicBlock.nameId, start: basicBlock.start, end: actionPos[0] + 1}, + {nameId: basicBlock.nameId + '@' + (actionPos[0] + 1), start: actionPos[0] + 1, end: basicBlock.end}, + ]; + else { + let first = 0; + const last = actPosSz; + const blockName = basicBlock.nameId; + let tmp: CanonicalBB = {nameId: blockName, start: basicBlock.start, end: actionPos[first] + 1}; + const result: CanonicalBB[] = []; + result.push(_.clone(tmp)); + while (first !== last - 1) { + tmp.nameId = blockName + '@' + (actionPos[first] + 1); + tmp.start = actionPos[first] + 1; + ++first; + tmp.end = actionPos[first] + 1; + result.push(_.clone(tmp)); + } + + tmp = {nameId: blockName + '@' + (actionPos[first] + 1), start: actionPos[first] + 1, end: basicBlock.end}; + result.push(_.clone(tmp)); + + return result; + } +} + +function concatInstructions(asmArr: ResultLine[], first: number, last: number) { + return asmArr + .slice(first, last) + .map(x => x.text) + .join('\n'); +} + +type Node = { + id: string; + label: string; +}; + +function makeNodes(asms: ResultLine[], arrOfCanonicalBasicBlock: CanonicalBB[]): Node[] { + return arrOfCanonicalBasicBlock.map(e => ({ + id: e.nameId, + label: `${e.nameId}${e.nameId.includes(':') ? '' : ':'}\n${concatInstructions(asms, e.start, e.end)}`, + })); +} + +type Edge = { + from: string; + to: string; + arrows: string; + color: string; +}; + +function makeEdges(asmArr: ResultLine[], arrOfCanonicalBasicBlock: CanonicalBB[], parser: BaseCFGParser) { + const edges: Edge[] = []; + + const setEdge = (sourceNode: string, targetNode: string, color: string) => ({ + from: sourceNode, + to: targetNode, + arrows: 'to', + color: color, + }); + const isBasicBlockEnd = parser.isBasicBlockEnd; + + const hasName = (asmArr: ResultLine[], cbb: CanonicalBB) => { + const asm = asmArr[cbb.end]; + return asm ? isBasicBlockEnd(asm.text, '') : false; + }; + + const generateName = function (name: string, suffix: number) { + const pos = name.indexOf('@'); + if (pos === -1) return `${name}@${suffix}`; + + return name.substring(0, pos + 1) + suffix; + }; + /* note: x.end-1 possible values: + jmp .L*, {jne,je,jg,...} .L*, ret/rep ret, call and any other instruction that doesn't change control flow + */ + + for (const x of arrOfCanonicalBasicBlock) { + let targetNode; + const lastInst = asmArr[x.end - 1].text; + switch (parser.instructionSetInfo.getInstructionType(lastInst)) { + case InstructionType.jmp: { + //we have to deal only with jmp destination, jmp instruction are always taken. + //edge from jump inst + targetNode = parser.extractNodeName(lastInst); + edges.push(setEdge(x.nameId, targetNode, 'blue')); + break; + } + case InstructionType.conditionalJmpInst: { + //deal with : branch taken, branch not taken + targetNode = parser.extractNodeName(lastInst); + edges.push(setEdge(x.nameId, targetNode, 'green')); + targetNode = hasName(asmArr, x) ? asmArr[x.end].text : generateName(x.nameId, x.end); + edges.push(setEdge(x.nameId, targetNode, 'red')); + break; + } + case InstructionType.notRetInst: { + //precondition: lastInst is not last instruction in asmArr (but it is in canonical basic block) + //note : asmArr[x.end] expected to be .L*:(name of a basic block) + // this .L*: has to be exactly after the last instruction in the current canonical basic block + if (asmArr[x.end]) { + targetNode = asmArr[x.end].text; + edges.push(setEdge(x.nameId, targetNode, 'grey')); + } + break; + } + case InstructionType.retInst: { + break; + } + } + } + logger.debug(edges); + return edges; +} + +function isLLVMBased({compilerType, version}: CompilerInfo) { + return ( + version.includes('clang') || + version.includes('LLVM') || + version.includes('rustc') || + compilerType === 'swift' || + compilerType === 'zig' || + compilerType === 'ispc' + ); +} + +type CFG = { + nodes: Node[]; + edges: Edge[]; +}; + +export function generateStructure(compilerInfo: CompilerInfo, asmArr: ResultLine[]) { + const compilerGroup = isLLVMBased(compilerInfo) ? 'clang' : compilerInfo.group; + const instructionSet = new (instructionSets(compilerInfo.instructionSet))(); + const parser = new (parsers(compilerGroup))(instructionSet); + const code = parser.filterData(asmArr); + const functions = splitToFunctions(code, parser); + if (functions.length === 0) { + return functions; + } + const result: Record = {}; + for (const fn of functions) { + const basicBlocks = splitToBasicBlocks(code, fn, parser); + let arrOfCanonicalBasicBlock: CanonicalBB[] = []; + for (const bb of basicBlocks) { + const tmp = splitToCanonicalBasicBlock(bb); + arrOfCanonicalBasicBlock = arrOfCanonicalBasicBlock.concat(tmp); + } + + result[code[fn.start].text] = { + nodes: makeNodes(code, arrOfCanonicalBasicBlock), + edges: makeEdges(code, arrOfCanonicalBasicBlock, parser), + }; + } + + return result; +} diff --git a/lib/cfg/instruction-sets/base.ts b/lib/cfg/instruction-sets/base.ts new file mode 100644 index 00000000000..57fe1dc31a4 --- /dev/null +++ b/lib/cfg/instruction-sets/base.ts @@ -0,0 +1,50 @@ +// Copyright (c) 2023, 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. + +export enum InstructionType { + jmp, + conditionalJmpInst, + notRetInst, + retInst, +} + +export class BaseInstructionSetInfo { + static get key() { + return 'base'; + } + + isJmpInstruction(x: string) { + return x.trim()[0] === 'j' || x.match(/\bb\.*(eq|ne|cs|hs|cc|lo|hi|ls|ge|lt|gt|le|rge|rlt)?\b/); + } + + getInstructionType(inst: string) { + if (inst.includes('jmp') || inst.includes(' b ')) return InstructionType.jmp; + else if (this.isJmpInstruction(inst)) return InstructionType.conditionalJmpInst; + else if (inst.includes(' ret')) { + return InstructionType.retInst; + } else { + return InstructionType.notRetInst; + } + } +} diff --git a/lib/handlers/compile.ts b/lib/handlers/compile.ts index 8ae81243d81..0973244c7f2 100644 --- a/lib/handlers/compile.ts +++ b/lib/handlers/compile.ts @@ -580,13 +580,13 @@ export class CompileHandler { }, error => { if (typeof error === 'string') { - logger.error('Error during compilation: ', {error}); + logger.error('Error during compilation 1: ', {error}); } else { if (error.stack) { - logger.error('Error during compilation: ', error); + logger.error('Error during compilation 2: ', error); Sentry.captureException(error); } else if (error.code) { - logger.error('Error during compilation: ', error.code); + logger.error('Error during compilation 3: ', error.code); if (typeof error.stderr === 'string') { error.stdout = utils.parseOutput(error.stdout); error.stderr = utils.parseOutput(error.stderr); @@ -594,7 +594,7 @@ export class CompileHandler { res.end(JSON.stringify(error)); return; } else { - logger.error('Error during compilation: ', error); + logger.error('Error during compilation 4: ', error); } error = `Internal Compiler Explorer error: ${error.stack || error}`; diff --git a/lib/keyed-type.ts b/lib/keyed-type.ts index 112d6dfaf73..f9bd82ca891 100644 --- a/lib/keyed-type.ts +++ b/lib/keyed-type.ts @@ -63,11 +63,26 @@ export function makeKeyedTypeGetter( const keyMap = makeKeyMap(typeName, objects); return function getFromKey(key) { - const obj = keyMap[key]; - if (obj === undefined) { + if (key in keyMap) { + return keyMap[key]; + } else { throw new Error(`No ${typeName} named '${key}' found`); } + }; +} - return obj; +export function makeDefaultedKeyedTypeGetter( + typeName: string, + objects: Record, + defaultObject: T, +): (key: string) => T { + const keyMap = makeKeyMap(typeName, objects); + + return function getFromKey(key) { + if (key in keyMap) { + return keyMap[key]; + } else { + return defaultObject; + } }; } diff --git a/test/cfg-cases/cfg-clang.if-else.json b/test/cfg-cases/cfg-clang.if-else.json index 0fa15d6dff1..2e00921e15c 100644 --- a/test/cfg-cases/cfg-clang.if-else.json +++ b/test/cfg-cases/cfg-clang.if-else.json @@ -204,9 +204,7 @@ "nodes": [ { "id": "__cxx_global_var_init:", - "label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit" } ], "edges": [ @@ -222,21 +220,15 @@ "nodes": [ { "id": "foo(int, double, float):", - "label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_2", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_2" }, { "id": "foo(int, double, float):@14", - "label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %ecx\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %ecx, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n cvttss2si %xmm1, %eax\n cmoval %ecx, %eax", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %ecx\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %ecx, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n cvttss2si %xmm1, %eax\n cmoval %ecx, %eax" }, { "id": ".LBB1_2:", - "label": ".LBB1_2:\n retq", - "color": "#99ccff", - "shape": "box" + "label": ".LBB1_2:\n retq" } ], "edges": [ @@ -264,9 +256,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_example.cpp:", - "label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init" } ], "edges": [ diff --git a/test/cfg-cases/cfg-clang.loop.json b/test/cfg-cases/cfg-clang.loop.json index 56da73fc0a6..8352be55bb7 100644 --- a/test/cfg-cases/cfg-clang.loop.json +++ b/test/cfg-cases/cfg-clang.loop.json @@ -338,9 +338,7 @@ "nodes": [ { "id": "__cxx_global_var_init:", - "label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "__cxx_global_var_init:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit" } ], "edges": [ @@ -356,51 +354,35 @@ "nodes": [ { "id": "foo(int, double, float):", - "label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_6", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):\n movl $583, %eax\n movsd .LCPI1_0(%rip), %xmm2\n ucomisd %xmm0, %xmm2\n jbe .LBB1_6" }, { "id": "foo(int, double, float):@14", - "label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %eax\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %eax, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n jbe .LBB1_5", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):@14\n leal (%rdi,%rdi,4), %eax\n xorps %xmm2, %xmm2\n cvtss2sd %xmm1, %xmm2\n cvtsi2sdl %eax, %xmm3\n mulsd %xmm0, %xmm3\n ucomisd %xmm3, %xmm2\n jbe .LBB1_5" }, { "id": "foo(int, double, float):@21", - "label": "foo(int, double, float):@21\n movl %eax, %ecx\n imull %edi, %ecx\n testl %ecx, %ecx\n jle .LBB1_6", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):@21\n movl %eax, %ecx\n imull %edi, %ecx\n testl %ecx, %ecx\n jle .LBB1_6" }, { "id": "foo(int, double, float):@25", - "label": "foo(int, double, float):@25\n xorl %ecx, %ecx", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, double, float):@25\n xorl %ecx, %ecx" }, { "id": ".LBB1_4:", - "label": ".LBB1_4:\n addl %eax, %eax\n xorps %xmm0, %xmm0\n cvtsi2ssl %eax, %xmm0\n movaps %xmm0, %xmm2\n subss %xmm1, %xmm2\n mulss %xmm0, %xmm2\n cvttss2si %xmm2, %eax\n incl %ecx\n movl %eax, %edx\n imull %edi, %edx\n cmpl %edx, %ecx\n jl .LBB1_4", - "color": "#99ccff", - "shape": "box" + "label": ".LBB1_4:\n addl %eax, %eax\n xorps %xmm0, %xmm0\n cvtsi2ssl %eax, %xmm0\n movaps %xmm0, %xmm2\n subss %xmm1, %xmm2\n mulss %xmm0, %xmm2\n cvttss2si %xmm2, %eax\n incl %ecx\n movl %eax, %edx\n imull %edi, %edx\n cmpl %edx, %ecx\n jl .LBB1_4" }, { "id": ".LBB1_4:@39", - "label": ".LBB1_4:@39\n jmp .LBB1_6", - "color": "#99ccff", - "shape": "box" + "label": ".LBB1_4:@39\n jmp .LBB1_6" }, { "id": ".LBB1_5:", - "label": ".LBB1_5:\n cvttss2si %xmm1, %eax", - "color": "#99ccff", - "shape": "box" + "label": ".LBB1_5:\n cvttss2si %xmm1, %eax" }, { "id": ".LBB1_6:", - "label": ".LBB1_6:\n retq", - "color": "#99ccff", - "shape": "box" + "label": ".LBB1_6:\n retq" } ], "edges": [ @@ -476,9 +458,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_example.cpp:", - "label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_example.cpp:\n jmp __cxx_global_var_init" } ], "edges": [ diff --git a/test/cfg-cases/cfg-clang.single-block.json b/test/cfg-cases/cfg-clang.single-block.json index 8c2337bb766..76b2ca76828 100644 --- a/test/cfg-cases/cfg-clang.single-block.json +++ b/test/cfg-cases/cfg-clang.single-block.json @@ -100,9 +100,7 @@ "nodes": [ { "id": "main:", - "label": "main:\n xorl %eax, %eax\n retq", - "color": "#99ccff", - "shape": "box" + "label": "main:\n xorl %eax, %eax\n retq" } ], "edges": [] @@ -111,9 +109,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_example.cpp:", - "label": "_GLOBAL__sub_I_example.cpp:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_example.cpp:\n pushq %rax\n movl std::__ioinit, %edi\n callq std::ios_base::Init::Init()\n movl std::ios_base::Init::~Init(), %edi\n movl std::__ioinit, %esi\n movl $__dso_handle, %edx\n popq %rax\n jmp __cxa_atexit" } ], "edges": [ diff --git a/test/cfg-cases/cfg-clang.split.json b/test/cfg-cases/cfg-clang.split.json index 0298e01dc67..8286cf9c32f 100644 --- a/test/cfg-cases/cfg-clang.split.json +++ b/test/cfg-cases/cfg-clang.split.json @@ -82,45 +82,31 @@ "nodes": [ { "id": "remove_space(char const*, char*, unsigned long):", - "label": "remove_space(char const*, char*, unsigned long):\n testq %rdx, %rdx\n je .LBB0_6", - "color": "#99ccff", - "shape": "box" + "label": "remove_space(char const*, char*, unsigned long):\n testq %rdx, %rdx\n je .LBB0_6" }, { "id": "remove_space(char const*, char*, unsigned long):@3", - "label": "remove_space(char const*, char*, unsigned long):@3\n xorl %eax, %eax", - "color": "#99ccff", - "shape": "box" + "label": "remove_space(char const*, char*, unsigned long):@3\n xorl %eax, %eax" }, - { - "color": "#99ccff", - "id": ".LBB0_2:", - "label": ".LBB0_2:\n movzbl (%rdi,%rax), %ecx\n cmpb $97, %cl\n je .LBB0_5", - "shape": "box" + { "id": ".LBB0_2:", + "label": ".LBB0_2:\n movzbl (%rdi,%rax), %ecx\n cmpb $97, %cl\n je .LBB0_5" + }, - { - "color": "#99ccff", - "id": ".LBB0_2:@8", - "label": ".LBB0_2:@8\n cmpb $122, %cl\n je .LBB0_5", - "shape": "box" + { "id": ".LBB0_2:@8", + "label": ".LBB0_2:@8\n cmpb $122, %cl\n je .LBB0_5" + }, - { - "color": "#99ccff", - "id": ".LBB0_2:@10", - "label": ".LBB0_2:@10\n movb %cl, (%rsi)\n addq $1, %rsi", - "shape": "box" + { "id": ".LBB0_2:@10", + "label": ".LBB0_2:@10\n movb %cl, (%rsi)\n addq $1, %rsi" + }, - { - "color": "#99ccff", - "id": ".LBB0_5:", - "label": ".LBB0_5:\n addq $1, %rax\n cmpq %rax, %rdx\n jne .LBB0_2", - "shape": "box" + { "id": ".LBB0_5:", + "label": ".LBB0_5:\n addq $1, %rax\n cmpq %rax, %rdx\n jne .LBB0_2" + }, - { - "color": "#99ccff", - "id": ".LBB0_6:", - "label": ".LBB0_6:\n movq %rsi, %rax\n retq", - "shape": "box" + { "id": ".LBB0_6:", + "label": ".LBB0_6:\n movq %rsi, %rax\n retq" + } ], "edges": [ diff --git a/test/cfg-cases/cfg-clang.symbol-filter.json b/test/cfg-cases/cfg-clang.symbol-filter.json index ab7f3acd7c9..50f40560072 100644 --- a/test/cfg-cases/cfg-clang.symbol-filter.json +++ b/test/cfg-cases/cfg-clang.symbol-filter.json @@ -86,9 +86,7 @@ "nodes": [ { "id": "foo(int, int):", - "label": "foo(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, int):\n retq" } ], "edges": [] @@ -97,9 +95,7 @@ "nodes": [ { "id": "foo3(int, int):", - "label": "foo3(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo3(int, int):\n retq" } ], "edges": [] @@ -108,9 +104,7 @@ "nodes": [ { "id": "foo5(int, int):", - "label": "foo5(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo5(int, int):\n retq" } ], "edges": [] @@ -119,9 +113,7 @@ "nodes": [ { "id": "foo6::::foo:", - "label": "foo6::::foo:\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo6::::foo:\n retq" } ], "edges": [] @@ -130,9 +122,7 @@ "nodes": [ { "id": "type metadata accessor for [Swift.Int]:", - "label": "type metadata accessor for [Swift.Int]:\n retq", - "color": "#99ccff", - "shape": "box" + "label": "type metadata accessor for [Swift.Int]:\n retq" } ], "edges": [] diff --git a/test/cfg-cases/cfg-gcc.binary.json b/test/cfg-cases/cfg-gcc.binary.json index 3f6f176f1c6..ba6ca5a222a 100644 --- a/test/cfg-cases/cfg-gcc.binary.json +++ b/test/cfg-cases/cfg-gcc.binary.json @@ -144,35 +144,25 @@ } ], "nodes": [ - { - "color": "#99ccff", - "id": "main:", - "label": "main:\n test edi,edi\n js 4003ea ", - "shape": "box" + { "id": "main:", + "label": "main:\n test edi,edi\n js 4003ea " + }, - { - "color": "#99ccff", - "id": "main:@3", - "label": "main:@3\n add edi,0x1\n xor eax,eax\n xor edx,edx\n nop DWORD PTR [rax+rax*1+0x0]\n add eax,edx\n add edx,0x1\n cmp edx,edi\n jne 4003e0 ", - "shape": "box" + { "id": "main:@3", + "label": "main:@3\n add edi,0x1\n xor eax,eax\n xor edx,edx\n nop DWORD PTR [rax+rax*1+0x0]\n add eax,edx\n add edx,0x1\n cmp edx,edi\n jne 4003e0 " + }, - { - "color": "#99ccff", - "id": "main:@11", - "label": "main:@11\n ret ", - "shape": "box" + { "id": "main:@11", + "label": "main:@11\n ret " + }, - { - "color": "#99ccff", - "id": " xor eax,eax", - "label": " xor eax,eax:\n ret ", - "shape": "box" + { "id": " xor eax,eax", + "label": " xor eax,eax:\n ret " + }, - { - "color": "#99ccff", - "id": " nop DWORD PTR [rax]", - "label": " nop DWORD PTR [rax]:\n", - "shape": "box" + { "id": " nop DWORD PTR [rax]", + "label": " nop DWORD PTR [rax]:\n" + } ] } diff --git a/test/cfg-cases/cfg-gcc.if-else.json b/test/cfg-cases/cfg-gcc.if-else.json index 662bc3066b3..a83390b717d 100644 --- a/test/cfg-cases/cfg-gcc.if-else.json +++ b/test/cfg-cases/cfg-gcc.if-else.json @@ -797,123 +797,83 @@ "nodes": [ { "id": "main:", - "label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L8", - "color": "#99ccff", - "shape": "box" + "label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L8" }, { "id": "main:@4", - "label": "main:@4\n add edx, edi\n je .L13", - "color": "#99ccff", - "shape": "box" + "label": "main:@4\n add edx, edi\n je .L13" }, { "id": "main:@6", - "label": "main:@6\n imul eax, edi, 223\n cmp eax, 1\n je .L14", - "color": "#99ccff", - "shape": "box" + "label": "main:@6\n imul eax, edi, 223\n cmp eax, 1\n je .L14" }, { "id": "main:@9", - "label": "main:@9\n xor eax, eax", - "color": "#99ccff", - "shape": "box" + "label": "main:@9\n xor eax, eax" }, { "id": ".L1:", - "label": ".L1:\n rep ret", - "color": "#99ccff", - "shape": "box" + "label": ".L1:\n rep ret" }, { "id": ".L14:", - "label": ".L14:\n test edi, edi\n jle .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L14:\n test edi, edi\n jle .L1" }, { "id": ".L14:@15", - "label": ".L14:@15\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L10", - "color": "#99ccff", - "shape": "box" + "label": ".L14:@15\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L10" }, { "id": ".L14:@21", - "label": ".L14:@21\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32", - "color": "#99ccff", - "shape": "box" + "label": ".L14:@21\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32" }, { "id": ".L5:", - "label": ".L5:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L5", - "color": "#99ccff", - "shape": "box" + "label": ".L5:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L5" }, { "id": ".L5:@46", - "label": ".L5:@46\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L15", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@46\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L15" }, { "id": ".L4:", - "label": ".L4:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L4:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1" }, { "id": ".L4:@66", - "label": ".L4:@66\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L4:@66\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1" }, { "id": ".L4:@71", - "label": ".L4:@71\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L4:@71\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1" }, { "id": ".L4:@76", - "label": ".L4:@76\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L4:@76\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1" }, { "id": ".L4:@81", - "label": ".L4:@81\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L4:@81\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1" }, { "id": ".L4:@86", - "label": ".L4:@86\n imul edi, edx\n add eax, edi\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L4:@86\n imul edi, edx\n add eax, edi\n ret" }, { "id": ".L13:", - "label": ".L13:\n imul edx, edi\n imul eax, edx, 78\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L13:\n imul edx, edi\n imul eax, edx, 78\n ret" }, { "id": ".L8:", - "label": ".L8:\n mov eax, 78\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L8:\n mov eax, 78\n ret" }, { "id": ".L15:", - "label": ".L15:\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L15:\n ret" }, { "id": ".L10:", - "label": ".L10:\n mov ecx, 1\n xor edx, edx\n jmp .L4", - "color": "#99ccff", - "shape": "box" + "label": ".L10:\n mov ecx, 1\n xor edx, edx\n jmp .L4" } ], "edges": [ @@ -1085,9 +1045,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_main:", - "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit" } ], "edges": [ diff --git a/test/cfg-cases/cfg-gcc.loop.json b/test/cfg-cases/cfg-gcc.loop.json index ca3b1dc71d7..eac1c9f76fb 100644 --- a/test/cfg-cases/cfg-gcc.loop.json +++ b/test/cfg-cases/cfg-gcc.loop.json @@ -857,135 +857,91 @@ "nodes": [ { "id": "main:", - "label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L10", - "color": "#99ccff", - "shape": "box" + "label": "main:\n lea edx, [0+rdi*8]\n test edx, edx\n je .L10" }, { "id": "main:@4", - "label": "main:@4\n add edx, edi\n je .L14", - "color": "#99ccff", - "shape": "box" + "label": "main:@4\n add edx, edi\n je .L14" }, { "id": "main:@6", - "label": "main:@6\n imul edx, edi, 223\n mov eax, 1\n cmp edx, eax\n je .L15", - "color": "#99ccff", - "shape": "box" + "label": "main:@6\n imul edx, edi, 223\n mov eax, 1\n cmp edx, eax\n je .L15" }, { "id": "main:@10", - "label": "main:@10\n lea edx, [rdi+rax]\n cmp edi, edx\n jl .L16", - "color": "#99ccff", - "shape": "box" + "label": "main:@10\n lea edx, [rdi+rax]\n cmp edi, edx\n jl .L16" }, { "id": "main:@13", - "label": "main:@13\n imul edi, edx\n imul eax, edi\n ret", - "color": "#99ccff", - "shape": "box" + "label": "main:@13\n imul edi, edx\n imul eax, edi\n ret" }, { "id": ".L14:", - "label": ".L14:\n imul edx, edi\n imul eax, edx, 78\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L14:\n imul edx, edi\n imul eax, edx, 78\n ret" }, { "id": ".L15:", - "label": ".L15:\n test edi, edi\n jle .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L15:\n test edi, edi\n jle .L1" }, { "id": ".L15:@23", - "label": ".L15:@23\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L11", - "color": "#99ccff", - "shape": "box" + "label": ".L15:@23\n lea edx, [rdi-1]\n mov esi, edx\n shr esi\n add esi, 1\n cmp edx, 11\n jbe .L11" }, { "id": ".L15:@29", - "label": ".L15:@29\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32", - "color": "#99ccff", - "shape": "box" + "label": ".L15:@29\n mov DWORD PTR [rsp-12], edi\n pxor xmm3, xmm3\n movd xmm7, DWORD PTR [rsp-12]\n mov ecx, esi\n xor edx, edx\n movdqa xmm2, XMMWORD PTR .LC0[rip]\n shr ecx, 2\n pshufd xmm4, xmm7, 0\n movdqa xmm6, XMMWORD PTR .LC1[rip]\n movdqa xmm5, xmm4\n psrlq xmm5, 32" }, { "id": ".L6:", - "label": ".L6:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L6", - "color": "#99ccff", - "shape": "box" + "label": ".L6:\n movdqa xmm0, xmm2\n add edx, 1\n movdqa xmm1, xmm2\n cmp ecx, edx\n paddd xmm2, xmm6\n pmuludq xmm0, xmm4\n pshufd xmm0, xmm0, 8\n psrlq xmm1, 32\n pmuludq xmm1, xmm5\n pshufd xmm1, xmm1, 8\n punpckldq xmm0, xmm1\n paddd xmm3, xmm0\n ja .L6" }, { "id": ".L6:@54", - "label": ".L6:@54\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L17", - "color": "#99ccff", - "shape": "box" + "label": ".L6:@54\n movdqa xmm0, xmm3\n mov r8d, esi\n and r8d, -4\n psrldq xmm0, 8\n paddd xmm3, xmm0\n movdqa xmm0, xmm3\n psrldq xmm0, 4\n paddd xmm3, xmm0\n movd edx, xmm3\n add eax, edx\n lea edx, [r8+r8]\n cmp esi, r8d\n lea ecx, [rdx+1]\n je .L17" }, { "id": ".L5:", - "label": ".L5:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L5:\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+3]\n cmp edi, ecx\n jl .L1" }, { "id": ".L5:@74", - "label": ".L5:@74\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@74\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+5]\n cmp edi, ecx\n jl .L1" }, { "id": ".L5:@79", - "label": ".L5:@79\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@79\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+7]\n cmp edi, ecx\n jl .L1" }, { "id": ".L5:@84", - "label": ".L5:@84\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@84\n imul ecx, edi\n add eax, ecx\n lea ecx, [rdx+9]\n cmp edi, ecx\n jl .L1" }, { "id": ".L5:@89", - "label": ".L5:@89\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@89\n imul ecx, edi\n add edx, 11\n add eax, ecx\n cmp edi, edx\n jl .L1" }, { "id": ".L5:@94", - "label": ".L5:@94\n imul edx, edi\n add eax, edx\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L5:@94\n imul edx, edi\n add eax, edx\n ret" }, { "id": ".L10:", - "label": ".L10:\n mov eax, 78", - "color": "#99ccff", - "shape": "box" + "label": ".L10:\n mov eax, 78" }, { "id": ".L1:", - "label": ".L1:\n rep ret", - "color": "#99ccff", - "shape": "box" + "label": ".L1:\n rep ret" }, { "id": ".L16:", - "label": ".L16:\n mov rax, QWORD PTR [rsi]\n movsx eax, BYTE PTR [rax]\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L16:\n mov rax, QWORD PTR [rsi]\n movsx eax, BYTE PTR [rax]\n ret" }, { "id": ".L17:", - "label": ".L17:\n ret", - "color": "#99ccff", - "shape": "box" + "label": ".L17:\n ret" }, { "id": ".L11:", - "label": ".L11:\n mov ecx, 1\n xor edx, edx\n jmp .L5", - "color": "#99ccff", - "shape": "box" + "label": ".L11:\n mov ecx, 1\n xor edx, edx\n jmp .L5" } ], "edges": [ @@ -1169,9 +1125,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_main:", - "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit" } ], "edges": [ diff --git a/test/cfg-cases/cfg-gcc.single-block.json b/test/cfg-cases/cfg-gcc.single-block.json index de7c2c76ba5..84744bb8473 100644 --- a/test/cfg-cases/cfg-gcc.single-block.json +++ b/test/cfg-cases/cfg-gcc.single-block.json @@ -88,9 +88,7 @@ "nodes": [ { "id": "main:", - "label": "main:\n xor eax, eax\n ret", - "color": "#99ccff", - "shape": "box" + "label": "main:\n xor eax, eax\n ret" } ], "edges": [] @@ -99,9 +97,7 @@ "nodes": [ { "id": "_GLOBAL__sub_I_main:", - "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit", - "color": "#99ccff", - "shape": "box" + "label": "_GLOBAL__sub_I_main:\n sub rsp, 8\n mov edi, OFFSET FLAT:std::__ioinit\n call std::ios_base::Init::Init()\n mov edx, OFFSET FLAT:__dso_handle\n mov esi, OFFSET FLAT:std::__ioinit\n mov edi, OFFSET FLAT:std::ios_base::Init::~Init()\n add rsp, 8\n jmp __cxa_atexit" } ], "edges": [ diff --git a/test/cfg-cases/cfg-gcc.symbol-filter.json b/test/cfg-cases/cfg-gcc.symbol-filter.json index 108f6794d24..5a19d9dd52c 100644 --- a/test/cfg-cases/cfg-gcc.symbol-filter.json +++ b/test/cfg-cases/cfg-gcc.symbol-filter.json @@ -86,9 +86,7 @@ "nodes": [ { "id": "foo(int, int):", - "label": "foo(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo(int, int):\n retq" } ], "edges": [] @@ -97,9 +95,7 @@ "nodes": [ { "id": "foo3(int, int):", - "label": "foo3(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo3(int, int):\n retq" } ], "edges": [] @@ -108,9 +104,7 @@ "nodes": [ { "id": "foo5(int, int):", - "label": "foo5(int, int):\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo5(int, int):\n retq" } ], "edges": [] @@ -119,9 +113,7 @@ "nodes": [ { "id": "foo6::::foo:", - "label": "foo6::::foo:\n retq", - "color": "#99ccff", - "shape": "box" + "label": "foo6::::foo:\n retq" } ], "edges": [] @@ -130,9 +122,7 @@ "nodes": [ { "id": "type metadata accessor for [Swift.Int]:", - "label": "type metadata accessor for [Swift.Int]:\n retq", - "color": "#99ccff", - "shape": "box" + "label": "type metadata accessor for [Swift.Int]:\n retq" } ], "edges": [] diff --git a/test/cfg-tests.js b/test/cfg-tests.js index 15366ebbcfd..fdeec6159c2 100644 --- a/test/cfg-tests.js +++ b/test/cfg-tests.js @@ -22,13 +22,19 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -import * as cfg from '../lib/cfg'; +import * as cfg from '../lib/cfg/cfg'; import {fs, path, resolvePathFromTestRoot} from './utils'; async function DoCfgTest(cfgArg, filename) { const contents = await fs.readJson(filename, 'utf8'); - const structure = cfg.generateStructure('', cfgArg, contents.asm); + const structure = cfg.generateStructure( + { + compilerType: '', + version: cfgArg, + }, + contents.asm, + ); structure.should.deep.equal(contents.cfg); }