Carlos Alberto Silva

42 papers C 10Journal 30Unranked 2
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
Leonel Corado, Sérgio Godinho, Carlos Alberto Silva, Juan Guerra-Hernández, Francesco Valerio, Teresa Gonçalves, Pedro D. Salgueiro
2024 J jnl
Remote. Sens.
Youshui Zhang, Carlos Alberto Silva, Mengdi Chen
2024 J jnl
ACM Trans. Access. Comput.
Jorge Sassaki Resende Silva, Paula Christina Figueira Cardoso, Raphael Winckler de Bettio, Daniela Cardoso Tavares, Carlos Alberto Silva, Willian Massami Watanabe, André Pimenta Freire
2024 C conf
IGARSS
Rodrigo Vieira Leite, William C. Wagner, Margaret Wooten, Monique Bohora Schlickmann, Carlos Alberto Silva, Cibele Hummel do Amaral, Diogo Nepomuceno Cosenza, Carlos M. M. E. Torres, Ameni Mkaouar, Shashank Bhushan, David E. Shean, Paul M. Montesano, Douglas C. Morton, Christopher S. R. Neigh
2023 C conf
IGARSS
Kleydson Diego Rocha, Monique Bohora Schlickmann, Jinyi Xia, Rodrigo Vieira Leite, Carine Klauberg, Ajay Sharma, Carlos Alberto Silva
2023 J jnl
Remote. Sens.
Ewane Basil Ewane, Midhun Mohan, Shaurya Bajaj, G. A. Pabodha Galgamuwa, Michael S. Watt, Pavithra S. Pitumpe Arachchige, Andrew T. Hudak, Gabriella Richardson, Nivedhitha Ajithkumar, Shruthi Srinivasan, Ana Paula Dalla Corte, Daniel J. Johnson, Eben North Broadbent, Sergio de-Miguel, Margherita Bruscolini, Derek J. N. Young, Shahid Shafai, Meshal M. Abdullah, Wan Shafrina Wan Mohd Jaafar, Willie Doaemo, Carlos Alberto Silva, Adrián Cardil
2023 J jnl
Remote. Sens.
Trina Merrick, Ralf Bennartz, Maria Luisa S. P. Jorge, Carli Merrick, Stephanie A. Bohlman, Carlos Alberto Silva, Stephanie Pau
2023 J jnl
Remote. Sens.
Kleydson Diego Rocha, Carlos Alberto Silva, Diogo Nepomuceno Cosenza, Midhun Mohan, Carine Klauberg, Monique Bohora Schlickmann, Jinyi Xia, Rodrigo Vieira Leite, Danilo Roberti Alves de Almeida, Jeff W. Atkins, Adrián Cardil, Eric Rowell, Russ Parsons, Nuria Sanchez-Lopez, Susan J. Prichard, Andrew T. Hudak
2023 C conf
IGARSS
Mauro Alessandro Karasinski, Carine Klauberg, Victoria M. Donovan, Jiangxiao Qiu, Denis Valle, Jason G. Vogel, Ajay Sharma, Jeff W. Atkins, Andres Susaeta, Monique Bohora Schlickmann, Jinyi Xia, Kleydson Diego Rocha, Rodrigo Vieira Leite, Carlos Alberto Silva
2023 C conf
IGARSS
Rodrigo Vieira Leite, Carlos Alberto Silva, Cibele Hummel do Amaral, Diogo Nepomuceno Cosenza, Monique Bohora Schlickmann, Kleydson Diego Rocha, Jinyi Xia, Midhun Mohan, Esmaeel Adrah, Danilo Roberti Alves de Almeida, Christopher S. R. Neigh
2023 C conf
IGARSS
Jinyi Xia, Carine Klauberg, Kledyson Diego Rocha, Monique Bohora Schlickmann, Carlos Alberto Silva
2023 C conf
IGARSS
Monique Bohora Schlickmann, Luiz Guilherme Nogueira, Rodrigo Vieira Leite, Kleydson Diego Rocha, Jinyi Xia, Danilo Souza, Eben North Broadbent, Sassan Saatchi, Carine Klauberg, Andrew T. Hudak, Mauro Alessandro Karasinski, Matheus Pinheiro Ferreira, Danilo Roberti Alves de Almeida, Carlos Alberto Silva
2023 C conf
IGARSS
Carlos Alberto Silva, Kleydson Diego Rocha, Diogo Nepomuceno Cosenza, Midhun Mohan, Carine Klauberg, Monique Bohora Schlickmann, Jinyi Xia, Rodrigo Vieira Leite, Danilo Roberti Alves de Almeida, Jeff W. Atkins, Adrián Cardil, Eric Rowell, Russ Parsons, Nuria Sanchez-Lopez, Susan J. Prichard, Andrew T. Hudak
2023 J jnl
Remote. Sens.
Carine Klauberg, Jason G. Vogel, Ricardo Dalagnol, Matheus Pinheiro Ferreira, Caio Hamamura, Eben Broadbent, Carlos Alberto Silva
2022 J jnl
Remote. Sens.
Jaz Stoddart, Danilo Roberti Alves de Almeida, Carlos Alberto Silva, Eric Bastos Görgens, Michael Keller, Ruben Valbuena
2022 J jnl
Remote. Sens.
Esmaeel Adrah, Wan Shafrina Wan Mohd Jaafar, Hamdan Omar, Shaurya Bajaj, Rodrigo Vieira Leite, Siti Munirah Mazlan, Carlos Alberto Silva, Maggie Chel Gee Ooi, Mohd Nizam Mohd Said, Khairul Nizam Abdul Maulud, Adrián Cardil, Midhun Mohan
2022 J jnl
Remote. Sens.
Jessica M. Stitt, Andrew T. Hudak, Carlos Alberto Silva, Lee A. Vierling, Kerri T. Vierling
2021 J jnl
J. Interact. Syst.
Delvani Antônio Mateus, Carlos Alberto Silva, Arthur Floriano Barbosa Andrade de Oliveira, Heitor A. X. Costa, André Pimenta Freire
2021 J jnl
Remote. Sens.
Iván Dorado-Roda, Adrián Pascual, Sérgio Godinho, Carlos Alberto Silva, Brigite Botequim, Pablo Rodríguez-Gonzálvez, Eduardo González-Ferreiro, Juan Guerra-Hernández
2021 C conf
IGARSS
Laura Duncanson, Amy Neuenschwander, Carlos Alberto Silva, Paul M. Montesano, Eric Guenther, Nathan Thomas, Steven Hancock, David Minor, Joanne C. White, Mike A. Wulder, John Armston
2021 J jnl
Remote. Sens.
Micah Russell, Jan U. H. Eitel, Timothy E. Link, Carlos Alberto Silva
2020 C conf
IGARSS
Charlie Marshak, Marc Simard, Laura Duncanson, Carlos Alberto Silva, Michael Denbina, Tien-Hao Liao
2020 J jnl
Remote. Sens.
Marcus V. N. d'Oliveira, Eben Broadbent, Luis C. Oliveira, Danilo Roberti Alves de Almeida, Daniel de Almeida Papa, Manuel Eduardo Ferreira, Angelica M. Almeyda Zambrano, Carlos Alberto Silva, Felipe Spina Avino, Gabriel Atticciati Prata, Ricardo A. Mello, Evandro O. Figueiredo, Lúcio André de Castro Jorge, Leomar Junior, Rafael Walter Albuquerque, Pedro Henrique Santin Brancalion, Benjamin Wilkinson, Marcelo Oliveira-da-Costa
2020 conf
IHC
Delvani Antônio Mateus, Carlos Alberto Silva, Marcelo Medeiros Eler, André Pimenta Freire
2020 J jnl
Remote. Sens.
Vanessa Sousa da Silva, Carlos Alberto Silva, Midhun Mohan, Adrián Cardil, Franciel Eduardo Rex, Gabrielle Hambrecht Loureiro, Danilo Roberti Alves de Almeida, Eben North Broadbent, Eric Bastos Görgens, Ana Paula Dalla Corte, Emanuel Araújo Silva, Ruben Valbuena, Carine Klauberg
2020 J jnl
Remote. Sens.
Franciel Eduardo Rex, Carlos Alberto Silva, Ana Paula Dalla Corte, Carine Klauberg, Midhun Mohan, Adrián Cardil, Vanessa Sousa da Silva, Danilo Roberti Alves de Almeida, Mariano García, Eben North Broadbent, Ruben Valbuena, Jaz Stoddart, Trina Merrick, Andrew Thomas Hudak
2020 J jnl
Remote. Sens.
Yonghua Qu, Ahmed Shaker, Lauri Korhonen, Carlos Alberto Silva, Kun Jia, Luo Tian, Jinling Song
2020 J jnl
Remote. Sens.
Rodrigo Vieira Leite, Cibele Hummel do Amaral, Raul de Paula Pires, Carlos Alberto Silva, Carlos Pedro Boechat Soares, Renata Paulo Macedo, Antonilmar Araújo Lopes da Silva, Eben North Broadbent, Midhun Mohan, Helio Garcia Leite
2020 J jnl
Comput. Electron. Agric.
Ana Paula Dalla Corte, Deivison Venicio Souza, Franciel Eduardo Rex, Carlos Roberto Sanquetta, Midhun Mohan, Carlos Alberto Silva, Angelica M. Almeyda Zambrano, Gabriel Atticciati Prata, Danilo Roberti Alves de Almeida, Jonathan William Trautenmüller, Carine Klauberg, Anibal de Moraes, Mateus Sanquetta, Benjamin Wilkinson, Eben North Broadbent
2020 J jnl
Remote. Sens.
Rodrigo Vieira Leite, Carlos Alberto Silva, Midhun Mohan, Adrián Cardil, Danilo Roberti Alves de Almeida, Samuel de Padua Chaves e Carvalho, Wan Shafrina Wan Mohd Jaafar, Juan Guerra-Hernández, Aaron Weiskittel, Andrew T. Hudak, Eben North Broadbent, Gabriel Atticciati Prata, Ruben Valbuena, Helio Garcia Leite, Mariana Futia Taquetti, Alvaro Augusto Vieira Soares, Henrique Ferraço Scolforo, Cibele Hummel do Amaral, Ana Paula Dalla Corte, Carine Klauberg
2020 J jnl
Remote. Sens.
Ana Paula Dalla Corte, Franciel Eduardo Rex, Danilo Roberti Alves de Almeida, Carlos Roberto Sanquetta, Carlos Alberto Silva, Marks Melo Moura, Benjamin Wilkinson, Angelica M. Almeyda Zambrano, Ernandes Macedo da Cunha Neto, Hudson Franklin Pessoa Veras, Anibal de Moraes, Carine Klauberg, Midhun Mohan, Adrián Cardil, Eben North Broadbent
2020 J jnl
Remote. Sens.
Charlie Marshak, Marc Simard, Laura Duncanson, Carlos Alberto Silva, Michael Denbina, Tien-Hao Liao, Lola Fatoyinbo, Ghislain Moussavou, John Armston
2020 J jnl
Remote. Sens.
Gabriel Atticciati Prata, Eben North Broadbent, Danilo Roberti Alves de Almeida, Joseph St. Peter, Jason B. Drake, Paul Medley, Ana Paula Dalla Corte, Jason G. Vogel, Ajay Sharma, Carlos Alberto Silva, Angelica M. Almeyda Zambrano, Ruben Valbuena, Benjamin Wilkinson
2019 J jnl
Sensors
Kaio Allan Cruz Gasparini, Celso Henrique Leite Silva Junior, Yosio Edemir Shimabukuro, Egidio Arai, Luiz Eduardo Oliveira e Cruz de Aragão, Carlos Alberto Silva, Peter L. Marshall
2019 J jnl
Int. J. Appl. Earth Obs. Geoinformation
Danilo Roberti Alves de Almeida, Eben North Broadbent, Angelica M. Almeyda Zambrano, Benjamin E. Wilkinson, Manuel Eduardo Ferreira, Robin L. Chazdon, Paula Meli, Eric Bastos Görgens, Carlos Alberto Silva, Scott C. Stark, Ruben Valbuena, Daniel de Almeida Papa, Pedro Henrique Santin Brancalion
2019 J jnl
Remote. Sens.
Danilo Roberti Alves de Almeida, Scott C. Stark, Gang Shao, Juliana Schietti, Bruce Walker Nelson, Carlos Alberto Silva, Eric Bastos Görgens, Ruben Valbuena, Daniel de Almeida Papa, Pedro Henrique Santin Brancalion
2019 conf
IHC
Carlos Alberto Silva, Arthur Floriano Barbosa Andrade de Oliveira, Delvani Antônio Mateus, Heitor Augustus Xavier Costa, André Pimenta Freire
2018 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Carlos Alberto Silva, Sassan Saatchi, Mariano García, Nicolas Labriere, Carine Klauberg, Antonio Ferraz, Victoria Meyer, Kathryn J. Jeffery, Katharine Abernethy, Lee J. T. White, Kaiguang Zhao, Simon L. Lewis, Andrew Todd
2018 J jnl
Remote. Sens.
Yonghua Qu, Ahmed Shaker, Carlos Alberto Silva, Carine Klauberg, Ekena Rangel Pinagé
2017 J jnl
Remote. Sens.
Carlos Alberto Silva, Andrew Thomas Hudak, Lee Alexander Vierling, Carine Klauberg, Mariano García, Antonio Ferraz, Michael Keller, Jan U. H. Eitel, Sassan Saatchi
2016 J jnl
Remote. Sens.
Antonio Ferraz, Sassan Saatchi, Clément Mallet, Stéphane Jacquemoud, Gil Rito Gonçalves, Carlos Alberto Silva, Paula Soares, Margarida Tomé, Luísa Gomes Pereira
2013 C conf
IGARSS
Carlos Alberto Silva, Carine Klauberg, Samuel de Padua Chaves e Carvalho, Luiz Carlos Estraviz Rodriguez
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