void dump_sql()

in tools/redex-tool/DexSqlDump.cpp [196:381]


void dump_sql(FILE* fdout,
              DexStoresVector& stores,
              ProguardMap& pg_map,
              const char* prefix) {
  fprintf(fdout,
          R"___(
DROP TABLE IF EXISTS %1$sfield_string_refs;
DROP TABLE IF EXISTS %1$smethod_string_refs;
DROP TABLE IF EXISTS %1$smethod_field_refs;
DROP TABLE IF EXISTS %1$smethod_method_refs;
DROP TABLE IF EXISTS %1$smethod_class_refs;
DROP TABLE IF EXISTS %1$sstrings;
DROP TABLE IF EXISTS %1$sfields;
DROP TABLE IF EXISTS %1$sis_a;
DROP TABLE IF EXISTS %1$smethods;
DROP TABLE IF EXISTS %1$sclasses;
CREATE TABLE %1$sclasses (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  dex TEXT NOT NULL, -- dex identifiers look like "<store>/<dex_id>"
  name TEXT NOT NULL,
  obfuscated_name TEXT NOT NULL,
  access INTEGER NOT NULL
);
CREATE TABLE %1$smethods (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  class_id INTEGER, -- fk:classes.id
  name TEXT NOT NULL,
  obfuscated_name TEXT NOT NULL,
  access INTEGER NOT NULL,
  code_size INTEGER NOT NULL
);
CREATE TABLE %1$sis_a (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  class_id INTEGER, -- fk:classes.id
  is_a_class_id INTEGER -- fk:classes.id
);
CREATE TABLE %1$sstrings (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  text TEXT NOT NULL
);
CREATE TABLE %1$sfields (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  class_id INTEGER, -- fk:classes.id
  name TEXT NOT NULL,
  obfuscated_name TEXT NOT NULL,
  access INTEGER NOT NULL
);
CREATE TABLE %1$sfield_string_refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  field_id INTEGER NOT NULL, -- fk:fields.id
  ref_string_id INTEGER NOT NULL -- fk:strings.id
);
CREATE TABLE %1$smethod_class_refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  method_id INTEGER, -- fk:methods.id
  ref_class_id INTEGER NOT NULL, -- fk:classes.id
  opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_method_refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  method_id INTEGER, -- fk:methods.id
  ref_method_id INTEGER NOT NULL, -- fk:methods.id
  opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_field_refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  method_id INTEGER, -- fk:methods.id
  ref_field_id INTEGER NOT NULL, -- fk:fields.id
  opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_string_refs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  method_id INTEGER, -- fk:methods.id
  ref_string_id INTEGER NOT NULL, -- fk:strings.id
  opcode INTEGER NOT NULL
);
)___",
          prefix);
  int next_class_id = 0;
  int next_method_id = 0;
  int next_field_id = 0;
  int next_string_id = 0;

  // Dump all dex items
  fprintf(fdout, "BEGIN TRANSACTION;\n");
  for (auto& store : stores) {
    auto store_name = store.get_name();
    auto& dexen = store.get_dexen();
    apply_deobfuscated_names(dexen, pg_map);
    for (size_t dex_idx = 0; dex_idx < dexen.size(); ++dex_idx) {
      auto& dex = dexen[dex_idx];
      GatheredTypes gtypes(&dex);
      auto strings = gtypes.get_cls_order_dexstring_emitlist();
      for (auto dexstr : strings) {
        int id = next_string_id++;
        string_ids[dexstr] = id;
        // Escape string before inserting. ' -> ''
        std::string esc(dexstr->c_str());
        boost::replace_all(esc, "'", "''");
        fprintf(fdout,
                "INSERT INTO %sstrings VALUES(%d, '%s');\n",
                prefix,
                id,
                esc.c_str());
      }
      std::string dex_id_str(store_name + "/" + std::to_string(dex_idx));
      const char* dex_id = dex_id_str.c_str();
      for (const auto& cls : dex) {
        int class_id = next_class_id++;
        dump_class(fdout, prefix, dex_id, cls, class_id);
        class_ids[cls] = class_id;
        for (auto field : cls->get_ifields()) {
          int field_id = next_field_id++;
          field_ids[field] = field_id;
          dump_field(fdout, prefix, class_id, field, field_id);
        }
        for (auto field : cls->get_sfields()) {
          int field_id = next_field_id++;
          field_ids[field] = field_id;
          dump_field(fdout, prefix, class_id, field, field_id);
        }
        for (const auto& meth : cls->get_dmethods()) {
          int meth_id = next_method_id++;
          method_ids[meth] = meth_id;
          dump_method(fdout, prefix, class_id, meth, meth_id);
        }
        for (auto& meth : cls->get_vmethods()) {
          int meth_id = next_method_id++;
          method_ids[meth] = meth_id;
          dump_method(fdout, prefix, class_id, meth, meth_id);
        }
      }
    }
  }
  fprintf(fdout, "END TRANSACTION;\n");

  // Dump references
  fprintf(fdout, "BEGIN TRANSACTION;\n");
  for (auto& store : stores) {
    auto& dexen = store.get_dexen();
    for (size_t dex_idx = 0; dex_idx < dexen.size(); ++dex_idx) {
      auto& dex = dexen[dex_idx];
      for (const auto& cls : dex) {
        for (const auto& meth : cls->get_dmethods()) {
          int meth_id = method_ids[meth];
          dump_method_refs(fdout, prefix, meth, meth_id);
        }
        for (auto& meth : cls->get_vmethods()) {
          int meth_id = method_ids[meth];
          dump_method_refs(fdout, prefix, meth, meth_id);
        }
        for (const auto& field : cls->get_sfields()) {
          int field_id = field_ids[field];
          dump_field_refs(fdout, prefix, field, field_id);
        }
        for (const auto& field : cls->get_ifields()) {
          int field_id = field_ids[field];
          dump_field_refs(fdout, prefix, field, field_id);
        }
      }
    }
  }
  fprintf(fdout, "END TRANSACTION;\n");

  // Dump hierarchy
  auto scope = build_class_scope(stores);
  ClassHierarchy ch = build_type_hierarchy(scope);
  int next_is_a_id = 0;
  fprintf(fdout, "BEGIN TRANSACTION;\n");
  for (auto& cls : scope) {
    TypeSet results;
    get_all_children_or_implementors(ch, scope, cls, results);
    for (auto type : results) {
      auto type_cls = type_class(type);
      if (type_cls) {
        fprintf(fdout,
                "INSERT INTO %sis_a VALUES(%d, %d, %d);\n",
                prefix,
                next_is_a_id++,
                class_ids[type_cls],
                class_ids[cls]);
      }
    }
  }
  fprintf(fdout, "END TRANSACTION;\n");
}