tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dumpCFG.js (7561B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // const cfg = loadCFG(scriptArgs[0]);
      6 // dump_CFG(cfg);
      7 
      8 function loadCFG(filename) {
      9  const data = os.file.readFile(filename);
     10  return JSON.parse(data);
     11 }
     12 
     13 function dump_CFG(cfg) {
     14  for (const body of cfg)
     15    dump_body(body);
     16 }
     17 
     18 function dump_body(body, src, dst) {
     19  const {BlockId,Command,DefineVariable,Index,Location,PEdge,PPoint,Version} = body;
     20 
     21  const [mangled, unmangled] = splitFunction(BlockId.Variable.Name[0]);
     22  print(`${unmangled} at ${Location[0].CacheString}:${Location[0].Line}`);
     23 
     24  if (src === undefined) {
     25    for (const def of DefineVariable)
     26      print(str_definition(def));
     27    print("");
     28  }
     29 
     30  for (const edge of PEdge) {
     31    if (src === undefined || edge.Index[0] == src) {
     32      if (dst == undefined || edge.Index[1] == dst)
     33        print(str_edge(edge, body));
     34    }
     35  }
     36 }
     37 
     38 function str_definition(def) {
     39  const {Type, Variable} = def;
     40  return `define ${str_Variable(Variable)} : ${str_Type(Type)}`;
     41 }
     42 
     43 function badFormat(what, val) {
     44  printErr("Bad format of " + what + ": " + JSON.stringify(val, null, 4));
     45  printErr((new Error).stack);
     46 }
     47 
     48 function str_Variable(variable) {
     49  if (variable.Kind == 'Return')
     50    return '<returnval>';
     51  else if (variable.Kind == 'This')
     52    return 'this';
     53 
     54  try {
     55    return variable.Name[1];
     56  } catch(e) {
     57    badFormat("variable", variable);
     58  }
     59 }
     60 
     61 function str_Type(type) {
     62  try {
     63    const {Kind, Type, Name, TypeFunctionArguments} = type;
     64    if (Kind == 'Pointer')
     65      return str_Type(Type) + ["*", "&", "&&"][type.Reference];
     66    else if (Kind == 'CSU')
     67      return Name;
     68    else if (Kind == 'Array')
     69      return str_Type(Type) + "[]";
     70    else if (Kind == 'Function')
     71      return str_Type(Type) + "()";
     72 
     73    return Kind;
     74  } catch(e) {
     75    badFormat("type", type);
     76  }
     77 }
     78 
     79 var OpCodeNames = {
     80  'LessEqual': ['<=', '>'],
     81  'LessThan': ['<', '>='],
     82  'GreaterEqual': ['>=', '<'],
     83  'Greater': ['>', '<='],
     84  'Plus': '+',
     85  'Minus': '-',
     86 };
     87 
     88 function opcode_name(opcode, invert) {
     89  if (opcode in OpCodeNames) {
     90    const name = OpCodeNames[opcode];
     91    if (invert === undefined)
     92      return name;
     93    return name[invert ? 1 : 0];
     94  } else {
     95    if (invert === undefined)
     96      return opcode;
     97    return (invert ? '!' : '') + opcode;
     98  }
     99 }
    100 
    101 function str_value(val, env, options) {
    102  const {Kind, Variable, String, Exp} = val;
    103  if (Kind == 'Var')
    104    return str_Variable(Variable);
    105  else if (Kind == 'Drf') {
    106    // Suppress the vtable lookup dereference
    107    if (Exp[0].Kind == 'Fld' && "FieldInstanceFunction" in Exp[0].Field)
    108      return str_value(Exp[0], env);
    109    const exp = str_value(Exp[0], env);
    110    if (options && options.noderef)
    111      return exp;
    112    return "*" + exp;
    113  } else if (Kind == 'Fld') {
    114    const {Exp, Field} = val;
    115    const name = Field.Name[0];
    116    if ("FieldInstanceFunction" in Field) {
    117      return Field.FieldCSU.Type.Name + "." + name;
    118    }
    119    const container = str_value(Exp[0]);
    120    if (container.startsWith("*"))
    121      return container.substring(1) + "->" + name;
    122    return container + "." + name;
    123  } else if (Kind == 'Empty') {
    124    return '<unknown>';
    125  } else if (Kind == 'Binop') {
    126    const {OpCode} = val;
    127    const op = opcode_name(OpCode);
    128    return `${str_value(Exp[0], env)} ${op} ${str_value(Exp[1], env)}`;
    129  } else if (Kind == 'Unop') {
    130    const exp = str_value(Exp[0], env);
    131    const {OpCode} = val;
    132    if (OpCode == 'LogicalNot')
    133      return `not ${exp}`;
    134    return `${OpCode}(${exp})`;
    135  } else if (Kind == 'Index') {
    136    const index = str_value(Exp[1], env);
    137    if (Exp[0].Kind == 'Drf')
    138      return `${str_value(Exp[0], env, {noderef:true})}[${index}]`;
    139    else
    140      return `&${str_value(Exp[0], env)}[${index}]`;
    141  } else if (Kind == 'NullTest') {
    142    return `nullptr == ${str_value(Exp[0], env)}`;
    143  } else if (Kind == "String") {
    144    return '"' + String + '"';
    145  } else if (String !== undefined) {
    146    return String;
    147  }
    148  badFormat("value", val);
    149 }
    150 
    151 function str_thiscall_Exp(exp) {
    152  return exp.Kind == 'Drf' ? str_value(exp.Exp[0]) + "->" : str_value(exp) + ".";
    153 }
    154 
    155 function stripcsu(s) {
    156    return s.replace("class ", "").replace("struct ", "").replace("union ");
    157 }
    158 
    159 function str_call(prefix, edge, env) {
    160  const {Exp, Type, PEdgeCallArguments, PEdgeCallInstance} = edge;
    161  const {Kind, Type:cType, TypeFunctionArguments, TypeFunctionCSU} = Type;
    162 
    163  if (Kind == 'Function') {
    164    const params = PEdgeCallArguments ? PEdgeCallArguments.Exp : [];
    165    const strParams = params.map(str_value);
    166 
    167    let func;
    168    let comment = "";
    169    let assign_exp;
    170    if (PEdgeCallInstance) {
    171      const csu = TypeFunctionCSU.Type.Name;
    172      const method = str_value(Exp[0], env);
    173 
    174      // Heuristic to only display the csu for constructors
    175      if (csu.includes(method)) {
    176        func = stripcsu(csu) + "::" + method;
    177      } else {
    178        func = method;
    179        comment = "# " + csu + "::" + method + "\n";
    180      }
    181 
    182      const {Exp: thisExp} = PEdgeCallInstance;
    183      func = str_thiscall_Exp(thisExp) + func;
    184    } else {
    185      func = str_value(Exp[0]);
    186    }
    187    assign_exp = Exp[1];
    188 
    189    let assign = "";
    190    if (assign_exp) {
    191      assign = str_value(assign_exp) + " := ";
    192    }
    193    return `${comment}${prefix} Call ${assign}${func}(${strParams.join(", ")})`;
    194  }
    195 
    196  print(JSON.stringify(edge, null, 4));
    197  throw new Error("unhandled format error");
    198 }
    199 
    200 function str_assign(prefix, edge) {
    201  const {Exp} = edge;
    202  const [lhs, rhs] = Exp;
    203  return `${prefix} Assign ${str_value(lhs)} := ${str_value(rhs)}`;
    204 }
    205 
    206 function str_loop(prefix, edge) {
    207  const {BlockId: {Loop}} = edge;
    208  return `${prefix} Loop ${Loop}`;
    209 }
    210 
    211 function str_assume(prefix, edge) {
    212  const {Exp, PEdgeAssumeNonZero} = edge;
    213  const cmp = PEdgeAssumeNonZero ? "" : "!";
    214 
    215  const {Exp: aExp, Kind, OpCode} = Exp[0];
    216  if (Kind == 'Binop') {
    217    const [lhs, rhs] = aExp;
    218    const op = opcode_name(OpCode, !PEdgeAssumeNonZero);
    219    return `${prefix} Assume ${str_value(lhs)} ${op} ${str_value(rhs)}`;
    220  } else if (Kind == 'Unop') {
    221    return `${prefix} Assume ${cmp}${OpCode} ${str_value(aExp[0])}`;
    222  } else if (Kind == 'NullTest') {
    223    return `${prefix} Assume nullptr ${cmp}== ${str_value(aExp[0])}`;
    224  } else if (Kind == 'Drf') {
    225    return `${prefix} Assume ${cmp}${str_value(Exp[0])}`;
    226  }
    227 
    228  print(JSON.stringify(edge, null, 4));
    229  throw new Error("unhandled format error");
    230 }
    231 
    232 function str_edge(edge, env) {
    233  const {Index, Kind} = edge;
    234  const [src, dst] = Index;
    235  const prefix = `[${src},${dst}]`;
    236 
    237  if (Kind == "Call")
    238    return str_call(prefix, edge, env);
    239  if (Kind == 'Assign')
    240    return str_assign(prefix, edge);
    241  if (Kind == 'Assume')
    242    return str_assume(prefix, edge);
    243  if (Kind == 'Loop')
    244    return str_loop(prefix, edge);
    245 
    246  print(JSON.stringify(edge, null, 4));
    247  throw "unhandled edge type";
    248 }
    249 
    250 function str(unknown) {
    251  if ("Name" in unknown) {
    252    return str_Variable(unknown);
    253  } else if ("Index" in unknown) {
    254    // Note: Variable also has .Index, with a different meaning.
    255    return str_edge(unknown);
    256  } else if ("Type" in unknown) {
    257    if ("Variable" in unknown) {
    258      return str_definition(unknown);
    259    } else {
    260      return str_Type(unknown);
    261    }
    262  } else if ("Kind" in unknown) {
    263    if ("BlockId" in unknown)
    264      return str_Variable(unknown);
    265    return str_value(unknown);
    266  }
    267  return "unknown";
    268 }
    269 
    270 function jdump(x) {
    271  print(JSON.stringify(x, null, 4));
    272  quit(0);
    273 }