Esempio n. 1
0
def save_html_report(output_dir, smalitree, app_name, granularity):
    templates = PageTemplateLoader(config.templates_path)
    resources_dir = os.path.join(output_dir, '.resources')
    Utils2.copytree(config.html_resources_dir_path, resources_dir)

    class_template = templates['class.pt']

    for cl in smalitree.classes:
        save_class(cl, class_template, output_dir, app_name, granularity)

    save_coverage(smalitree, templates, output_dir, app_name, granularity)
Esempio n. 2
0
 def get_xml(self):
     report = Element("report")
     report.set("name", self.app_name)
     
     groups = Utils2.get_groupped_classes(self.smalitree)
     for g in groups:
         package = SubElement(report,"package")
         package.set("name", Utils2.get_package_name(g[0].name))
         for cl in g:
             if (cl.is_coverable()):
                 self.add_xml_class(package, cl)
     return etree.tostring(report, pretty_print=True)
Esempio n. 3
0
 def save_reporter_array_stats(self, classes_info, verbose=False):
     log_path = os.path.join("allocation_log.csv")
     csv_text = ""
     if self.mem_stats == "verbose":
         entries = [
             "{},{},{}".format(self.package, cl[0], cl[1])
             for cl in classes_info
         ]
         csv_text = "\n".join(entries)
     else:
         memory = sum(cl[1] for cl in classes_info)
         logging.info(
             "{} bytes allocated in AcvReporter.smali".format(memory))
         csv_text = "{},{}".format(self.package, memory)
     Utils.log_entry(log_path, csv_text + '\n')
Esempio n. 4
0
def save_package_indexhtml(class_group, templates, output_dir, app_name,
                           granularity):
    folder = class_group[0].folder.replace('\\', '/')
    class_name_with_pkg = class_group[0].name
    package_name = Utils2.get_standart_package_name(class_name_with_pkg)
    init_table = templates['init_table.pt']
    init_row = templates['init_row.pt']
    index_template = templates['index.pt']

    slash_num = class_name_with_pkg.count('/')
    root_path = ''
    for i in range(slash_num):
        root_path += '../'
    total_coverage_data = CoverageData()
    rows = []
    for cl in class_group:
        elementlink = os.path.join(root_path, folder,
                                   cl.file_name + '.html').replace('\\', '/')
        elementname = cl.file_name
        coverage_data = CoverageData(lines=cl.coverable(),
                                     lines_missed=cl.not_covered(),
                                     lines_covered=cl.covered(),
                                     methods_covered=cl.mtds_covered(),
                                     methods_missed=cl.mtds_not_covered(),
                                     methods=cl.mtds_coverable())
        coverage_data.update_coverage_for_single_class_from_methods()
        coverage = coverage_data.get_coverage(granularity)
        row = init_row(
            elementlink=elementlink,
            type='class',
            elementname=elementname,
            coverage=coverage_data.format_coverage(coverage),
            respath=root_path,
            coverage_data=coverage_data,
            is_instruction_level=Granularity.is_instruction(granularity),
            progress_missed=coverage_data.missed(granularity),
            progress_covered=coverage_data.covered(granularity))
        rows.append(Markup(row))
        total_coverage_data.add_data(coverage_data)
    total_coverage = total_coverage_data.get_formatted_coverage(granularity)
    table = init_table(
        rows=Markup("\n".join(rows)),
        total_coverage=total_coverage,
        is_instruction_level=Granularity.is_instruction(granularity),
        total_coverage_data=total_coverage_data,
        progress_covered=total_coverage_data.covered(granularity),
        progress_all=total_coverage_data.coverable(granularity))
    html = index_template(table=Markup(table),
                          appname=app_name,
                          title=folder,
                          package=package_name,
                          respath=root_path,
                          file_name=None,
                          granularity=Granularity.get(granularity))
    rel_path = os.path.join(folder, 'index.html').replace('\\', '/')
    path = os.path.join(output_dir, rel_path).replace('\\', '/')
    with open(path, 'w') as f:
        f.write(html)
    return (package_name, rel_path, total_coverage_data)
Esempio n. 5
0
def instrument_apk(apk_path,
                   result_dir,
                   dbg_start=None,
                   dbg_end=None,
                   installation=False,
                   granularity=Granularity.default,
                   mem_stats=None):
    '''
    I assume that the result_dir is empty is checked.
    '''
    apktool = ApktoolInterface(javaPath=config.APKTOOL_JAVA_PATH,
                               javaOpts=config.APKTOOL_JAVA_OPTS,
                               pathApktool=Libs.APKTOOL_PATH,
                               jarApktool=Libs.APKTOOL_PATH)
    package = get_apk_properties(apk_path).package
    unpacked_data_path = decompile_apk(apktool, apk_path, package, result_dir)
    manifest_path = get_path_to_manifest(unpacked_data_path)
    logging.info("decompiled {0}".format(package))

    instrument_manifest(manifest_path)
    smali_code_path = get_path_to_smali_code(unpacked_data_path)
    pickle_path = get_pickle_path(apk_path, result_dir)
    instrument_smali_code(smali_code_path, pickle_path, package, granularity,
                          dbg_start, dbg_end, mem_stats)
    logging.info("instrumented")

    instrumented_package_path = get_path_to_instrumented_package(
        apk_path, result_dir)
    remove_if_exits(instrumented_package_path)
    build_apk(apktool, unpacked_data_path, instrumented_package_path)
    Utils.rm_tree(unpacked_data_path)
    logging.info("built")

    instrumented_apk_path = get_path_to_insrumented_apk(
        instrumented_package_path, result_dir)
    sign_align_apk(instrumented_package_path, instrumented_apk_path)

    logging.info("apk instrumented: {0}".format(instrumented_apk_path))
    logging.info("package name: {0}".format(package))
    if installation:
        install(instrumented_apk_path)
    return (package, instrumented_apk_path, pickle_path)
Esempio n. 6
0
 def save_instrumented_smali(self, output_dir, instrument=True):
     '''Saves instrumented smali to the specified directory/'''
     print("saving instrumented smali:  %s..." % output_dir)
     if os.path.exists(output_dir):
         shutil.rmtree(output_dir)
     os.makedirs(output_dir)
     classes_info = []
     class_number = 0  # to make array name unique
     # Helps to find specific method that cased a fail after the instrumentation.
     # See '# Debug purposes' below
     method_number = 0
     # dbg_ means specific part of the code defined by dbg_start-dbg_end
     # numbers will be instrumented
     dbg_instrument = instrument
     for class_ in self.smalitree.classes:
         class_path = os.path.join(output_dir, class_.folder,
                                   class_.file_name)
         code, cover_index, method_number, is_instrumented = self.instrument_class(
             class_,
             class_number,
             method_number=method_number,
             instrument=dbg_instrument,
             dbg_start=self.dbg_start,
             dbg_end=self.dbg_end)
         if dbg_instrument and is_instrumented:
             classes_info.append((class_.name, cover_index, class_number))
             class_number += 1
         self.save_class(class_path, code)
         if self.dbg and dbg_instrument and method_number > self.dbg_end:  # Now leave other code not instrumented.
             dbg_instrument = False
     if self.dbg:
         print("Number of methods instrumented: {0}-{1} from {2}".format(
             self.dbg_start, self.dbg_end, method_number))
     if instrument:
         self.generate_reporter_class(classes_info, output_dir)
         if self.mem_stats:
             self.save_reporter_array_stats(classes_info)
         Utils.copytree(self.instrumentation_smali_path, output_dir)
Esempio n. 7
0
def save_coverage(tree, templates, output_dir, app_name, granularity):
    groups = Utils2.get_groupped_classes(tree)
    init_row = templates['init_row.pt']
    init_table = templates['init_table.pt']
    index_template = templates['index.pt']

    rows = []
    total_coverage_data = CoverageData()
    for g in groups:
        (package, path,
         coverage_data) = save_package_indexhtml(g, templates, output_dir,
                                                 app_name, granularity)
        coverage = coverage_data.get_formatted_coverage(granularity)
        row = init_row(
            elementlink=path,
            type='package',
            elementname=package,
            coverage=coverage,
            respath='',
            coverage_data=coverage_data,
            is_instruction_level=Granularity.is_instruction(granularity),
            progress_covered=coverage_data.covered(granularity),
            progress_missed=coverage_data.missed(granularity))
        rows.append(Markup(row))
        total_coverage_data.add_data(coverage_data)
    total_coverage = total_coverage_data.get_formatted_coverage(granularity)
    table = init_table(
        rows=Markup("\n".join(rows)),
        total_coverage=total_coverage,
        total_coverage_data=total_coverage_data,
        is_instruction_level=Granularity.is_instruction(granularity),
        progress_covered=total_coverage_data.covered(granularity),
        progress_all=total_coverage_data.coverable(granularity))
    root_path = ''
    html = index_template(table=Markup(table),
                          appname=app_name,
                          title=app_name,
                          package=None,
                          respath=root_path,
                          file_name=None,
                          granularity=Granularity.get(granularity))
    path = os.path.join(output_dir, 'index.html')
    with open(path, 'w') as f:
        f.write(html)
Esempio n. 8
0
    def get_instrumented_insns_and_labels(self,
                                          method,
                                          reg_map,
                                          regs,
                                          cover_index,
                                          instrument=True):
        lines = []
        block_move_insn = False
        labels = method.labels.values()
        labels_search = LabelReversedLoopSearch(labels)
        # The last insn is always goto, return or throw. We dont track them.
        last_insn_index = len(method.insns) - 1
        labels = labels_search.find_reversed_by_index(last_insn_index + 1)
        if labels:
            insns, cover_index = self.get_instrumented_labels(
                labels, regs, cover_index, instrument
                and Granularity.is_instruction(self.granularity))
            lines[0:0] = insns
        goto_hack_i = 0
        throw_safe_indexes = []
        if method.synchronized:
            throw_safe_indexes = Utils.scan_synchronized_tries(method)
        # we start reading the instructions from the end of the method in reversed loop
        for i in range(last_insn_index, -1, -1):
            insns = []
            if instrument:
                line = self.get_insn_change_registers(method.insns[i], reg_map)
            else:
                line = method.insns[i].get_line()
            is_throw_safe = Utils.is_in_ranges(i, throw_safe_indexes)
            # dont track 'return*'insns
            if instrument and Granularity.is_instruction(self.granularity) and \
                not block_move_insn and \
                not method.insns[i].buf.startswith('return') and \
                not method.insns[i].buf.startswith('goto') and \
                not method.insns[i].buf.startswith('throw'):
                safe_insns, throwable_insns = self.get_throw_safe_tracking(
                    line, regs, cover_index, goto_hack_i)
                lines[0:0] = safe_insns
                lines.extend(throwable_insns)
                if len(throwable_insns) > 0:
                    goto_hack_i += 1
                method.insns[i].cover_code = cover_index
                cover_index += 1
            lines.insert(0, line)
            # set this flag if instruction before current should not be instrumented
            block_move_insn = instrument and Granularity.is_instruction(self.granularity) and \
                self.not_instr_regex.match(method.insns[i].buf) is not None
            labels = labels_search.find_reversed_by_index(i)
            if labels:
                safe_insns, throwable_insns, cover_index = self.get_throw_safe_instr_labels(
                    labels, regs, cover_index, instrument and Granularity.is_instruction(self.granularity) and \
                    not block_move_insn, goto_hack_i)
                lines[0:0] = safe_insns
                lines.extend(throwable_insns)
                if len(throwable_insns) > 0:
                    goto_hack_i += 1
            # :try_end_x goes immediatly after monitor-enter
            if instrument and not block_move_insn and labels and method.insns[
                    i - 1].buf.startswith('monitor-enter') and any(
                        [any(l.tries) for l in labels]):
                block_move_insn = True
        #first tracking statement in the method
        if instrument:
            insns = self.get_tracking_insns(regs, cover_index)
            lines[0:0] = insns
            method.cover_code = cover_index
            cover_index += 1

        return (lines, cover_index)
Esempio n. 9
0
def save_class(cl, class_template, output_dir, app_name, granularity):
    dir = os.path.join(output_dir, cl.folder)
    if not os.path.exists(dir):
        os.makedirs(dir)
    class_path = os.path.join(dir, cl.file_name + '.html')
    buf = [LI_TAG(d) for d in cl.get_class_description()]
    buf.append(LI_TAG(''))
    buf.extend([LI_TAG(a) for a in cl.get_annotations()])
    buf.append(LI_TAG(''))
    buf.extend([LI_TAG(f) for f in cl.get_fields()])
    buf.append(LI_TAG(''))
    for m in cl.methods:
        ins_buf = []
        labels = m.labels.values()
        labels = sorted(labels, key=attrgetter('index'))
        for i in range(len(m.insns)):
            ins = m.insns[i]
            if ins.covered:
                ins_buf.append(span_tab_tag(ins.buf, COV_CLASS))
            else:
                if ins.buf.startswith("return"):
                    lbl = get_first_lbl_by_index(labels, i)
                    if lbl is not None:
                        if lbl.covered:
                            ins_buf.append(span_tab_tag(ins.buf, EXEC_CLASS))
                    else:
                        if m.insns[i - 1].covered:
                            ins_buf.append(span_tab_tag(ins.buf, EXEC_CLASS))
                else:
                    if i < len(m.insns) - 1 and m.insns[
                            i + 1].covered and not_instr_regex.match(
                                m.insns[i + 1].buf):
                        ins_buf.append(span_tab_tag(ins.buf, EXEC_CLASS))
                    else:
                        ins_buf.append(span_tab_tag(ins.buf))
        # insert labels and tries
        # sort the labels by index
        count = 0
        for l in labels:
            if l.covered:
                ins_buf.insert(l.index + count, span_tab_tag(l.buf, COV_CLASS))
            else:
                ins_buf.insert(l.index + count, span_tab_tag(l.buf))
            count += 1
            for t in l.tries:
                ins_buf.insert(l.index + count, span_tab_tag(t.buf))
                count += 1
            if l.switch:
                for sl in l.switch.buf:
                    ins_buf.insert(l.index + count, span_tab_tag(sl))
                    count += 1
            if l.array_data:
                for sl in l.array_data.buf:
                    ins_buf.insert(l.index + count, span_tab_tag(sl))
                    count += 1
        ins_buf.insert(0, LI_TAG(''))
        for a in m.annotations:
            a.reload()
            ins_buf[0:0] = [span_tab_tag(d) for d in a.buf]
        for p in reversed(m.parameters):
            p.reload()
            ins_buf[0:0] = [span_tab_tag(d) for d in p.buf]
        ins_buf.insert(0, span_tab_tag(m.get_registers_line()))
        html_method_line = span_tag(
            html_escape(m.get_method_line()),
            COV_CLASS) if m.called else m.get_method_line()
        ins_buf.insert(0, html_method_line)
        ins_buf.append(LI_TAG(".end method"))
        buf.append(LI_TAG(''))
        buf.extend(ins_buf)
    slash_num = cl.name.count('/')
    respath = ''
    for i in range(slash_num):
        respath += '../'
    html = class_template(code=Markup("\n".join(buf)),
                          appname=app_name,
                          title=cl.file_name,
                          package=Utils2.get_standart_package_name(cl.name),
                          respath=respath,
                          granularity=Granularity.get(granularity))
    with open(class_path, 'w') as f:
        f.write(html)