Hailong Yao

86 papers A* 15A 6C 2Journal 31Unranked 32
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Biao Liu, Chen Jiang, Qi Xu, Hailong Yao, Tsung-Yi Ho, Bo Yuan
2026 A* conf
AAAI
Zhiyang Chen, Hailong Yao, Xia Yin
2026 J jnl
CoRR
Zhiyang Chen, Hailong Yao, Xia Yin
2025 A* conf
DAC
Mingyang Kou, Weiqing Ji, Shouyi Yin, Hailong Yao
2025 A* conf
ICML
Zhiyang Chen, Hailong Yao, Xia Yin
2025 A* conf
DAC
Chengkai Wang, Weiqing Ji, Mingyang Kou, Zhiyang Chen, Fei Li, Nengyong Zhu, Hailong Yao
2025 C conf
ICCD
Mingyang Kou, Jun Zeng, Xinyu Peng, Weiqing Ji, Hailong Yao
2025 A* conf
DAC
Zhiyang Chen, Hailong Yao, Xia Yin
2025 conf
ACM Great Lakes Symposium on VLSI
Haochang Tian, Weiqing Ji, Mingyang Kou, Chengkai Wang, Fei Li, Hailong Yao
2024 J jnl
IEEE Trans. Biomed. Circuits Syst.
Weiqing Ji, Xingzhuo Guo, Shouan Pan, Fei Long, Tsung-Yi Ho, Ulf Schlichtmann, Hailong Yao
2024 J jnl
CoRR
Chengkai Wang, Weiqing Ji, Mingyang Kou, Zhiyang Chen, Fei Li, Hailong Yao
2024 conf
ICBBT
Kenglun Chang, Jintian Ge, Hailong Yao, Yin Xia
2023 conf
ASICON
Jun Zeng, Panfeng Wang, Haili Wang, Hailong Yao, Fuchun Sun
2023 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Chen Jiang, Rongquan Yang, Qi Xu, Hailong Yao, Tsung-Yi Ho, Bo Yuan
2023 conf
ACM Great Lakes Symposium on VLSI
Weiqing Ji, Hailong Yao, Tsung-Yi Ho, Ulf Schlichtmann, Xia Yin
2023 A conf
ICCAD
Zhiyang Chen, Tsung-Yi Ho, Ulf Schlichtmann, Datao Chen, Mingyu Liu, Hailong Yao, Xia Yin
2023 conf
ACM Great Lakes Symposium on VLSI
Weiqing Ji, Xingcheng Yao, Hailong Yao, Tsung-Yi Ho, Ulf Schlichtmann, Xia Yin
2023 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Mingyang Kou, Jiangyuan Gu, Hailong Yao, Shaojun Wei, Shouyi Yin
2022 conf
MICAD
Kenglun Chang, Yanyuet Man, Hailong Yao
2022 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Hui-Chieh Yu, Yu-Huei Lin, Zhiyang Chen, Bing Li, Xing Huang, Ulf Schlichtmann, Tsung-Yi Ho, Hailong Yao
2022 A* conf
DAC
Mingyang Kou, Jun Zeng, Boxiao Han, Fei Xu, Jiangyuan Gu, Hailong Yao
2022 A* conf
DAC
Weiqing Ji, Xingzhuo Guo, Shouan Pan, Tsung-Yi Ho, Ulf Schlichtmann, Hailong Yao
2022 conf
ACM Great Lakes Symposium on VLSI
Jun Zeng, Mingyang Kou, Hailong Yao
2022 A* conf
NeurIPS
Jun Zeng, Mingyang Kou, Hailong Yao
2021 conf
ACM Great Lakes Symposium on VLSI
Wei Zhang, Yongxiao Zhou, Tsung-Yi Ho, Hailong Yao
2021 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Chunfeng Liu, Xing Huang, Bing Li, Hailong Yao, Paul Pop, Tsung-Yi Ho, Ulf Schlichtmann
2021 conf
ACM Great Lakes Symposium on VLSI
Zhiyang Chen, Weiqing Ji, Yihao Peng, Datao Chen, Mingyu Liu, Hailong Yao
2021 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Mingyang Kou, Pei-Yi Cheng, Jun Zeng, Tsung-Yi Ho, Kazuyoshi Takagi, Hailong Yao
2020 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Qin Wang, Ulf Schlichtmann, Yici Cai, Weiqing Ji, Zeyan Li, Haena Cheong, Oh-Sun Kwon, Hailong Yao, Tsung-Yi Ho, Kwanwoo Shin, Bing Li
2020 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Lingxuan Shao, Wentai Li, Tsung-Yi Ho, Sudip Roy, Hailong Yao
2020 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Weiqing Ji, Tsung-Yi Ho, Junchao Wang, Hailong Yao
2020 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Ying Zhu, Xing Huang, Bing Li, Tsung-Yi Ho, Qin Wang, Hailong Yao, Robert Wille, Ulf Schlichtmann
2020 A* conf
DAC
Mingyang Kou, Jiangyuan Gu, Shaojun Wei, Hailong Yao, Shouyi Yin
2020 A* conf
DAC
Weiqing Ji, Tsung-Yi Ho, Hailong Yao
2020 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Jiayi Weng, Tsung-Yi Ho, Weiqing Ji, Peng Liu, Mengdi Bao, Hailong Yao
2019 conf
ICBBT
Yanyuet Man, Hailong Yao
2019 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Qinghang Zhao, Wenyu Sun, Jiaqing Zhao, Jian Zhao, Hailong Yao, Tsung-Yi Ho, Xiaojun Guo, Huazhong Yang, Yongpan Liu
2018 conf
ITC-Asia
Chun-Yu Lin, Juinn-Dar Huang, Hailong Yao, Tsung-Yi Ho
2018 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Kailin Yang, Hailong Yao, Tsung-Yi Ho, Kunze Xin, Yici Cai
2018 conf
ISVLSI
Weiqing Ji, Tsung-Yi Ho, Hailong Yao
2018 A conf
ICCAD
Ying Zhu, Bing Li, Tsung-Yi Ho, Qin Wang, Hailong Yao, Robert Wille, Ulf Schlichtmann
2018 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Qin Wang, Hao Zou, Hailong Yao, Tsung-Yi Ho, Robert Wille, Yici Cai
2018 J jnl
ACM Trans. Design Autom. Electr. Syst.
Hongxia Zhou, Chiu-Wing Sham, Hailong Yao
2017 conf
ASP-DAC
Andreas Grimmer, Qin Wang, Hailong Yao, Tsung-Yi Ho, Robert Wille
2017 A* conf
DAC
Qinghang Zhao, Yongpan Liu, Wenyu Sun, Jiaqing Zhao, Hailong Yao, Xiaojun Guo, Huazhong Yang
2017 conf
ASP-DAC
Qin Wang, Shiliang Zuo, Hailong Yao, Tsung-Yi Ho, Bing Li, Ulf Schlichtmann, Yici Cai
2017 conf
ACM Great Lakes Symposium on VLSI
Lingxuan Shao, Yibin Yang, Hailong Yao, Tsung-Yi Ho, Yici Cai
2017 J jnl
IEEE Trans. Biomed. Circuits Syst.
Qin Wang, Yue Xu, Shiliang Zuo, Hailong Yao, Tsung-Yi Ho, Bing Li, Ulf Schlichtmann, Yici Cai
2017 J jnl
CoRR
Chunfeng Liu, Bing Li, Hailong Yao, Paul Pop, Tsung-Yi Ho, Ulf Schlichtmann
2017 A* conf
DAC
Chunfeng Liu, Bing Li, Hailong Yao, Paul Pop, Tsung-Yi Ho, Ulf Schlichtmann
2016 A conf
ICCAD
Qin Wang, Zeyan Li, Haena Cheong, Oh-Sun Kwon, Hailong Yao, Tsung-Yi Ho, Kwanwoo Shin, Bing Li, Ulf Schlichtmann, Yici Cai
2016 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Hailong Yao, Qin Wang, Yiren Shen, Tsung-Yi Ho, Yici Cai
2016 conf
ASP-DAC
Qin Wang, Yizhong Ru, Hailong Yao, Tsung-Yi Ho, Yici Cai
2015 J jnl
IEEE Des. Test
Hailong Yao, Qin Wang, Yizhong Ru, Yici Cai, Tsung-Yi Ho
2015 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Yici Cai, Chao Deng, Qiang Zhou, Hailong Yao, Feifei Niu, Cliff N. Sze
2015 A* conf
DAC
Hailong Yao, Tsung-Yi Ho, Yici Cai
2015 J jnl
Integr.
Hailong Yao, Fan Yang, Yici Cai, Qiang Zhou, Chiu-Wing Sham
2015 conf
ISPD
Qin Wang, Weiran He, Hailong Yao, Tsung-Yi Ho, Yici Cai
2014 J jnl
Integr.
Wei Zhao, Hailong Yao, Yici Cai, Subarna Sinha, Charles C. Chiang
2014 J jnl
Microelectron. J.
Hailong Yao, Qiang Gao, Yici Cai, Qiang Zhou, Chiu-Wing Sham
2014 A* conf
DAC
Qin Wang, Yiren Shen, Hailong Yao, Tsung-Yi Ho, Yici Cai
2014 conf
ISVLSI
Hongxia Zhou, Chiu-Wing Sham, Hailong Yao
2013 conf
ASICON
Jinming Zhao, Hailong Yao, Yici Cai, Qiang Zhou
2013 conf
ASICON
Weijie Chen, Hailong Yao, Yici Cai, Qiang Zhou
2013 conf
ISQED
Zihao Chen, Hailong Yao, Yici Cai
2012 conf
ASP-DAC
Hailong Yao, Yici Cai, Qiang Gao
2011 conf
ISQED
Qiang Gao, Hailong Yao, Qiang Zhou, Yici Cai
2011 conf
ISQED
Zhongdong Qi, Qiang Zhou, Yanming Jia, Yici Cai, Zhuoyuan Li, Hailong Yao
2011 conf
ISVLSI
Shuzhe Zhou, Hailong Yao, Qiang Zhou, Yici Cai
2011 conf
ACM Great Lakes Symposium on VLSI
Feifei Niu, Qiang Zhou, Hailong Yao, Yici Cai, Jianlei Yang, Chin Ngai Sze
2011 conf
ACM Great Lakes Symposium on VLSI
Fan Yang, Hailong Yao, Qiang Zhou, Yici Cai
2010 A conf
ISLPED
Qiang Gao, Yin Shen, Yici Cai, Hailong Yao
2010 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Kwangok Jeong, Andrew B. Kahng, Chul-Hong Park, Hailong Yao
2010 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Andrew B. Kahng, Chul-Hong Park, Xu Xu, Hailong Yao
2009 conf
ISQED
Kwangok Jeong, Andrew B. Kahng, Hailong Yao
2008 A* conf
DAC
Kwangok Jeong, Andrew B. Kahng, Chul-Hong Park, Hailong Yao
2008 J jnl
IET Circuits Devices Syst.
Hailong Yao, Subarna Sinha, Jingyu Xu, Charles C. Chiang, Yici Cai, Xianlong Hong
2008 A conf
ICCAD
Andrew B. Kahng, Chul-Hong Park, Xu Xu, Hailong Yao
2007 conf
ISVLSI
Hailong Yao, Yici Cai, Xianlong Hong
2006 C conf
ISCAS
Hailong Yao, Yici Cai, Xianlong Hong
2006 conf
APCCAS
Xianlong Hong, Yici Cai, Hailong Yao, Duo Li
2006 A conf
ICCAD
Hailong Yao, Subarna Sinha, Charles C. Chiang, Xianlong Hong, Yici Cai
2006 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Hailong Yao, Yici Cai, Qiang Zhou, Xianlong Hong
2005 J jnl
J. Comput. Sci. Technol.
Hailong Yao, Yici Cai, Qiang Zhou, Xianlong Hong
2005 conf
ACM Great Lakes Symposium on VLSI
Hailong Yao, Yici Cai, Xianlong Hong, Qiang Zhou
2004 conf
ISCAS (5)
Hailong Yao, Qiang Zhou, Xianlong Hong, Yici Cai
redb/extractors/decompiler/bninja/analysis/low_level.py
← Index redb/extractors/decompiler/bninja/analysis/low_level.py python
import time

from binaryninja import (
    LowLevelILInstruction,
)
from binaryninja import (
    LowLevelILOperation as LLIL_OP,
)
from binaryninja.lowlevelil import (
    LowLevelILAdd,
    LowLevelILConst,
    LowLevelILConstPtr,
    LowLevelILLoad,
    LowLevelILLsl,
    LowLevelILMul,
    LowLevelILPop,
    LowLevelILPush,
    LowLevelILReg,
    LowLevelILStore,
    LowLevelILSub,
)

# Support both package and standalone imports
try:
    from ..function_type import FunctionTypeAnalysis
    from ..similarity.minhasher import MinHasher, TokenKind
    from ..utils.hashes import calculate_sha256, calculate_tlsh
    from .low_level_normalization import LowLevelNormalization

except ImportError:
    # Fallback to absolute imports (for multiprocessing spawned processes)
    from redb.extractors.decompiler.bninja.analysis.low_level_normalization import LowLevelNormalization
    from redb.extractors.decompiler.bninja.similarity.minhasher import MinHasher
    from redb.extractors.decompiler.bninja.function_type import FunctionTypeAnalysis
    from redb.extractors.decompiler.bninja.utils.hashes import calculate_sha256, calculate_tlsh

class LowLevelAnalysis:
    def __init__(self, function, bv, logger):
        self.function = function
        self.name = function.name
        self.start = function.start
        self.llil_func = function.llil
        self.bv = bv
        self.logger = logger
        self.errors = []

    def log_error(
        self, message, function_name, address, exception=None, error_location="unknown"
    ):
        """Log an error during processing."""
        error_msg = f"Error in function {function_name} at {address}: {message}"
        if exception:
            error_msg += f" - {str(exception)}"
        self.logger.error(error_msg)

        # Add to errors list
        error = {
            "function_name": function_name,
            "function_address": str(address),
            "error_location": error_location,
            "error_message": message,
            "error_details": str(exception) if exception else "",
            "error_type": type(exception).__name__ if exception else "Unknown",
            "timestamp": int(time.time() * 1000),
        }
        self.errors.append(error)

    def count_control_flow_instructions(self):
        if self.llil_func is None:
            return 0

        count = 0
        for basic_block in self.llil_func.basic_blocks:
            for ins in basic_block:
                op = ins.operation
                if op in (
                    LLIL_OP.LLIL_IF,
                    LLIL_OP.LLIL_GOTO,
                    LLIL_OP.LLIL_JUMP,
                    LLIL_OP.LLIL_JUMP_TO,
                    LLIL_OP.LLIL_CALL,
                    LLIL_OP.LLIL_CALL_SSA,
                ):
                    count += 1

        return count

    def collect_memory_patterns(self):
        """ """
        patterns = set()

        try:
            llil = self.llil_func
            arch = self.bv.arch
            sp_name = arch.stack_pointer if arch and arch.stack_pointer else "sp"

            def analyze_addr(addr_expr, might_be_direct):
                """
                Visit the expression for the address and understand whether it has a direct, scaled, base offset, etc.
                access to memory
                """
                found = {
                    "direct": False,
                    "scaled": False,
                    "base_off": False,
                    "stack": False,
                    "string": False,
                }

                def addr_cb(n):
                    # stack (SP/BP-like)
                    match n:
                        case LowLevelILReg(src=reg):
                            if reg == sp_name:
                                found["stack"] = True

                        case LowLevelILConst() | LowLevelILConstPtr():
                            if might_be_direct:
                                found["direct"] = True

                        # base +/- const
                        case (
                            LowLevelILAdd(left=l, right=r)
                            | LowLevelILSub(left=l, right=r)
                        ):
                            l_is_reg = isinstance(l, LowLevelILReg)
                            r_is_reg = isinstance(r, LowLevelILReg)
                            l_is_cst = isinstance(
                                l, (LowLevelILConst, LowLevelILConstPtr)
                            )
                            r_is_cst = isinstance(
                                r, (LowLevelILConst, LowLevelILConstPtr)
                            )
                            if (l_is_reg and r_is_cst) or (r_is_reg and l_is_cst):
                                found["base_off"] = True

                        # scaled index (index*scale) or shift (index << k)
                        case LowLevelILMul(left=l, right=r):
                            if (
                                isinstance(l, LowLevelILReg)
                                and isinstance(r, LowLevelILConst)
                            ) or (
                                isinstance(r, LowLevelILReg)
                                and isinstance(l, LowLevelILConst)
                            ):
                                found["scaled"] = True

                        case LowLevelILLsl(left, right):
                            if isinstance(left, LowLevelILReg) and isinstance(
                                right, LowLevelILConst
                            ):
                                found["scaled"] = True

                    return None

                _ = list(addr_expr.traverse(addr_cb))

                if found["direct"]:
                    patterns.add("MEM_DIRECT")
                if found["scaled"]:
                    patterns.add("MEM_SCALED_INDEX")
                if found["base_off"]:
                    patterns.add("MEM_BASE_OFFSET")
                if found["stack"]:
                    patterns.add("MEM_STACK")
                elif found["string"]:
                    patterns.add("MEM_STRING")

            def func_cb(i):
                match i:
                    case LowLevelILPush(src=addr):
                        analyze_addr(addr, False)
                    case LowLevelILPop(src=addr):
                        analyze_addr(addr, False)
                    case LowLevelILLoad(src=addr):
                        analyze_addr(addr, True)
                    case LowLevelILStore(dest=addr, src=_):
                        analyze_addr(addr, True)

                return None

            # complete visit for the single instruction
            _ = list(llil.traverse(func_cb))

            return sorted(patterns)

        except Exception as e:
            self.log_error(
                "Failed to collect memory patterns via LLIL.traverse",
                self.name,
                self.start,
                e,
                "collect_memory_patterns",
            )
            return []

    def collect_register_usage(self):
        """
        Collect frequencies for register usage
        """
        try:
            llil = self.llil_func

            register_usage = {}

            def inc(reg, kind):
                if reg is None:
                    return
                entry = register_usage.setdefault(reg, {"reads": 0, "writes": 0})
                entry[kind] += 1

            if not llil:
                return {}, 0, 0

            for top_il in llil.instructions:
                registers_read = self.function.get_regs_read_by(
                    top_il.address, self.bv.arch
                )
                registers_write = self.function.get_regs_written_by(
                    top_il.address, self.bv.arch
                )

                for reg_read in registers_read:
                    inc(reg_read, "reads")

                for reg_write in registers_write:
                    inc(reg_write, "writes")

            total_reads = sum(entry["reads"] for entry in register_usage.values())
            total_writes = sum(entry["writes"] for entry in register_usage.values())

            return register_usage, total_reads, total_writes

        except Exception as e:
            self.log_error(
                "Failed to collect register usage via LLIL.traverse",
                self.name,
                self.start,
                e,
                "collect_register_usage",
            )
            return {}, 0, 0

    def _classify_address(self, bv, addr):
        """
        Classification of the address
        """
        info = {
            "address": addr,
            "section": None,
            "segment_writable": None,
            "symbol": None,
            "kind": None,  # "string", "function_ptr", "data_var", "symbol", "unknown"
            "datatype": None,  # es. "char *", "int32_t", "my_struct", ...
            "note": None,
        }

        # section / segment
        sec = bv.get_section_at(addr)
        seg = bv.get_segment_at(addr)
        if sec:
            info["section"] = sec.name
        if seg:
            info["segment_writable"] = bool(seg.writable)

        sym = bv.get_symbol_at(addr)
        if sym:
            info["symbol"] = sym.full_name

        # function pointer
        try:
            fns = list(bv.get_functions_at(addr))
        except Exception:
            # some versions have get_function_at(addr) that returns a single object or None
            fns = [bv.get_function_at(addr)] if hasattr(bv, "get_function_at") else []
        fns = [f for f in fns if f]
        if fns:
            info["kind"] = "function_ptr"
            info["datatype"] = "func"
            info["note"] = f"points to function {fns[0].name}"
            return info

        # string
        sref = bv.get_string_at(addr)
        if sref:
            info["kind"] = "string"
            # sref.type:
            info["datatype"] = (
                getattr(sref, "type", None).__class__.__name__
                if hasattr(sref, "type")
                else "string"
            )
            return info

        # data typed variable
        dv = bv.get_data_var_at(addr)
        if dv:
            info["kind"] = "data_var"
            info["datatype"] = str(dv.type) if getattr(dv, "type", None) else None
            if getattr(dv, "name", None):
                info["symbol"] = dv.name if not info["symbol"] else info["symbol"]
            return info

        # only symbol (no data var)
        if sym and not info["kind"]:
            info["kind"] = "symbol"
            return info

        # unknown
        info["kind"] = "unknown"
        return info

    def count_data_references(self):
        """Count the number of data references in a function using LLIL."""
        count = 0

        if self.llil_func is None:
            return 0

        try:
            # Iterate LLIL basic blocks and instructions
            for instr in self.llil_func.instructions:
                instr_str = str(instr)
                logged = False
                src = None

                # Check for constant dereferencing or symbolic refs
                if hasattr(instr, "src"):
                    src = instr.src
                    if isinstance(src, (LowLevelILConstPtr, LowLevelILConst)):
                        count += 1
                        logged = True

                if not logged and "_" in instr_str:
                    count += 1

                # If src is a pointer constant, check if it lands in a writable data segment
                if src is not None and isinstance(src, LowLevelILConstPtr):
                    addr = src.constant
                    segment = self.bv.get_segment_at(addr)
                    if segment and segment.writable:
                        count += 1

        except Exception as e:
            self.logger.warning(
                f"Failed to use LLIL for counting data references in "
                f"{self.name} at {self.start}: {e}"
            )
        return count

    def compute_num_calls(self):
        c = 0

        if not self.llil_func:
            return 0

        for instr in self.llil_func.instructions:
            if instr.operation in (LLIL_OP.LLIL_CALL, LLIL_OP.LLIL_TAILCALL):
                c += 1
        return c

    def compute_max_block_size(self):
        """Compute the maximum basic block size in a function."""
        if self.llil_func is None:
            return 0

        max_size = 0
        for block in self.llil_func.basic_blocks:
            try:
                # Count instructions in this block using the direct length approach
                # This avoids UTF-8 decoding issues entirely
                block_size = block.instruction_count
                max_size = max(max_size, block_size)
            except Exception as e:
                self.log_error(
                    f"[HandledError] computing max block size: {e}",
                    self.name,
                    self.start,
                    e,
                    "compute_max_block_size",
                )
        return max_size

    def estimate_stack_size(self):
        """Estimate the stack size used by a function."""
        try:
            # Binary Ninja provides a stack adjustment value for functions
            # Need to convert OffsetWithConfidence to a plain integer
            stack_adjust = self.function.stack_adjustment
            if hasattr(stack_adjust, "value"):  # Handle OffsetWithConfidence objects
                return stack_adjust.value
            return stack_adjust
        except Exception as e:
            self.log_error(
                "Failed to estimate stack size",
                self.name,
                self.start,
                e,
                "estimate_stack_size",
            )
            return -1

    def collect_instruction_types(self):
        def iter_llil_tree(root_il):
            stack = [root_il]
            while stack:
                il_single_op = stack.pop()
                if not isinstance(il_single_op, LowLevelILInstruction):
                    continue
                yield il_single_op
                for il_operand in il_single_op.operands:
                    if isinstance(il_operand, LowLevelILInstruction):
                        stack.append(il_operand)
                    elif isinstance(il_operand, (list, tuple)):
                        for sub in il_operand:
                            if isinstance(sub, LowLevelILInstruction):
                                stack.append(sub)

        type_frequencies = {}
        try:
            if self.llil_func is None:
                return type_frequencies

            il_func = self.llil_func

            for top_il in il_func.instructions:
                for il in iter_llil_tree(top_il):
                    op = getattr(il, "operation", None)
                    if op is None:
                        continue

                    category = str(op)

                    if category in type_frequencies:
                        type_frequencies[category] += 1
                    else:
                        type_frequencies[category] = 1

        except Exception as e:
            self.log_error(
                "Failed to collect LLIL instruction types",
               self.name,
                self.start,
                e,
                "collect_instruction_types_llil",
            )

        return type_frequencies

    def _collect_low_level_with_type(self):
        llil = self.llil_func
        if not llil:
            return [], []

        start = self.start

        low_level = LowLevelNormalization()

        instrs_with_addr = []

        for il in llil.instructions:
            norm = low_level.normalize_instr_with_operands(il)

            # Clamp negative offsets to 0 for UInt32 compatibility.
            # Negative offsets (instruction before function start) may occur with
            # overlapping functions or tail-calls in obfuscated/malware binaries.
            # Multiple instructions at offset 0 indicates this anomaly and can be
            # queried to identify such samples easily than by checking logs.
            # Triggered by 590ecad54cd9e1c8681509420ad56edde8b064ffbf884ce6cd8dd28eebb95ae1
            offset = il.address - start
            if offset < 0:
                offset = 0

            instrs_with_addr.append((offset, norm))

        return instrs_with_addr

    def _collect_low_level_and_with_addr(self):
        llil = self.llil_func
        if not llil:
            return [], []

        start = self.start

        low_level = LowLevelNormalization()

        instrs = []
        instrs_with_addr = []

        for il in llil.instructions:
            norm = low_level.normalize_instruction_all_levels(il)

            instrs.append(norm)

            # Clamp negative offsets to 0 for UInt32 compatibility.
            # Negative offsets (instruction before function start) may occur with
            # overlapping functions or tail-calls in obfuscated/malware binaries.
            # Multiple instructions at offset 0 indicates this anomaly and can be
            # queried to identify such samples easily than by checking logs.
            # Triggered by 590ecad54cd9e1c8681509420ad56edde8b064ffbf884ce6cd8dd28eebb95ae1
            offset = il.address - start
            if offset < 0:
                offset = 0

            instrs_with_addr.append((offset, norm))

        return instrs, instrs_with_addr


    def analyze(self):
        registers_uses, total_reads, total_written = self.collect_register_usage()
        instr_low_level, body_llil_vector = self._collect_low_level_and_with_addr()
        instr_low_level_str = str(instr_low_level)
        instructions_low_level = calculate_sha256(instr_low_level_str)
        instructions_low_level_tlsh = calculate_tlsh(instr_low_level_str)

        instr_typed_llil = self._collect_low_level_with_type()
        instr_typed_low_level_str = str(instr_typed_llil)
        instructions_typed_low_level = calculate_sha256(instr_typed_low_level_str)
        instructions_typed_low_level_tlsh = calculate_tlsh(instr_typed_low_level_str)

        seed = 0xdeadbeef
        minhash_llil_skeleton = MinHasher(seed, self.llil_func, TokenKind.LLIL).calculateMinHash()
        minhash_llil_typed = MinHasher(seed, self.llil_func, TokenKind.TYPED_LLIL).calculateMinHash()

        low_level_json = {
            "function_address": self.start,
            "function_type": FunctionTypeAnalysis(self.function)
            .get_function_type()
            .name,
            "body_llil_vector": body_llil_vector,
            "sha256_llil": instructions_low_level,
            "tlsh_llil": instructions_low_level_tlsh,
            "minhash_llil_skeleton": minhash_llil_skeleton,
            "instructions_types_llil": list(self.collect_instruction_types()),
            "instruction_typed_llil": instructions_typed_low_level,
            "tlsh_instruction_typed_llil": instructions_typed_low_level_tlsh,
            "minhash_llil_typed": minhash_llil_typed,
            "control_flow_count_llil": self.count_control_flow_instructions(),
            "memory_access_pattern_llil": self.collect_memory_patterns(),
            "register_usage": registers_uses,
            "total_reg_reads": total_reads,
            "total_reg_written": total_written,
            "data_references_count": self.count_data_references(),
            "max_block_size": self.compute_max_block_size(),
            "num_calls": self.compute_num_calls(),
            "stack_size": self.estimate_stack_size(),
        }

        return low_level_json, self.errors