From 4c5685344e056e0990c786b1bfb407f8edd155fe Mon Sep 17 00:00:00 2001 From: Mark Aldrich Date: Mon, 10 Oct 2022 21:58:07 -0400 Subject: [PATCH] Added Birdseye, PDP generation --- ts/birdseye/birdseye.html | 309 ++++++++++++++++++++ ts/src/abstractMachine/ExpressionMachine.ts | 23 +- ts/src/birdseye/README.md | 0 ts/src/birdseye/birdseye.ts | 36 +++ ts/src/utils.ts | 2 +- 5 files changed, 367 insertions(+), 3 deletions(-) create mode 100644 ts/birdseye/birdseye.html create mode 100644 ts/src/birdseye/README.md create mode 100644 ts/src/birdseye/birdseye.ts diff --git a/ts/birdseye/birdseye.html b/ts/birdseye/birdseye.html new file mode 100644 index 00000000..6733d252 --- /dev/null +++ b/ts/birdseye/birdseye.html @@ -0,0 +1,309 @@ + + + Augur -- Birdseye + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/ts/src/abstractMachine/ExpressionMachine.ts b/ts/src/abstractMachine/ExpressionMachine.ts index a37e56c9..2a87ef8c 100644 --- a/ts/src/abstractMachine/ExpressionMachine.ts +++ b/ts/src/abstractMachine/ExpressionMachine.ts @@ -3,6 +3,10 @@ import JSMachine from "./JSMachine"; import {StaticDescription} from "../types"; +import * as fs from 'fs'; +import * as path from 'path'; +import generateBirdseyeHTML from "../birdseye/birdseye"; + export default class ExpressionMachine extends JSMachine, [Set, StaticDescription]> { @@ -21,10 +25,10 @@ export default class ExpressionMachine // add them separately, since one of them might not be defined. // TODO: this is a hack. they SHOULD always be defined. if they aren't // we are losing information. - if (a) { + if (a && a instanceof Set) { a.forEach((v) => set.add(v)); } - if (b) { + if (b && b instanceof Set) { b.forEach((v) => set.add(v)); } return set; @@ -37,4 +41,19 @@ export default class ExpressionMachine getUntaintedValue(): Set { return new Set(); } + + /** + * When execution ends in an ExpressionMachine, + * we will automatically generate a web page to + * visualize the resulting "program dependence graph". + */ + endExecution() { + super.endExecution(); + + // Generate the Birdseye HTML. + let birdseyeHTML = generateBirdseyeHTML(this); + + // Write it to the output directory. + fs.writeFileSync(path.dirname(fs.realpathSync(this.outputFilePath)) + `/${this.spec.main}.birdseye.html`, birdseyeHTML) + } } diff --git a/ts/src/birdseye/README.md b/ts/src/birdseye/README.md new file mode 100644 index 00000000..e69de29b diff --git a/ts/src/birdseye/birdseye.ts b/ts/src/birdseye/birdseye.ts new file mode 100644 index 00000000..9b0307b3 --- /dev/null +++ b/ts/src/birdseye/birdseye.ts @@ -0,0 +1,36 @@ +// This file contains the Birdseye auto-generator. +// Given the flows and spec from an ExpressionMachine, +// this file generates a self-contained HTML page +// with a dynamic visualization of the +// *program dependence graph* observed from instrumenting +// the program with Augur. + +import { RunSpecification, StaticDescription } from "../types" +import ExpressionMachine from "../abstractMachine/ExpressionMachine" +import * as fs from 'fs' + +export default function generateBirdseyeHTML(m: ExpressionMachine): string { + // Step 1: Get the `birdseye.html` template. + let birdseyeHTML = fs.readFileSync('./birdseye/birdseye.html').toString() + console.error("Birdseye HTML TEMPLATE: " + birdseyeHTML) + + // Step 2: Insert the flows into this HTML file. + // The template contains the marker `AUGUR REPLACE ME HERE`. + // The flows will be injected into here, as serialized JSON. + birdseyeHTML = birdseyeHTML.replace("AUGUR REPLACE ME HERE", JSON.stringify(m.flows, (key, value) => + value instanceof Set ? [...value] : value, )) + birdseyeHTML = birdseyeHTML.replace("AUGUR REPLACE SPEC HERE", JSON.stringify(m.spec)) + birdseyeHTML = birdseyeHTML.replace("AUGUR REPLACE PROJECT NAME HERE", m.spec.main) + birdseyeHTML = birdseyeHTML.replace("AUGUR REPLACE INSTRUCTIONS HERE", getNumberOfInstructions(m.outputFilePath).toString()) + return birdseyeHTML +} + +function getNumberOfInstructions(outputFilePath: string): number { + // Augur output files have some garbage before and after the instructionns + const numLines = fs.readFileSync(outputFilePath) + .toString() + .split("\n") + .length + + return (numLines - 5) / 2 +} \ No newline at end of file diff --git a/ts/src/utils.ts b/ts/src/utils.ts index b6babc01..7af6554f 100644 --- a/ts/src/utils.ts +++ b/ts/src/utils.ts @@ -209,7 +209,7 @@ export function parseSpec(specPath: string): RunSpecification { } export function executeInstructionsFromFile(path: string, options: RunSpecification) { - const abstractMachine = createAbstractMachine(options); + const abstractMachine = createAbstractMachine(options, false, path); const compiledOutput = require(path); compiledOutput.drive(abstractMachine); return abstractMachine.getTaint();