Skip to content
This repository was archived by the owner on Oct 1, 2023. It is now read-only.

Commit e81cd9d

Browse files
author
Andrew Strelsky
authored
Merge pull request #33 from garyttierney/feat/class-graph-script
Add a script to graph a class hierarchy tree
2 parents f10241e + eac1364 commit e81cd9d

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Given a class name, render a graph with the entire class hierarchy (all supertypes and subtypes).
2+
// @category CppClassAnalyzer
3+
import cppclassanalyzer.data.typeinfo.ClassTypeInfoDB;
4+
import cppclassanalyzer.script.CppClassAnalyzerGhidraScript;
5+
import docking.widgets.EventTrigger;
6+
import ghidra.GhidraException;
7+
import ghidra.app.services.GraphDisplayBroker;
8+
import ghidra.framework.plugintool.PluginTool;
9+
import ghidra.service.graph.AttributedGraph;
10+
import ghidra.service.graph.AttributedVertex;
11+
import ghidra.service.graph.GraphDisplay;
12+
13+
import java.util.*;
14+
15+
public class ShowClassTreeGraph extends CppClassAnalyzerGhidraScript {
16+
17+
@Override
18+
protected void run() throws Exception {
19+
String typeName = askString("Class name", "Enter name of the class to print the class tree of");
20+
ClassTypeInfoDB type = currentManager.getTypeStream()
21+
.filter(ty -> typeName.equalsIgnoreCase(ty.getName()))
22+
.findFirst()
23+
.orElseThrow(() -> new GhidraException("No type found with given name"));
24+
25+
monitor.setMessage("Generating class tree graph");
26+
27+
PluginTool tool = getState().getTool();
28+
GraphDisplayBroker service = tool.getService(GraphDisplayBroker.class);
29+
GraphDisplay display = service.getDefaultGraphDisplay(false, monitor);
30+
Map<Long, AttributedVertex> vertices = new HashMap<>();
31+
32+
AttributedGraph graph = new AttributedGraph();
33+
AttributedVertex typeVertex = graph.addVertex(type.getFullName());
34+
vertices.put(type.getClassDataTypeId(), typeVertex);
35+
36+
Set<Long> subtypes = new HashSet<>();
37+
subtypes.add(type.getClassDataTypeId());
38+
39+
while (!subtypes.isEmpty()) {
40+
Set<Long> currentParents = new HashSet<>(subtypes);
41+
subtypes.clear();
42+
43+
for (ClassTypeInfoDB candidate : currentManager.getTypes()) {
44+
for (ClassTypeInfoDB parent : candidate.getParentModels()) {
45+
if (monitor.isCancelled()) {
46+
return;
47+
}
48+
49+
long parentId = parent.getClassDataTypeId();
50+
51+
if (currentParents.contains(parentId)) {
52+
subtypes.add(candidate.getClassDataTypeId());
53+
AttributedVertex vertex = graph.addVertex(candidate.getFullName());
54+
55+
vertices.put(candidate.getClassDataTypeId(), vertex);
56+
graph.addEdge(vertices.get(parentId), vertex);
57+
}
58+
}
59+
}
60+
}
61+
62+
Deque<ClassTypeInfoDB> supertypes = new ArrayDeque<>();
63+
supertypes.push(type);
64+
65+
while (!supertypes.isEmpty()) {
66+
ClassTypeInfoDB supertype = supertypes.pop();
67+
AttributedVertex vertex = vertices.computeIfAbsent(supertype.getClassDataTypeId(),
68+
(key) -> new AttributedVertex(supertype.getFullName()));
69+
70+
for (ClassTypeInfoDB parent : supertype.getParentModels()) {
71+
if (monitor.isCancelled()) {
72+
return;
73+
}
74+
75+
AttributedVertex parentVertex = vertices.computeIfAbsent(parent.getClassDataTypeId(),
76+
(key) -> new AttributedVertex(parent.getFullName()));
77+
78+
supertypes.push(parent);
79+
graph.addEdge(parentVertex, vertex);
80+
}
81+
}
82+
83+
display.setGraph(graph, "Class Tree", false, monitor);
84+
display.selectVertices(Set.of(typeVertex), EventTrigger.MODEL_CHANGE);
85+
}
86+
}

0 commit comments

Comments
 (0)