Xiang Chen

121 papers A* 1B 1C 21Journal 49Unranked 49
YearRankTypeTitle / Venue / Authors
2025 J jnl
IEEE Trans. Ind. Electron.
Tianqun Ren, Baorui Wang, Guoxiang Gu, Xiang Chen
2025 conf
CDC
Jiapeng Xu, Guanrong Chen, Xiang Chen, Kemin Zhou
2025 J jnl
J. Frankl. Inst.
Xiang Chen, Xiaogang Wang, Fei Liu
2025 J jnl
IEEE Trans. Autom. Control.
Jiapeng Xu, Xiang Chen, Ying Tan, Kemin Zhou
2025 C conf
ACC
Zike Lei, Xi Chen, Xiang Chen, Ying Tan
2024 J jnl
IEEE Trans. Autom. Control.
Jiapeng Xu, Guoxiang Gu, Xiang Chen
2024 J jnl
IEEE Trans. Autom. Control.
Zhongkui Li, Junjie Jiao, Xiang Chen
2024 J jnl
IEEE Trans. Autom. Control.
Jiapeng Xu, Xiang Chen, Ying Tan, Guoxiang Gu
2024 J jnl
Unmanned Syst.
Tong Zhang, Ying Tan, Xiang Chen, Guoxiang Gu
2023 conf
CCTA
Farsam Farzadpour, Tong Zhang, Xiang Chen
2023 J jnl
IEEE Trans. Ind. Electron.
Yu Feng, Kaiwei Dai, Xiang Chen
2023 conf
AIM
Farsam Farzadpour, Tong Zhang, Xiang Chen
2023 J jnl
CoRR
Jiapeng Xu, Xiang Chen, Ying Tan, Kemin Zhou
2023 J jnl
IEEE Trans. Ind. Electron.
Zike Lei, Xi Chen, Ying Tan, Xiang Chen, Li Chai
2023 J jnl
IEEE Trans. Ind. Electron.
Kun Bai, Yaowu Ding, Zixin Que, Han Yan, Xiang Chen, Shengxiong Wen, Kok-Meng Lee
2023 J jnl
IEEE Control. Syst. Lett.
Jiapeng Xu, Xiang Chen, Ying Tan, Wulin Zou
2023 C conf
ACC
Jiapeng Xu, Ying Tan, Xiang Chen
2023 J jnl
CoRR
Jiapeng Xu, Ying Tan, Xiang Chen
2023 J jnl
IEEE Trans. Control. Syst. Technol.
Xiaoli Li, Ying Tan, Jie Tang, Xiang Chen
2022 J jnl
IEEE Trans. Ind. Electron.
Tianyi He, Xiang Chen, Guoming G. Zhu
2022 J jnl
CoRR
Zhongkui Li, Junjie Jiao, Xiang Chen
2022 conf
ICARM
Wulin Zou, Xiang Chen, Shilei Li, Pu Duan, Ningbo Yu, Ling Shi
2022 J jnl
CoRR
Zike Lei, Xi Chen, Ying Tan, Xiang Chen, Li Chai
2022 J jnl
IEEE Trans. Autom. Control.
Yu Feng, Ying Tan, Guoxiang Gu, Xiang Chen
2022 J jnl
CoRR
Zhicheng Zhang, Zhiqiang Zuo, Xiang Chen, Ying Tan, Yijing Wang
2021 C conf
ACC
Tong Zhang, Ying Tan, Xiang Chen
2021 J jnl
IEEE Trans. Autom. Control.
Ji-Lie Zhang, Xiang Chen, Guoxiang Gu
2020 J jnl
IEEE Trans. Ind. Electron.
Xuetao Zhang, Yongchun Fang, Xuebo Zhang, Jingqi Jiang, Xiang Chen
2020 conf
AIM
Zixuan Huo, Shilong Dai, Mingxing Yuan, Xiang Chen, Xuebo Zhang
2020 C conf
ACC
Tianyi He, Guoming G. Zhu, Xiang Chen
2020 conf
CDC
Yu Feng, Xiang Chen, Ying Tan
2020 conf
CDC
Zhiyang Ju, Ying Tan, Hui Zhang, Xiang Chen
2020 J jnl
SIAM J. Control. Optim.
Yu Feng, Zhuoming Chen, Xiang Chen
2020 J jnl
IEEE Trans. Ind. Informatics
Xuetao Zhang, Yongchun Fang, Xuebo Zhang, Jingqi Jiang, Xiang Chen
2020 conf
AIM
Zike Lei, Xiang Chen, Xi Chen, Li Chai
2020 J jnl
CoRR
Zike Lei, Xi Chen, Xiang Chen, Li Chai
2020 J jnl
IEEE Trans. Autom. Control.
Yu Feng, Xuanhe Nie, Xiang Chen
2020 conf
AIM
Mahdi Hassan, Dikai Liu, Xiang Chen
2019 C conf
INDIN
Lei Feng, Xi Chen, Xiang Chen
2019 J jnl
Int. J. Intell. Robotics Appl.
Xuebo Zhang, Boyu Zhang, Xiang Chen, Yongchun Fang
2019 conf
AIM
Haiming Gao, Xuebo Zhang, Chenping Li, Xinwei Chen, Yongchun Fang, Xiang Chen
2019 J jnl
IEEE Trans. Autom. Control.
JianMing Zhou, Guoxiang Gu, Xiang Chen
2019 conf
AIM
Xuetao Zhang, Jingqi Jiang, Yongchun Fang, Xuebo Zhang, Xiang Chen
2019 conf
ICCA
Yonghong Tan, Qingmei Cao, Ruili Dong, Qingyuan Tan, Xiang Chen
2019 conf
ASCC
Wanglei Cheng, Yonghong Tan, Yuhua Lu, Ruili Dong, Qingyuan Tan, Xiang Chen
2019 conf
CDC
Xiang Chen, Kemin Zhou, Ying Tan
2018 J jnl
SIAM J. Control. Optim.
Fei Yan, Guoxiang Gu, Xiang Chen
2018 C conf
ACC
Xiaoli Li, Ying Tan, Iven Mareels, Xiang Chen
2018 conf
ICCA
Rui Xu, Xi Chen, Li Chai, Xiang Chen
2018 conf
AIM
Boyu Zhang, Xuebo Zhang, Xiang Chen, Yongchun Fang
2018 conf
AIM
Farsam Farzadpour, Philip Church, Xiang Chen
2018 conf
CDC
Yu Feng, Xuanhe Nie, Xiang Chen
2018 J jnl
SIAM J. Control. Optim.
Yu Feng, Xiang Chen, Guoxiang Gu
2018 J jnl
Autom.
Yu Feng, Xiang Chen, Guoxiang Gu
2017 C conf
ACC
JianMing Zhou, Guoxiang Gu, Xiang Chen
2017 J jnl
Int. J. Intell. Robotics Appl.
Xuebo Zhang, Congyuan Wang, Yongchun Fang, Han Lu, Xiang Chen
2017 J jnl
Int. J. Intell. Robotics Appl.
Xiang Chen, Mathieu Grossard, Naoyuki Kubota, Dirk Wollherr, Simon X. Yang, Song Zhang
2017 conf
AIM
Farsam Farzadpour, Xuebo Zhang, Xiang Chen, Tong Zhang
2017 J jnl
IEEE Trans. Autom. Control.
Yu Feng, Xiang Chen, Guoxiang Gu
2017 conf
ICCA
Huan Li, Guoming G. Zhu, Ying Huang, Xiang Chen
2017 conf
ICCA
Qingyuan Tan, Hongli Gao, Xiang Chen, Ming Zheng
2016 conf
AIM
Boyu Zhang, Xuebo Zhang, Xiang Chen, Yongchun Fang
2016 C conf
ACC
Yonghong Tan, Yanyan Li, Ruili Dong, Xiang Chen, Hong He
2016 J jnl
SIAM J. Control. Optim.
Luis D. Alvergue, Abhishek Pandey, Guoxiang Gu, Xiang Chen
2016 C conf
ACC
Fei Yan, Guoxiang Gu, Xiang Chen
2016 conf
CDC
Yu Feng, Xiang Chen, Guoxiang Gu
2016 conf
ICCA
Yonghong Tan, Ruili Dong, Yanyan Li, Xiang Chen, Hong He
2016 J jnl
SIAM J. Control. Optim.
Yu Feng, Xiang Chen, Guoxiang Gu
2016 C conf
ICARCV
Junsheng Chen, Farsam Farzadpour, Xiang Chen, Yonghong Tan
2016 conf
ICCA
Ji-Lie Zhang, Guoxiang Gu, Xiang Chen
2015 conf
AIM
Xuebo Zhang, Jose Luis Alarcon Herrera, Xiang Chen
2015 conf
CDC
Xuebo Zhang, Xiang Chen, Xiao Liang, Yongchun Fang
2015 C conf
ACC
Prasad Divekar, Qingyuan Tan, Ying Tan, Xiang Chen, Ming Zheng
2015 conf
ASCC
Xiang Chen, Yu Feng, Guoxiang Gu
2015 C conf
ACC
Guoming Zhu, Junmin Wang, Zongxuan Sun, Xiang Chen
2014 J jnl
J. Control. Decis.
Guoxiang Gu, Fei Liu, Xiang Chen
2014 J jnl
ACM Trans. Sens. Networks
Aaron Mavrinac, Xiang Chen, Yonghong Tan
2014 C conf
ISCAS
Jose Luis Alarcon Herrera, Xiang Chen
2014 J jnl
IEEE Trans. Ind. Electron.
Danny Grignion, Xiang Chen, Narayan Kar, Huijie Qian
2014 C conf
ACC
Qingyuan Tan, Prasad Divekar, Xiang Chen, Ming Zheng, Yonghong Tan
2014 C conf
ACC
Yu Feng, Xiang Chen, Guoxiang Gu
2014 A* conf
ICRA
Jose Luis Alarcon Herrera, Xiang Chen, Xuebo Zhang
2013 J jnl
Int. J. Comput. Vis.
Aaron Mavrinac, Xiang Chen
2013 conf
CDC
Xiang Chen, Guoxiang Gu, Li Qiu, Yu Feng
2013 conf
CDC
Luis Alvergue, Abhishek Pandey, Guoxiang Gu, Xiang Chen
2013 C conf
ACC
Yu Feng, Xiang Chen, Guoxiang Gu
2013 conf
CDC
Yu Feng, Xiang Chen, Guoxiang Gu
2013 conf
ASCC
Yu Feng, Xiang Chen, Guoxiang Gu
2012 conf
ICIRA (3)
Karam Shaya, Aaron Mavrinac, Jose Luis Alarcon Herrera, Xiang Chen
2012 conf
ICIRA (1)
Jose Luis Alarcon Herrera, Xiang Chen
2012 conf
CDC
Fei Liu, Guoxiang Gu, Xiang Chen
2012 C conf
CCA
Huijie Qian, Danny Grignion, Xiang Chen, Narayan Kar
2012 conf
ICDSC
Jose Luis Alarcon Herrera, Xiang Chen
2012 conf
ROCOND
Danny Grignion, Xiang Chen, Yonghong Tan, Huijie Qian, Narayan Kar
2011 conf
ICDSC
Aaron Mavrinac, Xiang Chen
2011 conf
ICCA
Ali Kebarighotbi, Xiang Chen
2010 conf
ICDSC
Aaron Mavrinac, Jose Luis Alarcon Herrera, Xiang Chen
2010 J jnl
Comput. Vis. Image Underst.
Aaron Mavrinac, Xiang Chen, Kemal Ertugrul Tepe
2010 conf
CDC
Ali Tahmasebi, Xiang Chen
2010 conf
ICIRA (1)
Aaron Mavrinac, Jose Luis Alarcon Herrera, Xiang Chen
2009 J jnl
Int. J. Control
Guofeng Zhang, Xiang Chen, Tongwen Chen
2009 conf
EIT
Smitha Cholakkal, Xiang Chen
2009 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Tiebao Yang, Xiang Chen
2009 conf
CCA/ISIC
Jean Kor, Xiang Chen, Henry Hu
2008 J jnl
IEEE Trans. Control. Syst. Technol.
Xiang Chen, Tiebao Yang, Xiaoqun Chen, Kemin Zhou
2008 J jnl
J. Intell. Manuf.
Tiebao Yang, Xiang Chen, Henry Hu, Yeou-li Chu, Patrick Cheng
2008 B conf
FUZZ-IEEE
Aaron Mavrinac, Ahmad Shawky, Xiang Chen
2008 conf
ICDSC
Aaron Mavrinac, Xiang Chen, Kemal Ertugrul Tepe
2008 conf
CDC
Tiebao Yang, Xiang Chen
2008 J jnl
Simul.
Xiang Chen, Meranda Salem, Tuhin Das, Xiaoqun Chen
2008 C conf
ICARCV
Tiebao Yang, Chun-Yi Su, Xiang Chen, Henry Hu
2007 conf
ISIC
Tiebao Yang, Xiang Chen, Henry Hu
2007 conf
CDC
Guofeng Zhang, Xiang Chen, Tongwen Chen
2007 J jnl
SIAM J. Control. Optim.
Guofeng Zhang, Tongwen Chen, Xiang Chen
2007 conf
CDC
Guofeng Zhang, Xiang Chen, Tongwen Chen
2007 J jnl
Int. J. Manuf. Res.
Tiebao Yang, Henry Hu, Xiang Chen, Yeou-li Chu, Patrick Cheng
2006 C conf
ACC
Tiebao Yang, Xiang Chen, Henry Hu
2005 C conf
CCA
Xiang Chen, Xiaoqun Chen, Kemin Zhou
2002 C conf
ACC
Xiang Chen, Guoxiang Gu, Kemin Zhou
2001 J jnl
SIAM J. Control. Optim.
Xiang Chen, Kemin Zhou
1998 J jnl
Autom.
Xiang Chen, Guoxiang Gu, Phillip Martin, Kemin Zhou
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