/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// const cfg = loadCFG(scriptArgs[0]);
// dump_CFG(cfg);
function loadCFG(filename) {
const data = os.file.readFile(filename);
return JSON.parse(data);
}
function dump_CFG(cfg) {
for (const body of cfg)
dump_body(body);
}
function dump_body(body, src, dst) {
const {BlockId,Command,DefineVariable,Index,Location,PEdge,PPoint,Version} = body;
const [mangled, unmangled] = splitFunction(BlockId.Variable.Name[0]);
print(`${unmangled} at ${Location[0].CacheString}:${Location[0].Line}`);
if (src === undefined) {
for (const def of DefineVariable)
print(str_definition(def));
print("" );
}
for (const edge of PEdge) {
if (src === undefined || edge.Index[0] == src) {
if (dst == undefined || edge.Index[1] == dst)
print(str_edge(edge, body));
}
}
}
function str_definition(def) {
const {Type, Variable} = def;
return `define ${str_Variable(Variable)} : ${str_Type(Type)}`;
}
function badFormat(what, val) {
printErr("Bad format of " + what + ": " + JSON.stringify(val, null , 4));
printErr((new Error).stack);
}
function str_Variable(variable) {
if (variable.Kind == 'Return' )
return '' ;
else if (variable.Kind == 'This' )
return 'this' ;
try {
return variable.Name[1];
} catch (e) {
badFormat("variable" , variable);
}
}
function str_Type(type) {
try {
const {Kind, Type, Name, TypeFunctionArguments} = type;
if (Kind == 'Pointer' )
return str_Type(Type) + ["*" , "&" , "&&" ][type.Reference];
else if (Kind == 'CSU' )
return Name;
else if (Kind == 'Array' )
return str_Type(Type) + "[]" ;
else if (Kind == 'Function' )
return str_Type(Type) + "()" ;
return Kind;
} catch (e) {
badFormat("type" , type);
}
}
var OpCodeNames = {
'LessEqual' : ['<=' , '>' ],
'LessThan' : ['<' , '>=' ],
'GreaterEqual' : ['>=' , '<' ],
'Greater' : ['>' , '<=' ],
'Plus' : '+' ,
'Minus' : '-' ,
};
function opcode_name(opcode, invert) {
if (opcode in OpCodeNames) {
const name = OpCodeNames[opcode];
if (invert === undefined)
return name;
return name[invert ? 1 : 0];
} else {
if (invert === undefined)
return opcode;
return (invert ? '!' : '' ) + opcode;
}
}
function str_value(val, env, options) {
const {Kind, Variable, String, Exp} = val;
if (Kind == 'Var' )
return str_Variable(Variable);
else if (Kind == 'Drf' ) {
// Suppress the vtable lookup dereference
if (Exp[0].Kind == 'Fld' && "FieldInstanceFunction" in Exp[0].Field)
return str_value(Exp[0], env);
const exp = str_value(Exp[0], env);
if (options && options.noderef)
return exp;
return "*" + exp;
} else if (Kind == 'Fld' ) {
const {Exp, Field} = val;
const name = Field.Name[0];
if ("FieldInstanceFunction" in Field) {
return Field.FieldCSU.Type.Name + "." + name;
}
const container = str_value(Exp[0]);
if (container.startsWith("*" ))
return container.substring(1) + "->" + name;
return container + "." + name;
} else if (Kind == 'Empty' ) {
return '' ;
} else if (Kind == 'Binop' ) {
const {OpCode} = val;
const op = opcode_name(OpCode);
return `${str_value(Exp[0], env)} ${op} ${str_value(Exp[1], env)}`;
} else if (Kind == 'Unop' ) {
const exp = str_value(Exp[0], env);
const {OpCode} = val;
if (OpCode == 'LogicalNot' )
return `not ${exp}`;
return `${OpCode}(${exp})`;
} else if (Kind == 'Index' ) {
const index = str_value(Exp[1], env);
if (Exp[0].Kind == 'Drf' )
return `${str_value(Exp[0], env, {noderef:true })}[${index}]`;
else
return `&${str_value(Exp[0], env)}[${index}]`;
} else if (Kind == 'NullTest' ) {
return `nullptr == ${str_value(Exp[0], env)}`;
} else if (Kind == "String" ) {
return '"' + String + '"' ;
} else if (String !== undefined) {
return String;
}
badFormat("value" , val);
}
function str_thiscall_Exp(exp) {
return exp.Kind == 'Drf' ? str_value(exp.Exp[0]) + "->" : str_value(exp) + "." ;
}
function stripcsu(s) {
return s.replace("class " , "" ).replace("struct " , "" ).replace("union " );
}
function str_call(prefix, edge, env) {
const {Exp, Type, PEdgeCallArguments, PEdgeCallInstance} = edge;
const {Kind, Type:cType, TypeFunctionArguments, TypeFunctionCSU} = Type;
if (Kind == 'Function' ) {
const params = PEdgeCallArguments ? PEdgeCallArguments.Exp : [];
const strParams = params.map(str_value);
let func;
let comment = "" ;
let assign_exp;
if (PEdgeCallInstance) {
const csu = TypeFunctionCSU.Type.Name;
const method = str_value(Exp[0], env);
// Heuristic to only display the csu for constructors
if (csu.includes(method)) {
func = stripcsu(csu) + "::" + method;
} else {
func = method;
comment = "# " + csu + "::" + method + "\n" ;
}
const {Exp: thisExp} = PEdgeCallInstance;
func = str_thiscall_Exp(thisExp) + func;
} else {
func = str_value(Exp[0]);
}
assign_exp = Exp[1];
let assign = "" ;
if (assign_exp) {
assign = str_value(assign_exp) + " := " ;
}
return `${comment}${prefix} Call ${assign}${func}(${strParams.join(", " )})`;
}
print(JSON.stringify(edge, null , 4));
throw new Error("unhandled format error" );
}
function str_assign(prefix, edge) {
const {Exp} = edge;
const [lhs, rhs] = Exp;
return `${prefix} Assign ${str_value(lhs)} := ${str_value(rhs)}`;
}
function str_loop(prefix, edge) {
const {BlockId: {Loop}} = edge;
return `${prefix} Loop ${Loop}`;
}
function str_assume(prefix, edge) {
const {Exp, PEdgeAssumeNonZero} = edge;
const cmp = PEdgeAssumeNonZero ? "" : "!" ;
const {Exp: aExp, Kind, OpCode} = Exp[0];
if (Kind == 'Binop' ) {
const [lhs, rhs] = aExp;
const op = opcode_name(OpCode, !PEdgeAssumeNonZero);
return `${prefix} Assume ${str_value(lhs)} ${op} ${str_value(rhs)}`;
} else if (Kind == 'Unop' ) {
return `${prefix} Assume ${cmp}${OpCode} ${str_value(aExp[0])}`;
} else if (Kind == 'NullTest' ) {
return `${prefix} Assume nullptr ${cmp}== ${str_value(aExp[0])}`;
} else if (Kind == 'Drf' ) {
return `${prefix} Assume ${cmp}${str_value(Exp[0])}`;
}
print(JSON.stringify(edge, null , 4));
throw new Error("unhandled format error" );
}
function str_edge(edge, env) {
const {Index, Kind} = edge;
const [src, dst] = Index;
const prefix = `[${src},${dst}]`;
if (Kind == "Call" )
return str_call(prefix, edge, env);
if (Kind == 'Assign' )
return str_assign(prefix, edge);
if (Kind == 'Assume' )
return str_assume(prefix, edge);
if (Kind == 'Loop' )
return str_loop(prefix, edge);
print(JSON.stringify(edge, null , 4));
throw "unhandled edge type" ;
}
function str(unknown) {
if ("Name" in unknown) {
return str_Variable(unknown);
} else if ("Index" in unknown) {
// Note: Variable also has .Index, with a different meaning.
return str_edge(unknown);
} else if ("Type" in unknown) {
if ("Variable" in unknown) {
return str_definition(unknown);
} else {
return str_Type(unknown);
}
} else if ("Kind" in unknown) {
if ("BlockId" in unknown)
return str_Variable(unknown);
return str_value(unknown);
}
return "unknown" ;
}
function jdump(x) {
print(JSON.stringify(x, null , 4));
quit(0);
}
quality 96%
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland