Skip to content

Commit 398126e

Browse files
author
astrelsky
committed
Improved GccRttiAnalyzer performance
1 parent f33fe63 commit 398126e

File tree

13 files changed

+246
-99
lines changed

13 files changed

+246
-99
lines changed

src/main/java/cppclassanalyzer/analysis/cmd/AbstractCppClassAnalyzer.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ private void repairInheritance() throws CancelledException, InvalidDataTypeExcep
137137
}
138138
}
139139
// this takes care of everything
140-
type.getClassDataType();
140+
try {
141+
type.getClassDataType();
142+
} catch (Exception e) {
143+
log.appendException(e);
144+
}
141145
monitor.incrementProgress(1);
142146
}
143147
}

src/main/java/cppclassanalyzer/data/ProgramClassTypeInfoManager.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import ghidra.app.cmd.data.rtti.TypeInfo;
66
import ghidra.app.cmd.data.rtti.Vtable;
77
import ghidra.app.cmd.data.rtti.gcc.UnresolvedClassTypeInfoException;
8+
import ghidra.app.util.importer.MessageLog;
89
import ghidra.framework.model.DomainObjectListener;
910

1011
import cppclassanalyzer.data.typeinfo.ArchivedClassTypeInfo;
@@ -120,7 +121,7 @@ default Stream<ClassTypeInfoDB> getTypeStream() {
120121
* @param monitor the TaskMonitor used to monitor the progress
121122
* @throws CancelledException if the task is cancelled
122123
*/
123-
void findVtables(TaskMonitor monitor) throws CancelledException;
124+
void findVtables(TaskMonitor monitor, MessageLog log) throws CancelledException;
124125

125126
/**
126127
* Returns a ClassTypeInfo that is managed by this ClassTypeInfoManager.

src/main/java/cppclassanalyzer/data/manager/ClassTypeInfoManagerDB.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import ghidra.app.cmd.data.rtti.*;
1515
import ghidra.app.cmd.data.rtti.gcc.GnuUtils;
1616
import ghidra.app.plugin.prototype.MicrosoftCodeAnalyzerPlugin.PEUtil;
17+
import ghidra.app.util.importer.MessageLog;
18+
1719
import cppclassanalyzer.plugin.typemgr.node.TypeInfoTreeNodeManager;
1820
import cppclassanalyzer.vs.RttiModelWrapper;
1921
import cppclassanalyzer.vs.VsClassTypeInfo;
@@ -624,21 +626,39 @@ private Stream<ClassTypeInfoRecord> getRecordStream(ClassTypeInfoRecord[] record
624626
}
625627

626628
@Override
627-
public void findVtables(TaskMonitor monitor) throws CancelledException {
629+
public void findVtables(TaskMonitor monitor, MessageLog log) throws CancelledException {
628630
TaskMonitor dummy = new CancelOnlyWrappingTaskMonitor(monitor);
629631
sort(monitor);
630632
monitor.initialize(getTypeCount());
631633
monitor.setMessage("Finding vtables");
632634
TypeInfoArchiveChangeRecord changeRecord = null;
633635
for (ClassTypeInfoDB type : getTypes(true)) {
634636
monitor.checkCanceled();
635-
type.findVtable(dummy);
636-
changeRecord = new TypeInfoArchiveChangeRecord(ChangeType.TYPE_UPDATED, type);
637-
plugin.managerChanged(changeRecord);
637+
try {
638+
type.findVtable(dummy);
639+
changeRecord = new TypeInfoArchiveChangeRecord(ChangeType.TYPE_UPDATED, type);
640+
plugin.managerChanged(changeRecord);
641+
} catch (CancelledException e) {
642+
throw e;
643+
} catch (Exception e) {
644+
if (log != null) {
645+
log.appendMsg(e.getMessage());
646+
}
647+
}
638648
monitor.incrementProgress(1);
639649
}
640650
}
641651

652+
private boolean isValidRecord(ClassTypeInfoRecord record) {
653+
try {
654+
AbstractClassTypeInfoDB.getBaseCount(record);
655+
return true;
656+
} catch (Exception e) {
657+
// record is incomplete and will be removed
658+
}
659+
return false;
660+
}
661+
642662
private void sort(TaskMonitor monitor) throws CancelledException {
643663
lock.acquire();
644664
try {
@@ -650,13 +670,16 @@ private void sort(TaskMonitor monitor) throws CancelledException {
650670
}
651671
ClassTypeInfoRecord[] records = getClassRecords();
652672
Map<Long, ReferenceCounter> keys = getRecordStream(records)
673+
.filter(this::isValidRecord)
653674
.map(ReferenceCounter::new)
654675
.collect(Collectors.toMap(ReferenceCounter::getKey, r -> r));
655676
for (ClassTypeInfoRecord record : records) {
656677
monitor.checkCanceled();
657-
long[] baseKeys = AbstractClassTypeInfoDB.getBaseKeys(record);
658-
for (long key : baseKeys) {
659-
keys.get(key).referencesFrom.getAndIncrement();
678+
if (keys.containsKey(record.getKey())) {
679+
long[] baseKeys = AbstractClassTypeInfoDB.getBaseKeys(record);
680+
for (long key : baseKeys) {
681+
keys.get(key).referencesFrom.getAndIncrement();
682+
}
660683
}
661684
}
662685
long[] newKeys = keys.values()
@@ -722,6 +745,9 @@ private void rebuildTable(long[] newKeys, TaskMonitor monitor) throws CancelledE
722745
while (iter.hasNext()) {
723746
monitor.checkCanceled();
724747
ClassTypeInfoRecord oldRecord = iter.next();
748+
if (!keyMap.contains(oldRecord.getKey())) {
749+
continue;
750+
}
725751
ClassTypeInfoRecord record = oldRecord.copy();
726752
record.setKey(keyMap.get(record.getKey()));
727753
if (record.getBooleanValue(ClassTypeInfoSchemaFields.VTABLE_SEARCHED)) {

src/main/java/cppclassanalyzer/data/typeinfo/GnuClassTypeInfoDB.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ public GnuClassTypeInfoDB(ProgramRttiRecordManager worker, ArchivedClassTypeInfo
6060
this.baseKeys = extractKeys(aMan, type.getBaseKeys());
6161
this.baseOffsets = type.getBaseOffsetValues();
6262
fillRecord(record);
63+
setVtableSearched();
64+
Vtable vtable = type.getVtable();
65+
if (Vtable.isValid(vtable)) {
66+
vtable = worker.resolve(vtable);
67+
setVtable(vtable);
68+
}
6369
}
6470

6571
private long[] extractKeys(ClassTypeInfoManager aMan, long[] keys) {

src/main/java/cppclassanalyzer/data/vtable/VtableModelDB.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ private Function[] getFunctions() {
185185
Listing listing = getProgram().getListing();
186186
return Arrays.stream(functions)
187187
.mapToObj(typeManager::decodeAddress)
188-
.map(listing::getFunctionAt)
188+
.map(listing::getFunctionContaining)
189189
.toArray(Function[]::new);
190190
}
191191

src/main/java/cppclassanalyzer/plugin/typemgr/node/AbstractSingleManagerNode.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import ghidra.app.util.SymbolPath;
1414
import ghidra.util.Msg;
15-
import ghidra.util.exception.AssertException;
1615
import ghidra.util.exception.CancelledException;
1716
import ghidra.util.task.TaskMonitor;
1817

@@ -121,10 +120,9 @@ public final TypeInfoNode getNode(ClassTypeInfoDB type) {
121120
addNode(type);
122121
}
123122
GTreeNode node = treePaths.get(path);
124-
if (node instanceof TypeInfoNode) {
125-
return (TypeInfoNode) node;
123+
if (node instanceof NamespacePathNode) {
124+
node = new TypeInfoNode(type, (NamespacePathNode) node);
126125
}
127-
// should be unreachable
128-
throw new AssertException("Node for "+type.getName()+" is not the correct node type");
126+
return (TypeInfoNode) node;
129127
}
130128
}

src/main/java/cppclassanalyzer/script/CppClassAnalyzerGhidraScript.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ public abstract class CppClassAnalyzerGhidraScript extends GhidraScript {
2020
@Override
2121
protected void loadPropertiesFile() throws IOException {
2222
super.loadPropertiesFile();
23-
ClassTypeInfoManagerService service =
24-
state.getTool().getService(ClassTypeInfoManagerService.class);
25-
this.currentManager = service.getManager(currentProgram);
23+
this.currentManager = getService().getManager(currentProgram);
2624
}
2725

2826
/**
@@ -34,6 +32,10 @@ protected final DemangledObject demangle(String mangled) {
3432
return DemanglerUtil.demangle(currentProgram, mangled);
3533
}
3634

35+
/**
36+
* Gets the ClassTypeInfoManagerService
37+
* @return the ClassTypeInfoManagerService
38+
*/
3739
protected final ClassTypeInfoManagerService getService() {
3840
return state.getTool().getService(ClassTypeInfoManagerService.class);
3941
}

src/main/java/ghidra/app/cmd/data/rtti/gcc/ClassTypeInfoUtils.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import cppclassanalyzer.data.typeinfo.GnuClassTypeInfoDB;
99
import cppclassanalyzer.data.typeinfo.AbstractClassTypeInfoDB.TypeId;
1010
import cppclassanalyzer.utils.CppClassAnalyzerUtils;
11+
import util.CollectionUtils;
12+
1113
import ghidra.app.cmd.data.rtti.ClassTypeInfo;
1214
import ghidra.app.cmd.data.rtti.GnuVtable;
1315
import ghidra.app.cmd.data.rtti.Vtable;
@@ -25,9 +27,7 @@
2527
import ghidra.program.model.mem.MemBuffer;
2628
import ghidra.program.model.mem.Memory;
2729
import ghidra.program.model.scalar.Scalar;
28-
import ghidra.program.model.symbol.Namespace;
29-
import ghidra.program.model.symbol.Symbol;
30-
import ghidra.program.model.symbol.SymbolTable;
30+
import ghidra.program.model.symbol.*;
3131
import ghidra.util.Msg;
3232
import ghidra.util.exception.*;
3333
import ghidra.util.task.TaskMonitor;
@@ -74,19 +74,20 @@ public static Vtable findVtable(Program program, ClassTypeInfo type, TaskMonitor
7474
throws CancelledException {
7575
SymbolTable table = program.getSymbolTable();
7676
Listing listing = program.getListing();
77-
for (Symbol symbol : table.getChildren(type.getNamespace().getSymbol())) {
78-
if (symbol.getName().equals(VtableModel.SYMBOL_NAME)) {
79-
try {
80-
return new VtableModel(program, symbol.getAddress(), type);
81-
} catch (InvalidDataTypeException e) {
82-
break;
83-
}
77+
List<Symbol> symbols =
78+
table.getSymbols(VtableModel.SYMBOL_NAME, type.getNamespace());
79+
for (Symbol symbol : symbols) {
80+
try {
81+
return new VtableModel(program, symbol.getAddress(), type);
82+
} catch (InvalidDataTypeException e) {
83+
break;
8484
}
8585
}
8686
Set<Address> references = Collections.emptySet();
8787
Data tiData = listing.getDataAt(type.getAddress());
8888
if (tiData != null) {
89-
references = Arrays.stream(XReferenceUtil.getXRefList(tiData))
89+
references = CollectionUtils.asStream(tiData.getReferenceIteratorTo())
90+
.map(Reference::getFromAddress)
9091
.filter(Predicate.not(SpecialAddress.class::isInstance))
9192
.collect(Collectors.toSet());
9293
if (!references.isEmpty()) {
@@ -96,8 +97,16 @@ public static Vtable findVtable(Program program, ClassTypeInfo type, TaskMonitor
9697
}
9798
}
9899
}
99-
references = GnuUtils.getDirectDataReferences(program, type.getAddress());
100-
return getValidVtable(program, references, monitor, type);
100+
if (type.getName().contains("type_info")) {
101+
references = GnuUtils.getDirectDataReferences(program, type.getAddress());
102+
if (!references.isEmpty()) {
103+
Vtable vtable = getValidVtable(program, references, monitor, type);
104+
if (Vtable.isValid(vtable)) {
105+
return vtable;
106+
}
107+
}
108+
}
109+
return Vtable.NO_VTABLE;
101110
}
102111

103112
private static boolean invalidData(Data data) {

src/main/java/ghidra/app/cmd/data/rtti/gcc/TypeInfoUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ public static String getIDString(Program program, Address address) {
186186
RelocationTable table = program.getRelocationTable();
187187
Relocation reloc = table.getRelocation(address);
188188
if (reloc != null && reloc.getSymbolName() != null) {
189+
if (reloc.getSymbolName().startsWith(VtableModel.MANGLED_PREFIX)) {
190+
return reloc.getSymbolName().substring(VtableModel.MANGLED_PREFIX.length());
191+
}
189192
Address relocationAddress = getAbsoluteAddress(program, address);
190193
if (relocationAddress == null || relocationAddress.getOffset() == 0) {
191194
return "";

src/main/java/ghidra/app/cmd/data/rtti/gcc/VtableUtils.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package ghidra.app.cmd.data.rtti.gcc;
22

33
import java.util.*;
4+
import java.util.function.Predicate;
5+
import java.util.stream.Collectors;
46

57
import cppclassanalyzer.data.ProgramClassTypeInfoManager;
68
import cppclassanalyzer.utils.CppClassAnalyzerUtils;
9+
import util.CollectionUtils;
710

8-
import ghidra.program.model.address.Address;
9-
import ghidra.program.model.address.AddressOverflowException;
10-
import ghidra.program.model.address.AddressRange;
11-
import ghidra.program.model.address.AddressRangeImpl;
11+
import ghidra.program.model.address.*;
1212
import ghidra.program.model.data.Array;
1313
import ghidra.program.model.data.DataType;
1414
import ghidra.program.model.data.DataTypeManager;
@@ -22,8 +22,7 @@
2222
import ghidra.program.model.mem.MemoryAccessException;
2323
import ghidra.program.model.mem.MemoryBufferImpl;
2424
import ghidra.program.model.reloc.Relocation;
25-
import ghidra.program.model.symbol.Symbol;
26-
import ghidra.program.model.symbol.SymbolTable;
25+
import ghidra.program.model.symbol.*;
2726
import ghidra.app.cmd.data.rtti.ClassTypeInfo;
2827
import ghidra.app.cmd.data.rtti.GnuVtable;
2928
import ghidra.app.cmd.data.rtti.Vtable;
@@ -91,6 +90,11 @@ public static int getNumPtrDiffs(Program program, Address address, int maxLength
9190
if (after == null) {
9291
set = new AddressRangeImpl(before.getMaxAddress(), program.getMaxAddress());
9392
} else {
93+
AddressSpace beforeSpace = before.getMaxAddress().getAddressSpace();
94+
AddressSpace afterSpace = after.getAddress().getAddressSpace();
95+
if (!beforeSpace.equals(afterSpace)) {
96+
return 0;
97+
}
9498
set = new AddressRangeImpl(before.getMaxAddress(), after.getAddress());
9599
}
96100
}
@@ -272,11 +276,12 @@ private static Address getFunctionAddress(Program program, Address currentAddres
272276

273277
private static Function createFunction(Program program, Address currentAddress) {
274278
Listing listing = program.getListing();
275-
Function function = listing.getFunctionAt(currentAddress);
279+
// arm lto may do offset pointers
280+
Function function = listing.getFunctionContaining(currentAddress);
276281
if (function != null) {
277282
return function;
278283
}
279-
if (listing.getInstructionAt(currentAddress) == null) {
284+
if (listing.getInstructionContaining(currentAddress) == null) {
280285
// If it has not been disassembled, disassemble it first.
281286
if (program.getMemory().getBlock(currentAddress).isInitialized()) {
282287
DisassembleCommand cmd = new DisassembleCommand(currentAddress, null, true);
@@ -302,7 +307,12 @@ public static VttModel getVttModel(Program program, GnuVtable vtable) {
302307
if (tableAddresses.length == 0) {
303308
return VttModel.INVALID;
304309
}
305-
Set<Address> references = GnuUtils.getDirectDataReferences(program, tableAddresses[0]);
310+
ReferenceManager man = program.getReferenceManager();
311+
Address addr = tableAddresses[0];
312+
Set<Address> references = CollectionUtils.asStream(man.getReferencesTo(addr))
313+
.map(Reference::getFromAddress)
314+
.filter(Predicate.not(SpecialAddress.class::isInstance))
315+
.collect(Collectors.toSet());
306316
if (references.isEmpty()) {
307317
return VttModel.INVALID;
308318
}

0 commit comments

Comments
 (0)