Updates
This commit is contained in:
@@ -59,3 +59,103 @@ def collect_labels(instructions: Iterable[Instruction], vectors: dict[int, tuple
|
||||
for target in ins.targets:
|
||||
labels.setdefault(target, label_for(target))
|
||||
return labels
|
||||
|
||||
|
||||
def collect_function_entries(
|
||||
instructions: Iterable[Instruction],
|
||||
vectors: dict[int, tuple[str, int]],
|
||||
) -> set[int]:
|
||||
entries = {target for _name, target in vectors.values()}
|
||||
for ins in instructions:
|
||||
if ins.kind == "call":
|
||||
entries.update(ins.targets)
|
||||
return entries
|
||||
|
||||
|
||||
def assign_functions(instructions: dict[int, Instruction], entries: set[int]) -> dict[int, int]:
|
||||
owners: dict[int, int] = {}
|
||||
current: int | None = None
|
||||
for address in sorted(instructions):
|
||||
if address in entries:
|
||||
current = address
|
||||
if current is not None:
|
||||
owners[address] = current
|
||||
if instructions[address].kind in {"return", "rte", "sleep"}:
|
||||
current = None
|
||||
return owners
|
||||
|
||||
|
||||
def build_functions(
|
||||
instructions: dict[int, Instruction],
|
||||
vectors: dict[int, tuple[str, int]],
|
||||
labels: dict[int, str],
|
||||
) -> list[dict[str, object]]:
|
||||
entries = collect_function_entries(instructions.values(), vectors)
|
||||
owners = assign_functions(instructions, entries)
|
||||
vector_sources: dict[int, list[str]] = {}
|
||||
for _vector_addr, (name, target) in vectors.items():
|
||||
vector_sources.setdefault(target, []).append(name)
|
||||
|
||||
functions: dict[int, dict[str, object]] = {}
|
||||
for address, owner in owners.items():
|
||||
ins = instructions[address]
|
||||
function = functions.setdefault(
|
||||
owner,
|
||||
{
|
||||
"start": owner,
|
||||
"label": labels.get(owner, label_for(owner)),
|
||||
"sources": vector_sources.get(owner, []),
|
||||
"instruction_count": 0,
|
||||
"end": owner,
|
||||
"calls": [],
|
||||
"unresolved_calls": 0,
|
||||
},
|
||||
)
|
||||
function["instruction_count"] = int(function["instruction_count"]) + 1
|
||||
function["end"] = max(int(function["end"]), ins.address + max(ins.size, 1) - 1)
|
||||
if ins.kind == "call":
|
||||
if ins.targets:
|
||||
calls = function["calls"]
|
||||
assert isinstance(calls, list)
|
||||
for target in ins.targets:
|
||||
if target not in calls:
|
||||
calls.append(target)
|
||||
else:
|
||||
function["unresolved_calls"] = int(function["unresolved_calls"]) + 1
|
||||
|
||||
return [functions[start] for start in sorted(functions)]
|
||||
|
||||
|
||||
def build_call_graph(
|
||||
instructions: dict[int, Instruction],
|
||||
vectors: dict[int, tuple[str, int]],
|
||||
labels: dict[int, str],
|
||||
) -> dict[str, object]:
|
||||
entries = collect_function_entries(instructions.values(), vectors)
|
||||
owners = assign_functions(instructions, entries)
|
||||
nodes = build_functions(instructions, vectors, labels)
|
||||
edges: list[dict[str, object]] = []
|
||||
seen: set[tuple[int, int]] = set()
|
||||
|
||||
for ins in instructions.values():
|
||||
if ins.kind != "call" or not ins.targets:
|
||||
continue
|
||||
source = owners.get(ins.address)
|
||||
if source is None:
|
||||
continue
|
||||
for target in ins.targets:
|
||||
key = (source, target)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
edges.append(
|
||||
{
|
||||
"from": source,
|
||||
"from_label": labels.get(source, label_for(source)),
|
||||
"to": target,
|
||||
"to_label": labels.get(target, label_for(target)),
|
||||
"call_site": ins.address,
|
||||
},
|
||||
)
|
||||
|
||||
return {"nodes": nodes, "edges": sorted(edges, key=lambda edge: (edge["from"], edge["to"]))}
|
||||
|
||||
Reference in New Issue
Block a user