GP-4408 Refactor of FillOutStructureCmd. Added FillOutStructureHelper and additional DecompilerUtils methods.

This commit is contained in:
ghidra1
2024-04-03 09:53:53 -04:00
parent 434c3f315d
commit 624a3c4e9e
25 changed files with 1281 additions and 1810 deletions

View File

@@ -16,56 +16,26 @@
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.*;
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd;
import ghidra.app.plugin.core.decompile.actions.FillOutStructureCmd.OffsetPcodeOpPair;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.decompiler.util.FillOutStructureHelper;
import ghidra.app.decompiler.util.FillOutStructureHelper.OffsetPcodeOpPair;
import ghidra.app.util.opinion.PeLoader;
import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.Category;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeConflictHandler;
import ghidra.program.model.data.IntegerDataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.listing.CircularDependencyException;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.FlowOverride;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.HighVariable;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.util.ProgramLocation;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
@@ -85,7 +55,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
private static final String RTTI_CLASS_HIERARCHY_DESCRIPTOR_DATA_NAME =
"RTTIClassHierarchyDescriptor";
private static final String VFTABLE_META_PTR_LABEL = "vftable_meta_ptr";
private static final String VFTABLE_LABEL = "vftable";
// private static final String VFTABLE_LABEL = "vftable";
private static final String CLASS_VTABLE_STRUCT_NAME = "_vbtable";
private static final String CLASS_VTABLE_PTR_FIELD_EXT = "vftablePtr";
@@ -102,15 +72,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
boolean isPDBLoaded;
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
public RTTIWindowsClassRecoverer(Program program, ServiceProvider serviceProvider,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVFunctions, boolean isPDBLoaded, TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
super(program, serviceProvider, api, createBookmarks, useShortTemplates, nameVFunctions,
isPDBLoaded, monitor);
this.isPDBLoaded = isPDBLoaded;
}
@Override
@@ -241,60 +210,60 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
return false;
}
/**
* Method to determine if the current program has RTTI data applied to it
* @return true if the current program has RTTI data applied to it
* @throws CancelledException if cancelled
*/
private boolean programHasRTTIApplied() throws CancelledException {
// First check to see if the RTTICompleteObjectLocator data type exists. If not there has
// been no RTTI applied
DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT,
RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME);
if (completeObjLocatorDataType == null) {
return false;
}
// Next check that a RTTICompleteObjectLocator has been applied somewhere to make sure that
// we don't have the case where pdb ran and created the data type but rtti didn't run so didn't
// apply any of the data types
return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL,
completeObjLocatorDataType);
}
private void runRTTIAnalyzer() throws Exception {
// Analyzer analyzer = new RttiAnalyzer();
// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor,
// new MessageLog());
}
/**
* Method to find all the vftables in the program
* @return list of all vftable symbols
* @throws CancelledException when cancelled
*/
//TODO: pull into separate methods and check separately above
private boolean hasSymbolAndDataType(String symbolName, DataType datatype)
throws CancelledException {
String pdbName = "`" + symbolName + "'";
SymbolIterator symbols =
program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true);
while (symbols.hasNext()) {
monitor.checkCancelled();
Symbol symbol = symbols.next();
if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) {
Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress());
if (dataAt.getDataType().equals(datatype)) {
return true;
}
}
}
return false;
}
// /**
// * Method to determine if the current program has RTTI data applied to it
// * @return true if the current program has RTTI data applied to it
// * @throws CancelledException if cancelled
// */
// private boolean programHasRTTIApplied() throws CancelledException {
//
// // First check to see if the RTTICompleteObjectLocator data type exists. If not there has
// // been no RTTI applied
// DataType completeObjLocatorDataType = dataTypeManager.getDataType(CategoryPath.ROOT,
// RTTI_BASE_COMPLETE_OBJECT_LOADER_DATA_NAME);
// if (completeObjLocatorDataType == null) {
// return false;
// }
//
// // Next check that a RTTICompleteObjectLocator has been applied somewhere to make sure that
// // we don't have the case where pdb ran and created the data type but rtti didn't run so didn't
// // apply any of the data types
// return hasSymbolAndDataType(RTTI_BASE_COMPLETE_OBJECT_LOADER_LABEL,
// completeObjLocatorDataType);
// }
//
// private void runRTTIAnalyzer() throws Exception {
//// Analyzer analyzer = new RttiAnalyzer();
//// analyzer.added(program, program.getAddressFactory().getAddressSet(), monitor,
//// new MessageLog());
// }
//
// /**
// * Method to find all the vftables in the program
// * @return list of all vftable symbols
// * @throws CancelledException when cancelled
// */
// //TODO: pull into separate methods and check separately above
// private boolean hasSymbolAndDataType(String symbolName, DataType datatype)
// throws CancelledException {
//
// String pdbName = "`" + symbolName + "'";
// SymbolIterator symbols =
// program.getSymbolTable().getSymbolIterator("*" + symbolName + "*", true);
//
// while (symbols.hasNext()) {
// monitor.checkCancelled();
// Symbol symbol = symbols.next();
// if (symbol.getName().equals(symbolName) || symbol.getName().equals(pdbName)) {
// Data dataAt = program.getListing().getDefinedDataAt(symbol.getAddress());
// if (dataAt.getDataType().equals(datatype)) {
// return true;
// }
// }
//
// }
// return false;
// }
public void fixUpRttiAnalysis() throws CancelledException, Exception {
applyMissingRTTIStructures();
@@ -512,10 +481,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<Address> classHierarchyDescriptorAddresses = new ArrayList<Address>();
Iterator<Symbol> baseClassDescriptorIterator = baseClassDescriptors.iterator();
while (baseClassDescriptorIterator.hasNext()) {
for (Symbol symbol : baseClassDescriptors) {
monitor.checkCancelled();
Symbol symbol = baseClassDescriptorIterator.next();
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
symbol.getAddress().add(24), symbol.getParentNamespace());
@@ -526,10 +493,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
Iterator<Symbol> completeObjectLocatorIterator = completeObjectLocators.iterator();
while (completeObjectLocatorIterator.hasNext()) {
for (Symbol symbol : completeObjectLocators) {
monitor.checkCancelled();
Symbol symbol = completeObjectLocatorIterator.next();
Address classHierarchyDescriptorAddress = createClassHierarchyDescriptor(
symbol.getAddress().add(16), symbol.getParentNamespace());
if (classHierarchyDescriptorAddress != null &&
@@ -621,13 +586,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<Address> baseClassArrayAddresses = new ArrayList<Address>();
Iterator<Address> classHierarchyDescriptorIterator = classHierarchyDescriptors.iterator();
while (classHierarchyDescriptorIterator.hasNext()) {
for (Address classHierarchyDescriptorAddress : classHierarchyDescriptors) {
monitor.checkCancelled();
Address classHierarchyDescriptorAddress = classHierarchyDescriptorIterator.next();
Symbol classHierarchyDescriptorSymbol =
symbolTable.getPrimarySymbol(classHierarchyDescriptorAddress);
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
@@ -725,11 +687,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<Symbol> vftables = new ArrayList<Symbol>();
Iterator<Symbol> iterator = completeObjectLocatorSymbols.iterator();
while (iterator.hasNext()) {
for (Symbol completeObjectLocatorSymbol : completeObjectLocatorSymbols) {
monitor.checkCancelled();
Symbol completeObjectLocatorSymbol = iterator.next();
Address completeObjectLocatorAddress = completeObjectLocatorSymbol.getAddress();
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
@@ -903,10 +862,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<Symbol> classHierarchyDescriptorList = getListOfClassHierarchyDescriptors();
Iterator<Symbol> classHierarchyDescriptorIterator = classHierarchyDescriptorList.iterator();
while (classHierarchyDescriptorIterator.hasNext()) {
for (Symbol classHierarchyDescriptorSymbol : classHierarchyDescriptorList) {
monitor.checkCancelled();
Symbol classHierarchyDescriptorSymbol = classHierarchyDescriptorIterator.next();
Address classHierarchyDescriptorAddress = classHierarchyDescriptorSymbol.getAddress();
// Get class name from class vftable is in
@@ -1000,16 +957,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
PointerDataType pointerDataType = new PointerDataType();
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
Iterator<Address> vftableIterator = vftableAddresses.iterator();
while (vftableIterator.hasNext()) {
for (Address vftableAddress : vftableAddresses) {
monitor.checkCancelled();
Address vftableAddress = vftableIterator.next();
Address ptrToColAddress = vftableAddress.subtract(defaultPointerSize);
Data pointerToCompleteObjLocator = extendedFlatAPI.getDataAt(vftableAddress);
@@ -1396,12 +1348,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
private void determineParentClassInfoFromBaseClassArray(List<RecoveredClass> recoveredClasses)
throws Exception {
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
boolean hasVirtualAncestor = false;
int vbaseOffset = NONE;
@@ -1531,22 +1480,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
}
Iterator<Function> constructorIterator = constructorList.iterator();
while (constructorIterator.hasNext()) {
DecompileOptions decompileOptions =
DecompilerUtils.getDecompileOptions(serviceProvider, program);
FillOutStructureHelper fillStructHelper =
new FillOutStructureHelper(program, decompileOptions, monitor);
for (Function constructor : constructorList) {
monitor.checkCancelled();
Function constructor = constructorIterator.next();
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
if (highFunction == null) {
continue;
}
FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool);
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction,
recoveredClass, constructor, vbtableOffset);
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper,
highFunction, recoveredClass, constructor, vbtableOffset);
if (vbtableAddress != null) {
return vbtableAddress;
@@ -1561,22 +1510,17 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
}
Iterator<Function> indeterminateIterator = indeterminateList.iterator();
while (indeterminateIterator.hasNext()) {
for (Function constructor : indeterminateList) {
monitor.checkCancelled();
Function constructor = indeterminateIterator.next();
HighFunction highFunction = decompilerUtils.getHighFunction(constructor);
if (highFunction == null) {
continue;
}
FillOutStructureCmd fillCmd = new FillOutStructureCmd(program, location, tool);
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillCmd, highFunction,
recoveredClass, constructor, vbtableOffset);
Address vbtableAddress = getVbtableAddressFromDecompiledFunction(fillStructHelper,
highFunction, recoveredClass, constructor, vbtableOffset);
if (vbtableAddress != null) {
return vbtableAddress;
@@ -1589,7 +1533,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
/**
* Method to find the address of the vbtable referenced at the given offset in the given function
* @param fillCmd the decompiler's filled out structure for a particular variable
* @param fillStructHelper a reusable {@link FillOutStructureHelper} instance to be used
* with decompiler for a particular variable
* @param highFunction the high function for the given function
* @param recoveredClass the given class
* @param function the given function
@@ -1597,7 +1542,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @return the address of the found vbtable or null if none is found
* @throws CancelledException if cancelled
*/
private Address getVbtableAddressFromDecompiledFunction(FillOutStructureCmd fillCmd,
private Address getVbtableAddressFromDecompiledFunction(FillOutStructureHelper fillStructHelper,
HighFunction highFunction, RecoveredClass recoveredClass, Function function, int offset)
throws CancelledException {
@@ -1619,22 +1564,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
}
Iterator<HighVariable> highVariableIterator = highVariables.iterator();
for (HighVariable highVariable : highVariables) {
while (highVariableIterator.hasNext()) {
HighVariable highVariable = highVariableIterator.next();
monitor.checkCancelled();
fillCmd.processStructure(highVariable, function);
List<OffsetPcodeOpPair> stores = fillCmd.getStorePcodeOps();
fillStructHelper.processStructure(highVariable, function, true, false);
List<OffsetPcodeOpPair> stores = fillStructHelper.getStorePcodeOps();
stores = removePcodeOpsNotInFunction(function, stores);
// this method checks the storedPcodeOps to see if one is a vftable address
Iterator<OffsetPcodeOpPair> iterator = stores.iterator();
while (iterator.hasNext()) {
for (OffsetPcodeOpPair offsetPcodeOpPair : stores) {
monitor.checkCancelled();
OffsetPcodeOpPair offsetPcodeOpPair = iterator.next();
int pcodeOffset = offsetPcodeOpPair.getOffset().intValue();
if (pcodeOffset == offset) {
@@ -1664,11 +1603,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
private void assignParentClassToVftables(List<RecoveredClass> recoveredClasses)
throws Exception {
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
for (RecoveredClass recoveredClass : recoveredClasses) {
monitor.checkCancelled();
RecoveredClass recoveredClass = recoveredClassIterator.next();
if (!recoveredClass.hasVftable()) {
continue;
}
@@ -1726,10 +1662,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// iterate over the hierarchy list and use it to get the order of the parentsParents and assign
// to correct vftable
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
Iterator<RecoveredClass> classHierarchyIterator = classHierarchy.iterator();
while (classHierarchyIterator.hasNext()) {
for (RecoveredClass ancestor : classHierarchy) {
monitor.checkCancelled();
RecoveredClass ancestor = classHierarchyIterator.next();
if (grandParents.contains(ancestor)) {
Integer index = sortedOrder.get(order);
Address vftableAddress = orderToVftableMap.get(index);
@@ -1817,12 +1751,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<RecoveredClass> classHierarchy = recoveredClass.getClassHierarchy();
Iterator<RecoveredClass> hierarchyIterator = classHierarchy.iterator();
while (hierarchyIterator.hasNext()) {
for (RecoveredClass ancestorClass : classHierarchy) {
monitor.checkCancelled();
RecoveredClass ancestorClass = hierarchyIterator.next();
RecoveredClass firstVirtuallyInheritedAncestorWithVfunctions =
getVirtuallyInheritedParentWithVfunctions(ancestorClass);
if (firstVirtuallyInheritedAncestorWithVfunctions != null) {
@@ -1857,11 +1787,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
Map<RecoveredClass, Boolean> parentToBaseTypeMap = recoveredClass.getParentToBaseTypeMap();
List<RecoveredClass> parents = new ArrayList<RecoveredClass>(classHierarchyMap.keySet());
Iterator<RecoveredClass> parentIterator = parents.iterator();
while (parentIterator.hasNext()) {
for (RecoveredClass parent : parents) {
monitor.checkCancelled();
RecoveredClass parent = parentIterator.next();
Boolean isVirtuallyInherited = parentToBaseTypeMap.get(parent);
if (isVirtuallyInherited != null && isVirtuallyInherited && parent.hasVftable()) {
@@ -1898,10 +1825,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
return;
}
Iterator<Integer> orderIterator = sortedOrder.iterator();
while (orderIterator.hasNext()) {
for (Integer order : sortedOrder) {
monitor.checkCancelled();
Integer order = orderIterator.next();
Address vftableAddress = orderToVftableMap.get(order);
RecoveredClass parentClass = parentOrderMap.get(order);
recoveredClass.addVftableToBaseClassMapping(vftableAddress, parentClass);
@@ -1970,13 +1895,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
return parentOrderMap;
}
Iterator<Function> functionIterator = functionList.iterator();
while (functionIterator.hasNext()) {
for (Function function : functionList) {
monitor.checkCancelled();
Function function = functionIterator.next();
parentOrderMap = new HashMap<Integer, RecoveredClass>();
Map<Address, RecoveredClass> referenceToParentMap =
@@ -1986,12 +1908,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
new HashMap<Address, RecoveredClass>();
List<Address> classReferences = new ArrayList<Address>(referenceToParentMap.keySet());
Iterator<Address> classReferenceIterator = classReferences.iterator();
while (classReferenceIterator.hasNext()) {
for (Address classReferenceAddress : classReferences) {
monitor.checkCancelled();
Address classReferenceAddress = classReferenceIterator.next();
// if the address refers to a vftable and that vftable is in the current class then it is not a parent class so do not add to map
Address possibleVftable = getVftableAddress(classReferenceAddress);
@@ -2029,11 +1948,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
Collections.sort(parentReferences, Collections.reverseOrder());
}
// iterate over the ordered parents and add to the order to parent map
Iterator<Address> parentRefIterator = parentReferences.iterator();
while (parentRefIterator.hasNext()) {
// iterate over the ordered parents and add the order to the parent map
for (Address refAddress : parentReferences) {
monitor.checkCancelled();
Address refAddress = parentRefIterator.next();
RecoveredClass parentClass = referenceToParentMap.get(refAddress);
parentOrderMap.put(order, parentClass);
order++;
@@ -2074,11 +1991,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
List<RecoveredClass> updatedParentClasses = new ArrayList<RecoveredClass>(parentClasses);
// now iterate over the direct parents and map that parent to each ancestor on the ancestor with vfunction list
Iterator<RecoveredClass> parentIterator = parentClasses.iterator();
while (parentIterator.hasNext()) {
for (RecoveredClass parentClass : parentClasses) {
monitor.checkCancelled();
RecoveredClass parentClass = parentIterator.next();
List<RecoveredClass> ancestors =
new ArrayList<RecoveredClass>(parentClass.getClassHierarchy());
ancestors.remove(parentClass);
@@ -2088,12 +2003,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
Iterator<RecoveredClass> ancestorIterator = ancestors.iterator();
while (ancestorIterator.hasNext()) {
for (RecoveredClass ancestor : ancestors) {
monitor.checkCancelled();
RecoveredClass ancestor = ancestorIterator.next();
List<RecoveredClass> decendentList = ancestorToCommonChild.get(ancestor);
if (decendentList == null) {
List<RecoveredClass> newDecendentList = new ArrayList<RecoveredClass>();
@@ -2119,10 +2031,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// now iterate over the ancestor map and update the parent list by adding any ancestor
// that has common parents and removing those parents from the list
Iterator<RecoveredClass> ancestorsIterator = keySet.iterator();
while (ancestorsIterator.hasNext()) {
for (RecoveredClass ancestor : keySet) {
monitor.checkCancelled();
RecoveredClass ancestor = ancestorsIterator.next();
List<RecoveredClass> commonChildList = ancestorToCommonChild.get(ancestor);
if (commonChildList != null && commonChildList.size() >= 2) {
if (!updatedParentClasses.contains(ancestor)) {