void ClassHierarchyUtils::findClassHierarchy(Module& M) { // extract call hierarchy using std::type_info structures rather // than debug info. The former works even for when there are anonymous // namespaces. type_info structs can be obtained from vtable globals. // (for more info, see http://mentorembedded.github.io/cxx-abi/abi.html) for (Module::global_iterator I=M.global_begin(), E=M.global_end(); I != E; I++) { GlobalVariable* G = &*I; if (G->getName().startswith("_ZTV")) { if (G->hasInitializer()) { SDEBUG("soaap.util.classhierarchy", 3, G->dump()); ConstantArray* Ginit = cast<ConstantArray>(G->getInitializer()); // Ginit[1] is the type_info global for this vtable's type bool typeInfoFound = false; bool primaryVTable = true; for (int i=0; i<Ginit->getNumOperands(); i++) { // typeinfo will be the first global variable in the array. // It's not always at a fixed index so we have to search for it... if (GlobalVariable* TI = dyn_cast<GlobalVariable>(Ginit->getOperand(i)->stripPointerCasts())) { //TI->dump(); typeInfoToVTable[TI] = G; vTableToTypeInfo[G] = TI; processTypeInfo(TI); // process TI recursively (it contains refs to super-class TIs) typeInfoFound = true; if (primaryVTable) { primaryVTable = false; vTableToSecondaryVTableMaps[G][0] = i+1; // i+1 is also the size of the vtable header } else { // offset_to_top is at the previous index ConstantExpr* offsetValCast = cast<ConstantExpr>(Ginit->getOperand(i-1)->stripPointerCasts()); ConstantInt* offsetVal = cast<ConstantInt>(offsetValCast->getOperand(0)); int offsetToTop = offsetVal->getSExtValue(); if (offsetToTop > 0) { dbgs() << "ERROR: offsetToTop is positive!\n"; G->dump(); } else { offsetToTop *= -1; } SDEBUG("soaap.util.classhierarchy", 3, dbgs() << "offsetToTop: " << offsetToTop << "\n"); vTableToSecondaryVTableMaps[G][offsetToTop] = i+1; } } } if (!typeInfoFound) { dbgs() << "ERROR: vtable initializer is not a global variable...\n"; dbgs() << *G << " = " << *Ginit << "\n"; } } } } SDEBUG("soaap.util.classhierarchy", 3, ppClassHierarchy(classToSubclasses)); }