Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/ida_pro_mcp/mcp-plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,67 @@ def get_xrefs_to_field(
})
return xrefs

@jsonrpc
@idaread
def get_callees(
function_address: Annotated[str, "Address of the function to get callee functions"],
) -> list[dict[str, str]]:
"""Get all callee functions of the given address"""
func_start = parse_address(function_address)
func = idaapi.get_func(func_start)
if not func:
raise IDAError(f"No function found containing address {function_address}")
func_end = idc.find_func_end(func_start)
callees: list[dict[str, str]] = []
current_ea = func_start
while current_ea < func_end:
insn = idaapi.insn_t()
idaapi.decode_insn(insn, current_ea)
if insn.itype in [idaapi.NN_call, idaapi.NN_callfi, idaapi.NN_callni]:
target = idc.get_operand_value(current_ea, 0)
target_type = idc.get_operand_type(current_ea, 0)
# check if it's a direct call - avoid getting the indirect call offset
if target_type in [idaapi.o_mem, idaapi.o_near, idaapi.o_far]:
# in here, we do not use get_function because the target can be external function.
# but, we should mark the target as internal/external function.
func_type = (
"internal" if idaapi.get_func(target) is not None else "external"
)
func_name = idc.get_name(target)
if func_name is not None:
callees.append(
{"address": hex(target), "name": func_name, "type": func_type}
)
current_ea = idc.next_head(current_ea, func_end)

# deduplicate callees
unique_callee_tuples = {tuple(callee.items()) for callee in callees}
unique_callees = [dict(callee) for callee in unique_callee_tuples]
return unique_callees # type: ignore

@jsonrpc
@idaread
def get_callers(
function_address: Annotated[str, "Address of the function to get callers"],
) -> list[Function]:
"""Get all callers of the given address"""
callers = {}
for caller_address in idautils.CodeRefsTo(parse_address(function_address), 0):
# validate the xref address is a function
func = get_function(caller_address, raise_error=False)
if not func:
continue
# load the instruction at the xref address
insn = idaapi.insn_t()
idaapi.decode_insn(insn, caller_address)
# check the instruction is a call
if insn.itype not in [idaapi.NN_call, idaapi.NN_callfi, idaapi.NN_callni]:
continue
# deduplicate callers by address
callers[func["address"]] = func

return list(callers.values())

@jsonrpc
@idaread
def get_entry_points() -> list[Function]:
Expand Down