Esempio n. 1
0
void SingleImplPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(dexen);
  int max_steps = 0;
  while (true) {
    DEBUG_ONLY size_t scope_size = scope.size();
    TypeToTypes intfs_to_classes;
    TypeSet intfs;
    build_type_maps(scope, intfs_to_classes, intfs);
    TypeMap single_impl;
    collect_single_impl(intfs_to_classes, single_impl);

    std::unique_ptr<SingleImplAnalysis> single_impls =
        SingleImplAnalysis::analyze(
            scope, dexen[0], single_impl, intfs, m_pass_config);
    auto optimized = optimize(std::move(single_impls), scope);
    if (optimized == 0 || ++max_steps >= MAX_PASSES) break;
    removed_count += optimized;
    assert(scope_size > scope.size());
  }

  TRACE(INTF, 1, "Removed interfaces %ld\n", removed_count);
  TRACE(INTF, 1,
          "Updated invoke-interface to invoke-virtual %ld\n",
          s_invoke_intf_count);
  post_dexen_changes(scope, dexen);
}
Esempio n. 2
0
void SimplifyCFGPass::run_pass(DexStoresVector& stores,
                           ConfigFiles& /* unused */,
                           PassManager& mgr) {
  const auto& scope = build_class_scope(stores);
  auto total_insns_removed =
      walk::parallel::reduce_methods<int64_t, Scope>(
          scope,
          [](DexMethod* m) -> int64_t {
            auto code = m->get_code();
            if (code == nullptr) {
              return 0;
            }

            int64_t before_insns = code->count_opcodes();

            // build and linearize the CFG
            code->build_cfg(/* editable */ true);
            code->clear_cfg();

            int64_t after_insns = code->count_opcodes();
            return before_insns - after_insns;
          },
          [](int64_t a, int64_t b) { return a + b; });
  mgr.set_metric("insns_removed", total_insns_removed);
}
Esempio n. 3
0
void BasicBlockProfilePass::run_pass(DexStoresVector& stores,
                                     ConfigFiles& /* conf */,
                                     PassManager& pm) {

  std::unordered_set<cfg::Block*> bb_profiled;

  auto scope = build_class_scope(stores);
  walk::methods(scope, [&](DexMethod* method) {
    IRCode* code = method->get_code();
    if (code == nullptr) {
      return;
    }
    code->build_cfg(/* editable */ false);
    const auto& blocks = code->cfg().blocks();

    TRACE(BBPROFILE, 5, "M,%s,%zu,%zu,%d\n",
          method->get_deobfuscated_name().c_str(), blocks.size(),
          code->count_opcodes(), method->is_virtual());

    for (cfg::Block* block : blocks) {
      // Only if the current block is a multi-sink block, its predecessors are
      // profiled. This is for tracing the path back.
      if (block->preds().size() > 1) {
        for (const auto& pred : block->preds()) {
          bb_profiled.insert(pred->src());
        }
      }
      TRACE(BBPROFILE, 5,
            "B,%zu,%zu,%zu,"
            "%zu,%d\n",
            block->id(), num_opcodes_bb(block), block->succs().size(),
            block->preds().size(), bb_profiled.count(block) != 0);
    }
  });
}
Esempio n. 4
0
void ReBindRefsPass::run_pass(
    DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  Scope scope = build_class_scope(stores);
  Rebinder rb(scope, mgr);
  rb.rewrite_refs();
  rb.print_stats();
}
Esempio n. 5
0
void AccessMarkingPass::run_pass(DexStoresVector& stores,
                                 ConfigFiles& /* conf */,
                                 PassManager& pm) {
  auto scope = build_class_scope(stores);
  ClassHierarchy ch = build_type_hierarchy(scope);
  SignatureMap sm = build_signature_map(ch);
  if (m_finalize_classes) {
    auto n_classes_final = mark_classes_final(scope, ch);
    pm.incr_metric("finalized_classes", n_classes_final);
    TRACE(ACCESS, 1, "Finalized %lu classes\n", n_classes_final);
  }
  if (m_finalize_methods) {
    auto n_methods_final = mark_methods_final(scope, ch);
    pm.incr_metric("finalized_methods", n_methods_final);
    TRACE(ACCESS, 1, "Finalized %lu methods\n", n_methods_final);
  }
  if (m_finalize_fields) {
    auto n_fields_final = mark_fields_final(scope);
    pm.incr_metric("finalized_fields", n_fields_final);
    TRACE(ACCESS, 1, "Finalized %lu fields\n", n_fields_final);
  }
  auto candidates = devirtualize(sm);
  auto dmethods = direct_methods(scope);
  candidates.insert(candidates.end(), dmethods.begin(), dmethods.end());
  if (m_privatize_methods) {
    auto privates = find_private_methods(scope, candidates);
    fix_call_sites_private(scope, privates);
    mark_methods_private(privates);
    pm.incr_metric("privatized_methods", privates.size());
    TRACE(ACCESS, 1, "Privatized %lu methods\n", privates.size());
  }
}
Esempio n. 6
0
void SingleImplPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(stores);
  ClassHierarchy ch = build_type_hierarchy(scope);
  int max_steps = 0;
  size_t previous_invoke_intf_count = s_invoke_intf_count;
  removed_count = 0;
  while (true) {
    DEBUG_ONLY size_t scope_size = scope.size();
    TypeToTypes intfs_to_classes;
    TypeSet intfs;
    build_type_maps(scope, intfs_to_classes, intfs);
    TypeMap single_impl;
    collect_single_impl(intfs_to_classes, single_impl);

    std::unique_ptr<SingleImplAnalysis> single_impls =
        SingleImplAnalysis::analyze(
            scope, stores, single_impl, intfs, m_pass_config);
    auto optimized = optimize(
        std::move(single_impls), ch, scope, m_pass_config);
    if (optimized == 0 || ++max_steps >= MAX_PASSES) break;
    removed_count += optimized;
    assert(scope_size > scope.size());
  }

  TRACE(INTF, 1, "Removed interfaces %ld\n", removed_count);
  TRACE(INTF, 1,
          "Updated invoke-interface to invoke-virtual %ld\n",
          s_invoke_intf_count - previous_invoke_intf_count);

  mgr.incr_metric(METRIC_REMOVED_INTERFACES, removed_count);
  mgr.incr_metric(METRIC_INVOKE_INT_TO_VIRT,
                  s_invoke_intf_count - previous_invoke_intf_count);

  post_dexen_changes(scope, stores);
}
Esempio n. 7
0
void RemoverPass::run_pass(DexStoresVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  CMethodStrs rMethodStrs;
  CMethodStrs aMethodStrs;
  std::ifstream aFile;

  f_name_rmethods = cfg.get_rmethods();
  if (f_name_rmethods.empty()) {
      f_name_rmethods = "methods_to_remove.csv";
      std::cout << "Using default file " << f_name_rmethods << std::endl;
  } else
      std::cout << "Using custom file " << f_name_rmethods << std::endl;

  f_name_amethods = cfg.get_amethods();
  if (f_name_amethods.empty()) {
      f_name_amethods = "methods_to_make_abstract.csv";
      std::cout << "Using default file " << f_name_amethods << std::endl;
  } else
      std::cout << "Using custom file " << f_name_amethods << std::endl;

  std::cout << "Reading list of methods to remove from " << f_name_rmethods << "..." << std::endl;
  read_methods(f_name_rmethods, rMethodStrs);

  std::cout << "Reading list of methods to make abstract from " << f_name_amethods << "..." << std::endl;
  read_methods(f_name_amethods, aMethodStrs);

  Scope scope = build_class_scope(dexen);
  std::cout << "Method removal pass" << std::endl;
  remove_methods(scope, rMethodStrs);

  std::cout << "Method abstraction optimization" << std::endl;
  make_methods_abstract(scope, aMethodStrs);

  std::cout << "Method removal pass done." << std::endl;
}
Esempio n. 8
0
/*
 * Check that analyze_enum_clinit returns the correct enum field -> ordinal
 * mapping.
 */
TEST_F(RedexTest, OrdinalAnalysis) {
  always_assert(load_class_file(std::getenv("enum_class_file")));

  auto dexfile = std::getenv("dexfile");
  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  auto scope = build_class_scope(root_store.get_dexen());

  auto enumA = type_class(DexType::get_type(ENUM_A));
  auto enum_field_to_ordinal = optimize_enums::analyze_enum_clinit(enumA);
  auto enumA_zero = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_0:Lcom/"
                          "facebook/redextest/EnumA;"));
  auto enumA_one = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_1:Lcom/"
                          "facebook/redextest/EnumA;"));
  auto enumA_two = static_cast<DexField*>(
      DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_2:Lcom/"
                          "facebook/redextest/EnumA;"));
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_zero), 0);
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_one), 1);
  EXPECT_EQ(enum_field_to_ordinal.at(enumA_two), 2);
}
Esempio n. 9
0
void FinalInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  auto keep_annos = keep_class_member_annos(m_keep_class_member_annos, cfg);
  auto keep_members = keep_class_members(m_keep_class_members);
  auto scope = build_class_scope(dexen);
  inline_field_values(scope);
  remove_unused_fields(scope, keep_annos, keep_members);
}
Esempio n. 10
0
void TypeErasurePass::run_pass(DexStoresVector& stores,
                               ConfigFiles& conf,
                               PassManager& mgr) {
  // Type mapping file
  ModelMerger::s_mapping_file = conf.metafile(m_merged_type_mapping_file);
  Model::s_outdir = conf.get_outdir();

  // Setup Interdex plugin if any models.
  if (m_dex_sharding_model_specs.size() > 0) {
    interdex::InterDexRegistry* registry =
        static_cast<interdex::InterDexRegistry*>(
            PluginRegistry::get().pass_registry(interdex::INTERDEX_PASS_NAME));
    std::function<interdex::InterDexPassPlugin*()> fn =
        [&]() -> interdex::InterDexPassPlugin* {
      return new TypeErasureInterDexPlugin(m_dex_sharding_model_specs, mgr);
    };
    registry->register_plugin("TYPE_ERASURE_PLUGIN", std::move(fn));
  }

  if (m_model_specs.empty()) {
    return;
  }
  auto scope = build_class_scope(stores);
  Model::build_interdex_groups(&conf);
  for (ModelSpec& model_spec : m_model_specs) {
    if (!model_spec.enabled) {
      continue;
    }
    handle_interface_as_root(model_spec, scope, stores);
    erase_model(model_spec, scope, mgr, stores, conf);
  }
  post_dexen_changes(scope, stores);
}
Esempio n. 11
0
void BridgePass::run_pass(DexStoresVector& stores,
                          ConfigFiles& /* conf */,
                          PassManager& mgr) {
  if (mgr.no_proguard_rules()) {
    TRACE(BRIDGE, 1, "BridgePass not run because no ProGuard configuration was provided.");
    return;
  }
  Scope scope = build_class_scope(stores);
  BridgeRemover(scope, mgr, m_black_list).run();
}
Esempio n. 12
0
void CheckBreadcrumbsPass::run_pass(
    DexStoresVector& stores,
    ConfigFiles& cfg,
    PassManager& mgr) {
  auto scope = build_class_scope(stores);
  Breadcrumbs bc(scope, stores);
  bc.check_breadcrumbs();
  bc.report_deleted_types(!fail, mgr);
  bc.report_illegal_refs(fail_if_illegal_refs, mgr);
}
Esempio n. 13
0
void LayoutReachabilityPass::run_pass(DexStoresVector& stores,
                                      ConfigFiles& conf,
                                      PassManager& mgr) {
  TRACE(PGR, 1, "Recomputing layout classes\n");
  std::string apk_dir;
  conf.get_json_config().get("apk_dir", "", apk_dir);
  always_assert(apk_dir.size());

  auto scope = build_class_scope(stores);
  // Update the m_byresources rstate flags on classes/methods
  recompute_reachable_from_xml_layouts(scope, apk_dir);
}
void RemoveRedundantCheckCastsPass::run_pass(DexStoresVector& stores,
                                             ConfigFiles&,
                                             PassManager& mgr) {
  auto scope = build_class_scope(stores);

  size_t num_redundant_check_casts = walk::parallel::reduce_methods<size_t>(
      scope,
      [&](DexMethod* method) -> size_t {
        return remove_redundant_check_casts(method);
      },
      std::plus<size_t>());

  mgr.set_metric("num_redundant_check_casts", num_redundant_check_casts);
}
Esempio n. 15
0
void SimpleInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  const auto no_inline = no_inline_annos(m_no_inline_annos, cfg);

  auto scope = build_class_scope(dexen);
  // gather all inlinable candidates
  auto methods = gather_non_virtual_methods(scope, no_inline);
  select_single_called(scope, methods);

  auto resolver = [&](DexMethod* method, MethodSearch search) {
    return resolve_method(method, search, resolved_refs);
  };

  // inline candidates
  MultiMethodInliner inliner(
      scope, dexen[0], inlinable, resolver, m_inliner_config);
  inliner.inline_methods();

  // delete all methods that can be deleted
  auto inlined = inliner.get_inlined();
  size_t inlined_count = inlined.size();
  size_t deleted = delete_methods(scope, inlined, resolver);

  TRACE(SINL, 3, "recursive %ld\n", inliner.get_info().recursive);
  TRACE(SINL, 3, "blacklisted meths %ld\n", inliner.get_info().blacklisted);
  TRACE(SINL, 3, "more than 16 regs %ld\n",
      inliner.get_info().more_than_16regs);
  TRACE(SINL, 3, "try/catch in callee %ld\n",
      inliner.get_info().try_catch_block);
  TRACE(SINL, 3, "try/catch in caller %ld\n",
      inliner.get_info().caller_tries);
  TRACE(SINL, 3, "virtualizing methods %ld\n", inliner.get_info().need_vmethod);
  TRACE(SINL, 3, "invoke super %ld\n", inliner.get_info().invoke_super);
  TRACE(SINL, 3, "override inputs %ld\n", inliner.get_info().write_over_ins);
  TRACE(SINL, 3, "escaped virtual %ld\n", inliner.get_info().escaped_virtual);
  TRACE(SINL, 3, "known non public virtual %ld\n",
      inliner.get_info().non_pub_virtual);
  TRACE(SINL, 3, "non public ctor %ld\n", inliner.get_info().non_pub_ctor);
  TRACE(SINL, 3, "unknown field %ld\n", inliner.get_info().escaped_field);
  TRACE(SINL, 3, "non public field %ld\n", inliner.get_info().non_pub_field);
  TRACE(SINL, 3, "throws %ld\n", inliner.get_info().throws);
  TRACE(SINL, 3, "array data %ld\n", inliner.get_info().array_data);
  TRACE(SINL, 3, "multiple returns %ld\n", inliner.get_info().multi_ret);
  TRACE(SINL, 3, "reference outside of primary %ld\n",
      inliner.get_info().not_in_primary);
  TRACE(SINL, 3, "not found %ld\n", inliner.get_info().not_found);
  TRACE(SINL, 1,
      "%ld inlined calls over %ld methods and %ld methods removed\n",
      inliner.get_info().calls_inlined, inlined_count, deleted);
}
Esempio n. 16
0
void PassImpl::run_pass(DexStoresVector& stores,
                        ConfigFiles& config,
                        PassManager& mgr) {
  if (m_config.create_runtime_asserts) {
    m_config.runtime_assert =
        RuntimeAssertTransform::Config(config.get_proguard_map());
  }

  auto scope = build_class_scope(stores);
  run(scope);
  mgr.incr_metric("branches_removed", m_transform_stats.branches_removed);
  mgr.incr_metric("materialized_consts", m_transform_stats.materialized_consts);
  mgr.incr_metric("constant_fields", m_stats.constant_fields);
  mgr.incr_metric("constant_methods", m_stats.constant_methods);
}
Esempio n. 17
0
void UnterfacePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  Scope scope = build_class_scope(dexen);

  InterfaceImplementations interfaces(scope);
  assert(interfaces.print_all());

  auto one_level = exclude(interfaces,
      HAS_SUPER | HAS_CHILDREN | NO_VMETHODS,
      IMPL_MULTIPLE_INTERFACES |
          HAS_SUPER |
          HAS_CHILDREN |
          IS_ABSTRACT |
          NO_MATCH_INTERFACE_METHODS |
          HAS_MULTIPLE_INSTANCE_FIELDS |
          MULTIPLE_ARGS_CTOR |
          HAS_CLINIT |
          NO_VMETHODS |
          HAS_STATIC_FIELDS |
          HAS_DIRECT_METHODS);
  interfaces.analyze_candidates(one_level, "No hierarchy, perfect match");

  // optimize
  std::vector<DexClass*> untfs;
  std::unordered_set<DexClass*> removed;
  //optimize(scope, candidates, untfs, removed);

  // write back
  DexClassesVector outdex;
  DexClasses& orig_classes = dexen[0];
  DexClasses classes(orig_classes.size() + untfs.size() - removed.size());
  int pos = 0;
  for (int i = 0; i < orig_classes.size(); ++i) {
    auto cls = orig_classes.get(i);
    if (removed.find(cls) == removed.end()) {
      classes.insert_at(cls, pos++);
    }
  }
  for (auto untf : untfs) {
    classes.insert_at(untf, pos++);
  }
  outdex.emplace_back(std::move(classes));
  for (size_t i = 1; i < dexen.size(); i++) {
    outdex.emplace_back(std::move(dexen[i]));
  }
  dexen = std::move(outdex);
}
Esempio n. 18
0
void DelInitPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  if (!cfg.using_seeds && m_package_filter.size() == 0) {
    TRACE(DELINIT, 1, "No seeds information so not running DelInit\n");
    return;
  }
  package_filter = m_package_filter;
  auto scope = build_class_scope(stores);
  find_referenced_classes(scope);
  DeadRefs drefs;
  drefs.delinit(scope);
  TRACE(DELINIT, 1, "Removed %d <init> methods\n",
      drefs.del_init_res.deleted_inits);
  TRACE(DELINIT, 1, "Removed %d vmethods\n",
      drefs.del_init_res.deleted_vmeths);
  TRACE(DELINIT, 1, "Removed %d ifields\n",
      drefs.del_init_res.deleted_ifields);
  TRACE(DELINIT, 1, "Removed %d dmethods\n",
      drefs.del_init_res.deleted_dmeths);
  post_dexen_changes(scope, stores);
}
Esempio n. 19
0
void RenameClassesPass::run_pass(DexStoresVector& stores,
                                 ConfigFiles& cfg,
                                 PassManager& mgr) {
  const JsonWrapper& json_cfg = cfg.get_json_config();
  if (json_cfg.get("emit_name_based_locators", false)) {
    // TODO: Purge the old RenameClassesPass entirely everywhere.
    fprintf(stderr,
            "[RenameClassesPass] error: Configuration option "
            "emit_locator_strings is not compatible with RenameClassesPass. "
            "Upgrade to RenameClassesPassV2 instead.\n");
    exit(EXIT_FAILURE);
  }

  auto scope = build_class_scope(stores);
  ClassHierarchy ch = build_type_hierarchy(scope);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeSet children;
      get_all_children(ch, base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  mgr.incr_metric(METRIC_CLASSES_IN_SCOPE, scope.size());
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist,
      untouchables, m_rename_annotations, mgr);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
Esempio n. 20
0
void RenameClassesPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  auto scope = build_class_scope(dexen);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeVector children;
      get_all_children(base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist, m_path,
      untouchables, cfg.get_proguard_map(), m_rename_annotations);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
Esempio n. 21
0
void DelSuperPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  const auto& scope = build_class_scope(dexen);
  DelSuper(scope).run(/* do_delete = */true);
}
Esempio n. 22
0
void StaticReloPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  // Clear out counter
  s_cls_delete_count = 0;
  s_meth_delete_count = 0;
  s_meth_move_count = 0;
  s_meth_could_not_move_count = 0;
  s_avg_relocation_load = 0.0f;
  s_max_relocation_load = 0;
  s_single_ref_total_count = 0;
  s_single_ref_moved_count = 0;
  s_line_conflict_but_sig_fine_count = 0;

  auto scope = build_class_scope(dexen);
  auto cls_to_dex = build_class_to_dex_map(dexen);
  auto cls_to_pgo_order = build_class_to_pgo_order_map(dexen, cfg);
  auto dont_optimize_annos = get_dont_optimize_annos(m_config, cfg);

  // Make one pass through all code to find dmethod refs and class refs,
  // needed later on for refining eligibility as well as performing the
  // actual rebinding
  refs_t<DexMethod> dmethod_refs;
  refs_t<DexClass> class_refs;
  build_refs(scope, dmethod_refs, class_refs);

  // Find candidates
  candidates_t candidates = build_candidates(
      scope, class_refs, dont_optimize_annos);

  // Find the relocation target for each dex
  auto dex_to_target = build_dex_to_target_map(
    candidates, cls_to_dex);

  // Build up all the mutations for relocation
  std::unordered_map<DexMethod*, DexClass*> meth_moves;
  std::unordered_set<DexMethod*> meth_deletes;
  std::unordered_set<DexClass*> cls_deletes;
  build_mutations(
    candidates,
    dmethod_refs,
    cls_to_pgo_order,
    cls_to_dex,
    dex_to_target,
    meth_moves,
    meth_deletes,
    cls_deletes);

  // Perform all relocation mutations
  do_mutations(scope, dexen, meth_moves, meth_deletes, cls_deletes, cfg);

  // Final report
  TRACE(
    RELO,
    1,
    "RELO :) Deleted %d methods\n"
    "RELO :) Moved %d methods\n"
    "RELO :) Deleted %d classes\n"
    "RELO :) Moved %d/%d methods to single call site targets\n"
    "RELO :| On average relocated %f methods onto all targets\n"
    "RELO :| Max %d methods relocated onto any one target\n"
    "RELO :( Could not move %d methods\n"
    "RELO :( Could not move %d methods due to conservative "
    "aliasing criteria\n",
    s_meth_delete_count,
    s_meth_move_count,
    s_cls_delete_count,
    s_single_ref_moved_count,
    s_single_ref_total_count,
    s_avg_relocation_load,
    s_max_relocation_load,
    s_meth_could_not_move_count,
    s_line_conflict_but_sig_fine_count);
}
Esempio n. 23
0
void FinalInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(dexen);
  inline_field_values(scope);
  remove_unused_fields(scope, m_remove_class_members);
}
Esempio n. 24
0
void LocalDcePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(dexen);
  LocalDce(scope).run();
}
Esempio n. 25
0
void PeepholePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  auto scope = build_class_scope(dexen);
  PeepholeOptimizer(scope).run();
}
Esempio n. 26
0
Scope build_class_scope(const DexStoresVector& stores) {
  return build_class_scope(DexStoreClassesIterator(stores));
}
Esempio n. 27
0
void BridgePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  Scope scope = build_class_scope(dexen);
  BridgeRemover(scope).run();
}
Esempio n. 28
0
void UnmarkProguardKeepPass::run_pass(DexStoresVector& stores,
                                      ConfigFiles& /* conf */,
                                      PassManager& mgr) {
  auto scope = build_class_scope(stores);
  unmark_keep(scope, m_package_list, m_supercls_list);
}
Esempio n. 29
0
void PassManager::run_passes(DexStoresVector& stores, ConfigFiles& cfg) {
  DexStoreClassesIterator it(stores);
  Scope scope = build_class_scope(it);

  {
    Timer t("API Level Checker");
    api::LevelChecker::init(m_redex_options.min_sdk, scope);
  }

  char* seeds_output_file = std::getenv("REDEX_SEEDS_FILE");
  if (seeds_output_file) {
    std::string seed_filename = seeds_output_file;
    Timer t("Writing seeds file " + seed_filename);
    std::ofstream seeds_file(seed_filename);
    redex::print_seeds(seeds_file, cfg.get_proguard_map(), scope, false, false);
  }
  if (!cfg.get_printseeds().empty()) {
    Timer t("Writing seeds to file " + cfg.get_printseeds());
    std::ofstream seeds_file(cfg.get_printseeds());
    redex::print_seeds(seeds_file, cfg.get_proguard_map(), scope);
    std::ofstream config_file(cfg.get_printseeds() + ".pro");
    redex::show_configuration(config_file, scope, *m_pg_config);
    std::ofstream incoming(cfg.get_printseeds() + ".incoming");
    redex::print_classes(incoming, cfg.get_proguard_map(), scope);
    std::ofstream shrinking_file(cfg.get_printseeds() + ".allowshrinking");
    redex::print_seeds(shrinking_file, cfg.get_proguard_map(), scope, true,
                       false);
    std::ofstream obfuscation_file(cfg.get_printseeds() + ".allowobfuscation");
    redex::print_seeds(obfuscation_file, cfg.get_proguard_map(), scope, false,
                       true);
  }

  // Enable opt decision logging if specified in config.
  const Json::Value& opt_decisions_args =
      cfg.get_json_config()["opt_decisions"];
  if (opt_decisions_args.get("enable_logs", false).asBool()) {
    opt_metadata::OptDataMapper::get_instance().enable_logs();
  }

  // TODO(fengliu) : Remove Pass::eval_pass API
  for (size_t i = 0; i < m_activated_passes.size(); ++i) {
    Pass* pass = m_activated_passes[i];
    TRACE(PM, 1, "Evaluating %s...\n", pass->name().c_str());
    Timer t(pass->name() + " (eval)");
    m_current_pass_info = &m_pass_info[i];
    pass->eval_pass(stores, cfg, *this);
    m_current_pass_info = nullptr;
  }

  // Retrieve the type checker's settings.
  const Json::Value& type_checker_args =
      cfg.get_json_config()["ir_type_checker"];
  bool run_after_each_pass =
      type_checker_args.get("run_after_each_pass", false).asBool();
  // When verify_none is enabled, it's OK to have polymorphic constants.
  bool polymorphic_constants =
      type_checker_args.get("polymorphic_constants", false).asBool() ||
      get_redex_options().verify_none_enabled;
  bool verify_moves = type_checker_args.get("verify_moves", false).asBool();
  bool check_no_overwrite_this =
      type_checker_args.get("check_no_overwrite_this", false).asBool();
  std::unordered_set<std::string> trigger_passes;

  for (auto& trigger_pass : type_checker_args["run_after_passes"]) {
    trigger_passes.insert(trigger_pass.asString());
  }

  for (size_t i = 0; i < m_activated_passes.size(); ++i) {
    Pass* pass = m_activated_passes[i];
    TRACE(PM, 1, "Running %s...\n", pass->name().c_str());
    Timer t(pass->name() + " (run)");
    m_current_pass_info = &m_pass_info[i];

    {
      ScopedCommandProfiling cmd_prof(
          m_profiler_info && m_profiler_info->pass == pass
              ? boost::make_optional(m_profiler_info->command)
              : boost::none);
      jemalloc_util::ScopedProfiling malloc_prof(m_malloc_profile_pass == pass);
      pass->run_pass(stores, cfg, *this);
    }

    if (run_after_each_pass || trigger_passes.count(pass->name()) > 0) {
      scope = build_class_scope(it);
      // It's OK to overwrite the `this` register if we are not yet at the
      // output phase -- the register allocator can fix it up later.
      run_type_checker(scope, polymorphic_constants, verify_moves,
                       /* check_no_overwrite_this */ false);
    }
    m_current_pass_info = nullptr;
  }

  // Always run the type checker before generating the optimized dex code.
  scope = build_class_scope(it);
  run_type_checker(scope, polymorphic_constants, verify_moves,
                   check_no_overwrite_this);

  if (!cfg.get_printseeds().empty()) {
    Timer t("Writing outgoing classes to file " + cfg.get_printseeds() +
            ".outgoing");
    // Recompute the scope.
    scope = build_class_scope(it);
    std::ofstream outgoing(cfg.get_printseeds() + ".outgoing");
    redex::print_classes(outgoing, cfg.get_proguard_map(), scope);
  }
}
Esempio n. 30
0
void DelSuperPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) {
  const auto& scope = build_class_scope(stores);
  DelSuper(scope).run(/* do_delete = */true, mgr);
}