Jaewon Kim

85 papers A* 3A 5B 6C 2Misc 2Journal 47Unranked 20
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Inf. Forensics Secur.
Jingon Joung, Sinuk Choi, Jaewon Kim, Eui-Rim Jeong, Chau Yuen
2025 J jnl
NeuroImage
Su Hyun Bong, Yourim Shin, Dayoung Yoon, Jaewon Kim, Hyunsoo Park, Bumseok Jeong
2025 J jnl
Biomed. Signal Process. Control.
Hyeokjong Lee, Jaewon Kim, Bohyung Han, Sang Min Park, Jooyoung Chang
2025 J jnl
IEEE Access
Jaewon Kim, Eunbi Kim, Dongsoo Kim, Yoojoong Kim, Taesu Cheong
2025 J jnl
NeuroImage
Dayoung Yoon, Jaejoong Kim, Donghyun Kim, Dong Woo Shin, Su Hyun Bong, Jaewon Kim, Hae-Jeong Park, Hong Jin Jeon, Bumseok Jeong
2025 J jnl
Comput. Medical Imaging Graph.
Azka Rehman, Jaewon Kim, Hyeokjong Lee, Jooyoung Chang, Sang Min Park
2025 J jnl
npj Digit. Medicine
Hyeokjong Lee, Jaewon Kim, Sangmin Kwak, Azka Rehman, Sang Min Park, Jooyoung Chang
2025 J jnl
IEEE Internet Things J.
Jueming Hu, Mohammad Ammar, Bilal Zahid Hussain, Jaewon Kim, Irfan Khan
2025 conf
CASE
Oluwafemi Ajeigbe, Jaewon Kim, Ryan Ozelton, Jeremy Tang, Anthony Munoz, Sandip Roy
2025 J jnl
J. Imaging Inform. Medicine
Soo Ho Ahn, Seungjin Baek, Jiwoo Park, Jaewon Kim, Hyungjin Rhee, Yong Eun Chung, Hwiyoung Kim, Young Han Lee
2024 A conf
WACV
Junuk Cha, Hansol Lee, Jaewon Kim, Nhat Nguyen Bao Truong, Jae Shin Yoon, Seungryul Baek
2024 J jnl
CoRR
Junuk Cha, Hansol Lee, Jaewon Kim, Nhat Nguyen Bao Truong, Jae Shin Yoon, Seungryul Baek
2024 J jnl
IEEE Internet Things J.
Peng-Hao Huang, Jaewon Kim, P. R. Kumar, Jeyavijayan Rajendran, Prasad Enjeti
2024 J jnl
CoRR
Jaewon Kim, Lindsay Popowski, Anna Fang, Cassidy Pyle, Guo Freeman, Ryan M. Kelly, Angela Y. Lee, Fannie Liu, Angela D. R. Smith, Alexandra To, Amy X. Zhang
2024 J jnl
CoRR
Rahul Shenoy, Zhihong Pan, Kaushik Balakrishnan, Qisen Cheng, Yongmoon Jeon, Heejune Yang, Jaewon Kim
2024 J jnl
IEEE Trans. Ind. Electron.
Woo-Hyun Ko, Jorge Ramos-Ruiz, Tong Huang, Jaewon Kim, Hasan Ibrahim, Prasad N. Enjeti, P. R. Kumar, Le Xie
2024 A conf
INTERSPEECH
Jaewon Kim, Won-Gook Choi, Seyun Ahn, Joon-Hyuk Chang
2024 J jnl
IEEE Trans. Wirel. Commun.
Santosh Ganji, Jaewon Kim, Romil Sonigra, P. R. Kumar
2024 J jnl
IEEE Access
Min-Sup Song, Jaewon Kim, Hwanhee Cho
2023 J jnl
Biomed. Signal Process. Control.
Xiaoqun Yu, Seonghyeok Park, Doil Kim, Eungjin Kim, Jaewon Kim, Woosub Kim, Yechan An, Shuping Xiong
2023 Misc conf
MVA
Jihyun Lee, Hangil Park, Yongmin Seo, Taewon Min, Joodong Yun, Jaewon Kim, Tae-Kyun Kim
2023 J jnl
IEEE Access
Faris H. Alotaibi, Hasan Ibrahim, Jaewon Kim, P. R. Kumar, Prasad Enjeti
2023 J jnl
npj Digit. Medicine
Hyeonhoon Lee, Hyun-Kyu Yoon, Jaewon Kim, Ji Soo Park, Chang-Hoon Koo, Dongwook Won, Hyung-Chul Lee
2023 J jnl
IEEE Trans. Ind. Electron.
Lantian Shangguan, Kenny Chour, Woo-Hyun Ko, Jaewon Kim, Gopal Krishna Kamath, Bharadwaj Satchidanandan, Swaminathan Gopalswamy, P. R. Kumar
2023 J jnl
IEEE Access
Min-Sup Song, Jaewon Kim, Jae-Bum Lee
2023 J jnl
Expert Syst. Appl.
Jaewon Kim, Kyohoon Jin, Soojin Jang, Shinjin Kang, YoungBin Kim
2023 J jnl
CoRR
Santosh Ganji, Jaewon Kim, Romil Sonigra, P. R. Kumar
2022 J jnl
CoRR
Jaewon Kim, Jooyoung Chang, Sang Min Park
2022 J jnl
CoRR
Desik Rengarajan, Sapana Chaudhary, Jaewon Kim, Dileep Kalathil, Srinivas Shakkottai
2022 A* conf
NeurIPS
Desik Rengarajan, Sapana Chaudhary, Jaewon Kim, Dileep Kalathil, Srinivas Shakkottai
2022 conf
EGSR (ST)
Yongmoon Jeon, Haneol Kim, Hyeona Lee, Seonghoon Jo, Jaewon Kim
2022 J jnl
CoRR
Santosh Ganji, Jaewon Kim, P. R. Kumar
2022 conf
SIGCOMM Posters and Demos
Santosh Ganji, Jaewon Kim, P. R. Kumar
2021 J jnl
J. Medical Imaging Health Informatics
Jaewon Kim, Sungsik Kang, Konsu Lee, Jin Ho Jung, Garam Kim, Hyunkeong Lim, Yong Choi, Sangwon Lee, Mijin Yun
2021 conf
UbiComp/ISWC Adjunct
Jaewon Kim, Yuri Kim, Yuna Jeong, Youngki Lee
2021 J jnl
CoRR
Venkata Siva Santosh Ganji, Tzu-Hsiang Lin, Jaewon Kim, P. R. Kumar
2021 conf
SIGCOMM Posters and Demos
Santosh Ganji, Tzu-Hsiang Lin, Jaewon Kim, P. R. Kumar
2020 J jnl
Sensors
Abdurhaman Teyib Abafogi, Jaewon Kim, Jinyeop Lee, Merem Omer Mohammed, Danny van Noort, Sungsu Park
2020 J jnl
IEEE Trans. Ind. Electron.
Jaewon Kim, Joon-Hyoung Ryu, Gildong Kim, Jaebum Lee, Sanghoon Chang, Changmu Lee, Joorak Kim, Yong-Kuk Oh, Hansang Lee, Jooha Kim
2020 J jnl
Nucleic Acids Res.
Ye Eun Jang, Insu Jang, Sunkyu Kim, Subin Cho, Daehan Kim, Keonwoo Kim, Jaewon Kim, Jimin Hwang, Sangok Kim, Jaesang Kim, Jaewoo Kang, Byungwook Lee, Sanghyuk Lee
2020 J jnl
IEEE Access
Yuchul Shin, Jaewon Kim, Kyohoon Jin, Young Bin Kim
2020 J jnl
Symmetry
Jaewon Kim, Jeonga Wi, Soojin Jang, Young Bin Kim
2020 B conf
CHIIR
Afrah Olayan Alanazi, Mark Sanderson, Zhifeng Bao, Jaewon Kim
2019 conf
ASIST
Jaewon Kim, Ji-Young Kim, Yongjun Zhu
2019 conf
BIR@ECIR
Jaewon Kim, Johanne R. Trippas, Mark Sanderson, Zhifeng Bao, W. Bruce Croft
2018 conf
IEEE BigData
Kangsoo Jung, Jaewon Kim, Youngjun Kim, Seog Park
2018 conf
BigComp
Byungsoo Ko, Chan Yong Park, Dongkeon Lee, Jaewon Kim, Ho-Jin Choi, Dongsoo Han
2018 C conf
IPIN
Jaewon Kim, Dongsoo Han
2018 A conf
CIKM
Tadele Tedla Damessie, J. Shane Culpepper, Jaewon Kim, Falk Scholer
2017 conf
ICC
Sangjae Lee, Namkyoung Lee, Jeonghee Ahn, Jaewon Kim, Byoungchul Moon, Suk Hoon Jung, Dongsoo Han
2017 B conf
CHIIR
Jaewon Kim, Paul Thomas, Ramesh S. Sankaranarayana, Tom Gedeon, Hwan-Jin Yoon
2016 A conf
CIKM
Jaewon Kim, Paul Thomas, Ramesh S. Sankaranarayana, Tom Gedeon, Hwan-Jin Yoon
2016 J jnl
J. Assoc. Inf. Sci. Technol.
Jaewon Kim, Paul Thomas, Ramesh S. Sankaranarayana, Tom Gedeon, Hwan-Jin Yoon
2016 A* conf
SIGIR
Jaewon Kim
2015 conf
GLOBECOM Workshops
Namjeong Lee, Cheol Jeong, Jaewon Kim, Jeongho Park
2015 J jnl
J. Assoc. Inf. Sci. Technol.
Jaewon Kim, Paul Thomas, Ramesh S. Sankaranarayana, Tom Gedeon, Hwan-Jin Yoon
2014 conf
HCI (1)
Yu-Jin Hong, Jaewon Kim, Junghyun Cho, Ig-Jae Kim
2014 B conf
GLOBECOM
Jaewon Kim, Cheol Jeong, Hyunkyu Yu, Jeongho Park
2014 conf
GCCE
Jaewon Kim, Changwoo Min, Jee-hong Kim, Donghyun Kang, Inhyeok Kim, Young Ik Eom
2014 J jnl
Wirel. Pers. Commun.
Eunyoung Ahn, Jaewon Kim
2013 J jnl
EURASIP J. Adv. Signal Process.
Jaewon Kim, Donghyun Lee, Wonjin Sung
2013 conf
HCI (25)
Jaewon Kim, Gyuchull Han, Ig-Jae Kim, Hyoung-Gon Kim, Sang Chul Ahn
2013 J jnl
Wirel. Pers. Commun.
Jaewon Kim, Kyungeun Cho, Eunyoung Ahn
2012 Misc conf
ADCS
Jaewon Kim, Paul Thomas, Ramesh S. Sankaranarayana, Tom Gedeon
2012 J jnl
Inf. Media Technol.
Seiichi Tagawa, Yasuhiro Mukaigawa, Jaewon Kim, Ramesh Raskar, Yasuyuki Matsushita, Yasushi Yagi
2012 B conf
PIMRC
Jaewon Kim, Sukho Shin, Jihoon Sung, Donghyun Lee, Wonjin Sung
2012 conf
ICITCS
Jaewon Kim, Kyungeun Cho, Eunyoung Ahn
2012 B conf
ICPR
Jong-Ho Lee, Sang Chul Ahn, Hwasup Lim, Ig-Jae Kim, Jaewon Kim, Hyoung-Gon Kim
2012 J jnl
IEEE Commun. Lett.
Jaewon Kim, Sukho Shin, Wonjin Sung
2011 B conf
WCNC
Jaeyong Park, Jaewon Kim, Hyung-gil Yoo, Wonjin Sung
2011 J jnl
IPSJ Trans. Comput. Vis. Appl.
Seiichi Tagawa, Yasuhiro Mukaigawa, Jaewon Kim, Ramesh Raskar, Yasuyuki Matsushita, Yasushi Yagi
2011 J jnl
ACM Trans. Graph.
Jaewon Kim, Roarke Horstmeyer, Ig-Jae Kim, Ramesh Raskar
2011 conf
FGIT-MulGraB (1)
Dong-Yuel Choi, Eunyoung Ahn, Jaewon Kim
2010 J jnl
CoRR
Jaewon Kim, JongHyun Park
2010 conf
ECCV (1)
Jaewon Kim, Douglas Lanman, Yasuhiro Mukaigawa, Ramesh Raskar
2010 J jnl
J. Commun. Networks
Sangtae Kim, Jaewon Kim, Dong-Joon Shin, Dae-Ig Chang, Wonjin Sung
2010 conf
ACCV (1)
Yasuhiro Mukaigawa, Seiichi Tagawa, Jaewon Kim, Ramesh Raskar, Yasuyuki Matsushita, Yasushi Yagi
2008 conf
CCNC
Euiseok Song, JongHyun Park, Jaewon Kim, Seongtaek Hwang, Wonjin Sung
2008 J jnl
J. Commun. Networks
JongHyun Park, Jaewon Kim, Wonjin Sung
2005 conf
Australian Conference on Artificial Intelligence
Eunyoung Ahn, Jaewon Kim, Noyoon Kwak, Sanghoon Han
1999 J jnl
IEEE Trans. Consumer Electron.
Jaewon Kim, Hyungjung Kim, Songin Choi, Younggap You
1997 A* conf
DAC
Jaewon Kim, Sung-Mo Kang
1996 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Jaewon Kim, Sung-Mo Kang
1995 A conf
ICCAD
Jaewon Kim, Sung-Mo Kang
1994 C conf
ISCAS
Jaewon Kim, Sung-Mo Kang, Sachin S. Sapatnekar
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