Xiaohong Shen

90 papers C 1Misc 1Journal 57Unranked 31
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Wirel. Commun.
Xiangxiang Li, Haiyan Wang, Yao Ge, Xiaohong Shen, Yong Liang Guan, Miaowen Wen, Chau Yuen
2026 J jnl
IEEE Trans. Cogn. Commun. Netw.
Gaoyue Ma, Xiaohong Shen, Yuwen Yan, Haiyang Yao, Haiyan Wang
2026 J jnl
IEEE Trans. Mob. Comput.
Yifan Yuan, Xiaohong Shen, Lin Sun, Yongsheng Yan, Shilei Ma, Haiyan Wang
2026 J jnl
IEEE Internet Things J.
Lin Sun, Xiaohong Shen, Yuan Liu, Yifan Yuan, Weiliang Xie, Haiyan Wang
2026 J jnl
IEEE Internet Things J.
Ruiqin Zhao, Weiliang Xie, Xiaohong Shen, Chao Wang, Haiyan Wang
2025 J jnl
Pattern Recognit.
Zhongda Zhao, Haiyan Wang, Tao Lei, Xuan Wang, Xiaohong Shen, Haiyang Yao
2025 J jnl
IEEE Internet Things J.
Weiliang Xie, Xiaohong Shen, Lin Sun, Chao Wang, Yongsheng Yan, Haiyan Wang
2025 J jnl
Commun. Nonlinear Sci. Numer. Simul.
Bo Geng, Haiyan Wang, Yongsheng Yan, Xiaohong Shen
2024 conf
ICSPCC
Shuji Zhou, Haiyan Wang, Xiaohong Shen
2024 conf
ICSPCC
Han-Qiang Chen, Xiaohong Shen, Zhongda Zhao, Yongsheng Yan
2024 J jnl
IEEE Internet Things J.
Yuan Liu, Haiyan Wang, Lin Cai, Junhao Hu, Xiaohong Shen
2024 J jnl
CoRR
Xiangxiang Li, Haiyan Wang, Yao Ge, Xiaohong Shen, Jiarui Zhao
2024 J jnl
IEEE Wirel. Commun. Lett.
Xiangxiang Li, Haiyan Wang, Yao Ge, Xiaohong Shen, Jiarui Zhao
2024 conf
ICSPCC
Jiwan Wang, Ke He, Hasqimeg Ordoqin, Haiyan Wang, Xiaohong Shen
2024 conf
ICSPCC
Xin Fa, Haiyan Wang, Xiaohong Shen, Feifei Pang
2024 J jnl
Telecommun. Syst.
Tianyi Jia, Chang Gao, Xiaohong Shen, Hongwei Liu
2023 conf
ICSPCC
Zhe Jiang, Xiaohong Shen, Junbo Zhang, Haiyan Wang
2023 conf
ICSPCC
Wei Lian, Xiaohong Shen, Jian Suo, Haiyan Wang, Ke He
2023 J jnl
Phys. Commun.
Yuzhi Zhang, Jiazheng Chang, Yang Liu, Liuyi Xing, Xiaohong Shen
2023 conf
ICSPCC
Bingbing Zheng, Zhe Jiang, Xiaohong Shen
2023 conf
ICSPCC
Yang Li, Haiyan Wang, Yong Wang, Kan Qin, Xiaohong Shen
2023 conf
ICSPCC
Yuyuan Song, Xiaohong Shen, Kan Qin, Haiyan Wang, Haiyang Yao
2023 J jnl
IEEE Signal Process. Lett.
Hongwei Zhang, Haiyan Wang, Xuanming Liang, Yong-Sheng Yan, Xiaohong Shen
2022 conf
ICSPCC
Qinzheng Zhang, Haiyan Wang, Yongsheng Yan, Xiaohong Shen, Ke He
2022 conf
ICSPCC
Yifan Yuan, Xiaohong Shen, Yong Wang, Lin Sun, Shilei Ma
2022 J jnl
IEEE Trans. Instrum. Meas.
Yafen Dong, Xiaohong Shen, Haiyan Wang
2022 conf
ICSPCC
Gaoyue Ma, Xiaohong Shen, Haiyan Wang, Shilei Ma
2022 conf
ICSPCC
Yuzhi Zhang, Jiazheng Chang, Yang Liu, Xiaohong Shen, Weigang Bai
2022 J jnl
Remote. Sens.
Yuzhi Zhang, Jingru Zhu, Haiyan Wang, Xiaohong Shen, Bin Wang, Yuan Dong
2022 conf
ICCC Workshops
Xiangxiang Li, Haiyan Wang, Xiaohong Shen, Yao Ge, Yuanyuan Lei
2022 J jnl
CoRR
Xiangxiang Li, Haiyan Wang, Yao Ge, Xiaohong Shen, Yuanyuan Lei
2022 conf
SAM
Xuandi Sun, Haiyan Wang, Xiaohong Shen, Fei Hua
2022 J jnl
Digit. Signal Process.
Chao Wang, Xiaohong Shen, Haiyan Wang, Haodi Mei
2022 J jnl
Signal Process.
Ge Yang, Yongsheng Yan, Haiyan Wang, Xiaohong Shen
2022 C conf
HPSR
Yuan Liu, Lin Cai, Junhao Hu, Xiaohong Shen, Haiyan Wang
2022 conf
ICSPCC
Chao Dong, Xiaohong Shen, Yongsheng Yan, Yong Wang
2022 J jnl
Remote. Sens.
Yuzhi Zhang, Yue Su, Xiaohong Shen, Anyi Wang, Bin Wang, Yang Liu, Weigang Bai
2022 J jnl
Sensors
Shasha Ma, Haiyan Wang, Xiaohong Shen, Zhenxin Sun, Ning Sun
2022 conf
ICSPCC
Lin Sun, Xiaohong Shen, Zhengguo Liu, Haiyan Wang, Yifan Yuan, Haodi Mei
2022 conf
ICSPCC
Yafen Dong, Xiaohong Shen, Yongsheng Yan, Haiyan Wang
2022 J jnl
EURASIP J. Adv. Signal Process.
Yichen Duan, Xiaohong Shen, Haiyan Wang
2021 J jnl
IEEE Signal Process. Lett.
Lei He, Xiaohong Shen, Mu-Hang Zhang, Haiyan Wang
2021 J jnl
IEEE Wirel. Commun. Lett.
Xin Wang, Xiaohong Shen, Fei Hua, Zhe Jiang
2021 J jnl
IEEE Trans. Commun.
Yong-Sheng Yan, Ge Yang, Haiyan Wang, Xiaohong Shen
2021 conf
ICSPCC
Yuzhu Kang, Xiaohong Shen, Yongsheng Yan, Haiyan Wang, Juan Chang, Changzan Liu
2020 J jnl
Telecommun. Syst.
Tianyi Jia, Haiyan Wang, Xiaohong Shen
2020 Misc conf
ICASSP
Tianyi Jia, K. C. Ho, Haiyan Wang, Xiaohong Shen
2020 J jnl
Sensors
Haitao Dong, Ke He, Xiaohong Shen, Shilei Ma, Haiyan Wang, Changcheng Qiao
2020 J jnl
Sensors
Ruiqin Zhao, Yuan Liu, Octavia A. Dobre, Haiyan Wang, Xiaohong Shen
2020 J jnl
IEEE Commun. Lett.
Ruiqin Zhao, Ning Li, Octavia A. Dobre, Xiaohong Shen
2020 J jnl
IEEE Trans. Veh. Technol.
Zhe Jiang, Xiaohong Shen, Haiyan Wang
2020 J jnl
IEEE Trans. Commun.
Zhe Jiang, Xiaohong Shen, Haiyan Wang, Zhi Ding
2020 J jnl
IEEE Trans. Signal Process.
Tianyi Jia, K. C. Ho, Haiyan Wang, Xiaohong Shen
2020 J jnl
IEEE Access
Changzan Liu, Bo Dang, Haiyan Wang, Xiaohong Shen, Ling Yang, Zhiping Ren, Ruirong Dang, Yuzhu Kang, Baoquan Sun
2020 conf
ICSPCC
Yifan Yuan, Xiaohong Shen, Ke He, Haiyan Wang, Lin Sun, Shilei Ma
2020 conf
ICSPCC
Juan Chang, Xiaohong Shen, Yifan Yuan, Yuzhu Kang, Shaojuan Li
2019 J jnl
Entropy
Weijia Li, Xiaohong Shen, Ya'an Li
2019 J jnl
IEEE Commun. Lett.
Xiaobo Zhao, Daniel E. Lucani, Xiaohong Shen, Haiyan Wang
2019 conf
CCNC
Xiaobo Zhao, Daniel E. Lucani, Xiaohong Shen, Haiyan Wang
2019 J jnl
Sensors
Jing-Jie Gao, Xiaohong Shen, Haodi Mei, Zhichen Zhang
2019 J jnl
IEEE Trans. Signal Process.
Tianyi Jia, K. C. Ho, Haiyan Wang, Xiaohong Shen
2019 J jnl
Sensors
Juan Chang, Xiaohong Shen, Weigang Bai, Ruiqin Zhao, Bin Zhang
2019 conf
EW
Xiaobo Zhao, Daniel E. Lucani, Xiaohong Shen, Haiyan Wang
2019 J jnl
IEEE Access
Tianyi Jia, Xiaohong Shen, Haiyan Wang
2019 J jnl
IEEE Syst. J.
Ruiqin Zhao, Hao Long, Octavia A. Dobre, Xiaohong Shen, Telex Magloire Nkouatchah Ngatched, Haodi Mei
2019 J jnl
CoRR
Ruiqin Zhao, Hao Long, Octavia A. Dobre, Xiaohong Shen, Telex Magloire Nkouatchah Ngatched, Haodi Mei
2018 J jnl
Sensors
Haixia Jing, Haiyan Wang, Zhengguo Liu, Xiaohong Shen
2018 J jnl
IEEE Access
Haitao Dong, Haiyan Wang, Xiaohong Shen, Zhe Jiang
2018 J jnl
Sensors
Yong-Sheng Yan, Haiyan Wang, Xiaohong Shen, Bing Leng, Shuangquan Li
2018 J jnl
CoRR
Xiaobo Zhao, Daniel E. Lucani, Xiaohong Shen, Haiyan Wang
2018 J jnl
IEEE Commun. Lett.
Xiaobo Zhao, Daniel E. Lucani, Xiaohong Shen, Haiyan Wang
2018 J jnl
Signal Process.
Tianyi Jia, Haiyan Wang, Xiaohong Shen, Zhe Jiang, Ke He
2018 conf
FSDM
Lei Liu, Xiaohong Shen, Shilei Ma, Zhichen Zhang
2018 J jnl
J. Frankl. Inst.
Zhe Jiang, Xiaohong Shen, Haiyan Wang
2017 J jnl
Sensors
Jing-Jie Gao, Xiaohong Shen, Ruiqin Zhao, Haodi Mei, Haiyan Wang
2017 conf
ICSPCC
Xuandi Sun, Zhe Jiang, Xiaohong Shen, Xin Wang
2017 conf
ICSPCC
Zhichen Zhang, Haiyan Wang, Zhengguo Liu, Xiaohong Shen, Zhe Jiang, Haixia Jing
2017 J jnl
IET Commun.
Zhe Jiang, Xiaohong Shen, Yao Ge, Haiyan Wang
2017 conf
ICSPCC
Changwei Li, Xiaohong Shen, Zhe Jiang, Xin Wang
2017 conf
ICSPCC
Shilei Ma, Haiyan Wang, Xiaohong Shen, Haitao Dong
2017 conf
ICSPCC
Juan Chang, Xiaohong Shen, Hongyan Zhao
2016 J jnl
J. Commun. Networks
Yuzhi Zhang, Yi Huang, Lei Wan, Shengli Zhou, Xiaohong Shen, Haiyan Wang
2016 J jnl
Int. J. Distributed Sens. Networks
Weigang Bai, Haiyan Wang, Xiaohong Shen, Ruiqin Zhao, Yuzhi Zhang
2016 conf
FSDM
Mengna Zhang, Haiyan Wang, Jing-Jie Gao, Xiaohong Shen
2015 J jnl
Sensors
Yong-Sheng Yan, Haiyan Wang, Xiaohong Shen, Xionghu Zhong
2015 J jnl
Sensors
Jian Xu, Dexing Yang, Chuan Qin, Yajun Jiang, Leixiang Sheng, Xiangyun Jia, Yang Bai, Xiaohong Shen, Haiyan Wang, Xin Deng, Liangbin Xu, Shiquan Jiang
2015 J jnl
Int. J. Distributed Sens. Networks
Yong-Sheng Yan, Haiyan Wang, Xiaohong Shen, Ke He, Xionghu Zhong
2014 conf
WUWNet
Jing-Jie Gao, Xiaohong Shen, Haiyan Wang
2014 J jnl
J. Frankl. Inst.
Zhe Jiang, Xiaohong Shen, Yao Ge, Ruiqin Zhao, Haiyan Wang
2012 J jnl
Int. J. Distributed Sens. Networks
Ruiqin Zhao, Xiaohong Shen, Zhe Jiang, Haiyan Wang
redb/extractors/decompiler/bninja/analysis/disassembly.py
← Index redb/extractors/decompiler/bninja/analysis/disassembly.py python
import re
import time

import binaryninja
from binaryninja.enums import (
    InstructionTextTokenType,
)

# Support both package and standalone imports
try:
    from ..function_type import FunctionTypeAnalysis
    from ..utils.hashes import calculate_sha256
except ImportError:
    # Fallback to absolute imports (for multiprocessing spawned processes)
    from redb.extractors.decompiler.bninja.function_type import FunctionTypeAnalysis
    from redb.extractors.decompiler.bninja.utils.hashes import calculate_sha256


class DisassemblyAnalysis:
    INVALID_STACK_SIZE = -1

    def __init__(self, arch, function, bv, logger):
        self.arch = arch
        self.function = function
        self.bv = bv
        self.logger = logger
        if self.function is not None and hasattr(self.function, "instructions"):
            self.instructions = self.function.instructions
        else:
            self.instructions = []
        self.errors = []
        return

    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 get_json(self):
        try:
            # Build disassembly string and normalized versions
            disassembly_builder = [[], []]  # Address and instruction text

            # Create a dictionary mapping addresses to instruction tokens
            instr_tokens_by_addr = {}
            for instr_tokens, addr in self.instructions:
                instr_tokens_by_addr[addr] = instr_tokens

            addresses = sorted(instr_tokens_by_addr.keys())
            for address in addresses:
                # Original disassembly with addresses
                # instr_tokens, address = instruction
                instr_tokens = instr_tokens_by_addr[address]
                disassembly_builder[0].append(address)
                disassembly_builder[1].append("".join(map(str, instr_tokens)))

            # Join with newlines
            disassembly_str = "\n".join(disassembly_builder[1])
            disassembly_with_addresses = "\n".join(
                f"{hex(address)}: {instr_text}"
                for address, instr_text in zip(
                    disassembly_builder[0], disassembly_builder[1], strict=False
                )
            )

            disassembly_json = {
                "disassembled_function_hash": calculate_sha256(disassembly_str),
                "disassembled_function": disassembly_with_addresses,
                "disassembled_function_no_addresses": disassembly_str,
                "disassembled_function_name": self.function.name,
                "disassembled_function_address": self.function.start,
                "instructions_count": len(instr_tokens_by_addr.keys()),
                "function_type": FunctionTypeAnalysis(self.function)
                .get_function_type()
                .name,
            }

            # Add additional metrics
            type_frequencies = self.collect_instruction_types()
            disassembly_json["instructions_types"] = list(type_frequencies.keys())
            disassembly_json["control_flow_count"] = (
                self.count_control_flow_instructions()
            )
            disassembly_json["memory_access_pattern"] = self.collect_memory_patterns()
            disassembly_json["register_usage"] = self.collect_register_usage()
            disassembly_json["data_references_count"] = self.count_data_references()
            disassembly_json["max_block_size"] = self.compute_max_block_size()
            disassembly_json["num_calls"] = self.compute_num_calls()
            disassembly_json["stack_size"] = self.estimate_stack_size()

            return disassembly_json, self.errors

        except Exception as e:
            self.log_error(
                "Failed to collect instruction types",
                self.function.name,
                self.function.start,
                e,
                "collect_instruction_types",
            )
            raise ValueError(e) from e

    def collect_instruction_types(self):
        """Collect instruction type frequencies from a function."""
        type_frequencies = {}

        try:
            # Iterate through all instructions in the function
            for instruction in self.instructions:
                instr_tokens = instruction[0]  # Get the instruction tokens

                # Extract the mnemonic from the instruction tokens
                mnemonic = None
                for token in instr_tokens:
                    if token.type == InstructionTextTokenType.InstructionToken:
                        mnemonic = token.text
                        break

                if not mnemonic:
                    continue

                # Use normalize_opcode to get standardized opcode
                normalized = self.normalize_opcode(mnemonic)

                # Get category from opcode_categories or use the instruction type directly
                category = self.arch.opcode_categories.get(normalized)
                if category:
                    self._increment_frequency(type_frequencies, category)

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

        return type_frequencies

    def normalize_opcode(self, opcode):
        return opcode.upper()

    def collect_memory_patterns(self):
        """Collect memory access patterns from a function."""
        patterns = []
        try:
            for instruction in self.instructions:
                instr_tokens = instruction[0]

                # We need to capture memory operands between BeginMemoryOperandToken and EndMemoryOperandToken
                in_memory_operand = False
                memory_operand_text = ""

                for token in instr_tokens:
                    if token.type == InstructionTextTokenType.BeginMemoryOperandToken:
                        in_memory_operand = True
                        memory_operand_text = ""
                    elif token.type == InstructionTextTokenType.EndMemoryOperandToken:
                        in_memory_operand = False

                        # Process the captured memory operand text
                        if memory_operand_text:
                            # Categorize memory access pattern
                            if (
                                "+" in memory_operand_text
                                and "*" in memory_operand_text
                            ):
                                if "MEM_SCALED_INDEX" not in patterns:
                                    patterns.append("MEM_SCALED_INDEX")
                            elif (
                                "+" in memory_operand_text or "-" in memory_operand_text
                            ):
                                if "MEM_BASE_OFFSET" not in patterns:
                                    patterns.append("MEM_BASE_OFFSET")
                            else:
                                if "MEM_DIRECT" not in patterns:
                                    patterns.append("MEM_DIRECT")

                            # Check for stack accesses
                            if any(
                                reg in memory_operand_text
                                for reg in ["SP", "BP", "ESP", "EBP", "RSP", "RBP"]
                            ):
                                if "MEM_STACK" not in patterns:
                                    patterns.append("MEM_STACK")
                            # Check for string operations
                            elif (
                                any(
                                    reg in memory_operand_text
                                    for reg in ["SI", "DI", "ESI", "EDI", "RSI", "RDI"]
                                )
                                and "MEM_STRING" not in patterns
                            ):
                                patterns.append("MEM_STRING")
                    elif in_memory_operand:
                        # Accumulate token text while inside a memory operand
                        memory_operand_text += token.text
        except Exception as e:
            self.log_error(
                "Failed to collect memory patterns",
                self.function.name,
                self.function.start,
                e,
                "collect_memory_patterns",
            )
        return patterns

    def collect_register_usage(self):
        """Collect register usage from a function."""
        registers = []
        try:
            # Define register groups we're interested in tracking
            register_groups = {
                "GPR": [
                    "RAX",
                    "RBX",
                    "RCX",
                    "RDX",
                    "R9",
                    "R10",
                    "R11",
                    "R12",
                    "R13",
                    "R14",
                    "R15",
                    "EAX",
                    "EBX",
                    "ECX",
                    "EDX",
                    "R9D",
                    "R10D",
                    "R11D",
                    "R12D",
                    "R13D",
                    "R14D",
                    "AX",
                    "BX",
                    "CX",
                    "DX",
                ],
                "GPR_INDEX": ["RSI", "RDI", "ESI", "EDI", "SI", "DI"],
                "GPR_STACK": ["RSP", "RBP", "ESP", "EBP", "SP", "BP"],
                "SIMD": ["XMM", "YMM", "ZMM"],
                "FPU": ["ST", "ST0", "ST1", "ST2", "ST3", "ST4", "ST5", "ST6", "ST7"],
                "FLAGS": ["FLAGS", "EFLAGS", "RFLAGS"],
                "CONTROL_REGISTER": ["CR0", "CR2", "CR3", "CR4", "CR8"],
                "DEBUG_REGISTER": ["DR0", "DR1", "DR2", "DR3", "DR6", "DR7"],
            }

            # Extract registers from instructions
            for instruction in self.instructions:
                instr_tokens = instruction[0]
                for token in instr_tokens:
                    if token.type == InstructionTextTokenType.RegisterToken:
                        reg = token.text.upper()
                        # Check which group this register belongs to
                        for group, regs in register_groups.items():
                            # if any(r in reg for r in regs) or any(reg.startswith(r) for r in regs):
                            if any(reg == r or reg.startswith(r) for r in regs):
                                if group not in registers:
                                    registers.append(group)
                                break
        except Exception as e:
            self.log_error(
                "Failed to collect register usage",
                self.function.name,
                self.function.start,
                e,
                "collect_register_usage",
            )
        return registers

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

            if self.function.mlil is None:
                return 0

            for block in self.function.mlil:
                for instr in block:
                    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,
                            (
                                binaryninja.mediumlevelil.MediumLevelILConstPtr,
                                binaryninja.mediumlevelil.MediumLevelILConst,
                            ),
                        ):
                            count += 1
                            logged = True

                    # Check full string for hardcoded addresses or symbol-like tokens
                    if re.search(r"\b0x[0-9A-Fa-f]{3,}\b", instr_str) and not logged:
                        count += 1
                        logged = True

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

                    # Only check for MediumLevelILConstPtr if src exists
                    if src is not None and isinstance(
                        src, binaryninja.mediumlevelil.MediumLevelILConstPtr
                    ):
                        addr = src.constant
                        # Check if address is in data sections
                        segment = self.bv.get_segment_at(addr)
                        if segment and segment.writable:
                            # print(f"[{function.name}] Matched data section reference in: {instr_str}")
                            count += 1
                            logged = True
        except Exception as e:
            self.logger.warning(
                f"Failed to use MLIL for counting data references in {self.function.name} at {self.function.start}: {e}"
            )
        return count

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

        for block in self.function.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.function.name,
                    self.function.start,
                    e,
                    "compute_max_block_size",
                )
        return max_size

    def count_control_flow_instructions(self):
        """Count the number of control flow instructions in a function."""
        count = 0
        try:
            for instruction in self.instructions:
                instr_tokens = instruction[0]
                if self.arch.is_control_flow_instruction(instr_tokens):
                    count += 1
        except Exception as e:
            self.log_error(
                "Failed to count control flow instructions",
                self.function.name,
                self.function.start,
                e,
                "count_control_flow_instructions",
            )
        return count

    def compute_num_calls(self) -> int:
        """Compute the number of call instructions in a function."""
        num_calls = 0
        try:
            for instruction in self.instructions:
                instr_tokens = instruction[0]
                # Extract the mnemonic
                for token in instr_tokens:
                    if token.type == InstructionTextTokenType.InstructionToken:
                        if token.text.upper() == "CALL":
                            num_calls += 1
                        break
        except Exception as e:
            self.log_error(
                "Failed to compute number of calls",
                self.function.name,
                self.function.start,
                e,
                "compute_num_calls",
            )
        return num_calls

    def _increment_frequency(self, frequencies, type_name):
        """Increment the frequency count for an instruction type."""
        if type_name in frequencies:
            frequencies[type_name] += 1
        else:
            frequencies[type_name] = 1

    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.function.name,
                self.function.start,
                e,
                "estimate_stack_size",
            )
            return self.INVALID_STACK_SIZE