diff --git a/oi/Features.cpp b/oi/Features.cpp index 644e7ce..4780e86 100644 --- a/oi/Features.cpp +++ b/oi/Features.cpp @@ -45,4 +45,10 @@ const char* featureToStr(Feature f) { } } +FeatureSet::FeatureSet(std::initializer_list features) { + for (auto f : features) { + (*this)[f] = true; + } +} + } // namespace ObjectIntrospection diff --git a/oi/Features.h b/oi/Features.h index c1a6f16..62ad7c0 100644 --- a/oi/Features.h +++ b/oi/Features.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #define OI_FEATURE_LIST \ @@ -43,4 +44,23 @@ constexpr std::array allFeatures = { #undef X }; +class FeatureSet { + private: + using BitsetType = std::bitset; + + public: + FeatureSet() = default; + FeatureSet(std::initializer_list); + + constexpr bool operator[](Feature f) const { + return bitset[(size_t)f]; + } + BitsetType::reference operator[](Feature f) { + return bitset[(size_t)f]; + } + + private: + BitsetType bitset; +}; + } // namespace ObjectIntrospection diff --git a/oi/OICodeGen.cpp b/oi/OICodeGen.cpp index 9aa5e16..ac494f8 100644 --- a/oi/OICodeGen.cpp +++ b/oi/OICodeGen.cpp @@ -62,13 +62,6 @@ std::unique_ptr OICodeGen::buildFromConfig(const Config& c, OICodeGen::OICodeGen(const Config& c, SymbolService& s) : config{c}, symbols{s} { - chaseRawPointers = config.features.contains(Feature::ChaseRawPointers); - packStructs = config.features.contains(Feature::PackStructs); - genPaddingStats = config.features.contains(Feature::GenPaddingStats); - captureThriftIsset = config.features.contains(Feature::CaptureThriftIsset); - polymorphicInheritance = - config.features.contains(Feature::PolymorphicInheritance); - // TODO: Should folly::Range just be added as a container? auto typesToStub = std::array{ "SharedMutex", @@ -998,7 +991,7 @@ bool OICodeGen::recordChildren(drgn_type* type) { * types in the program to build the reverse mapping. */ bool OICodeGen::enumerateChildClasses() { - if (!polymorphicInheritance) { + if (!feature(Feature::PolymorphicInheritance)) { return true; } @@ -1327,7 +1320,8 @@ bool OICodeGen::isEmptyClassOrFunctionType(drgn_type* type, * one or more virtual member functions or virtual base classes). */ bool OICodeGen::isDynamic(drgn_type* type) const { - if (!polymorphicInheritance || !drgn_type_has_virtuality(type)) { + if (!feature(Feature::PolymorphicInheritance) || + !drgn_type_has_virtuality(type)) { return false; } @@ -2008,7 +2002,7 @@ bool OICodeGen::getDrgnTypeNameInt(drgn_type* type, std::string& outName) { name.assign(drgn_type_name(type)); } else if (drgn_type_kind(type) == DRGN_TYPE_POINTER) { drgn_type* underlyingType = getPtrUnderlyingType(type); - if (chaseRawPointers && + if (feature(Feature::ChaseRawPointers) && drgn_type_kind(underlyingType) != DRGN_TYPE_FUNCTION) { // For pointers, figure out name for the underlying type then add // appropriate number of '*' @@ -2278,7 +2272,7 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) { std::string structDefinition; - if (paddingInfo.paddingSize != 0 && genPaddingStats) { + if (paddingInfo.paddingSize != 0 && feature(Feature::GenPaddingStats)) { structDefinition.append("/* offset | size */ "); } @@ -2294,7 +2288,8 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) { std::to_string(*alignment / CHAR_BIT) + ")"); } - if (packStructs && (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_CLASS) && + if (feature(Feature::PackStructs) && + (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_CLASS) && violatesAlignmentRequirement && paddingInfo.paddingSize == 0) { structDefinition.append(" __attribute__((__packed__))"); } @@ -2313,7 +2308,7 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) { structDefinition.append("};\n"); - if (genPaddingStats) { + if (feature(Feature::GenPaddingStats)) { auto paddedStructFound = paddedStructs.find(*tmpStr); if (paddedStructFound == paddedStructs.end()) { @@ -2509,7 +2504,8 @@ std::optional OICodeGen::generateMember( currOffsetBits = 0; VLOG(1) << "Member size: " << memberSize; } else { - addSizeComment(genPaddingStats, code, currOffsetBits, memberSize); + addSizeComment(feature(Feature::GenPaddingStats), code, currOffsetBits, + memberSize); currOffsetBits = currOffsetBits + memberSize; } @@ -2709,12 +2705,12 @@ bool OICodeGen::generateStructMembers( bool isThriftIssetStruct = typeName.starts_with("isset_bitset<") && memberName == "__isset"; - if (captureThriftIsset && isThriftIssetStruct && + if (feature(Feature::CaptureThriftIsset) && isThriftIssetStruct && memberIndex == members.size() - 1) { thriftIssetStructTypes.insert(e); } - if (genPaddingStats) { + if (feature(Feature::GenPaddingStats)) { paddingInfo.isThriftStruct = isThriftIssetStruct; /* @@ -3258,12 +3254,12 @@ bool OICodeGen::generateJitCode(std::string& code) { functionsCode.append("namespace OIInternal {\nnamespace {\n"); functionsCode.append("// functions -----\n"); if (!funcGen.DeclareGetSizeFuncs(functionsCode, containerTypesFuncDef, - chaseRawPointers)) { + feature(Feature::ChaseRawPointers))) { LOG(ERROR) << "declaring get size for containers failed"; return false; } - if (chaseRawPointers) { + if (feature(Feature::ChaseRawPointers)) { functionsCode.append(R"( template void getSizeType(const T* t, size_t& returnArg); @@ -3284,7 +3280,7 @@ bool OICodeGen::generateJitCode(std::string& code) { } } - if (config.useDataSegment || chaseRawPointers) { + if (config.useDataSegment || feature(Feature::ChaseRawPointers)) { funcGen.DeclareStoreData(functionsCode); } @@ -3296,12 +3292,12 @@ bool OICodeGen::generateJitCode(std::string& code) { } if (!funcGen.DefineGetSizeFuncs(functionsCode, containerTypesFuncDef, - chaseRawPointers)) { + feature(Feature::ChaseRawPointers))) { LOG(ERROR) << "defining get size for containers failed"; return false; } - if (chaseRawPointers) { + if (feature(Feature::ChaseRawPointers)) { functionsCode.append(R"( template void getSizeType(const T* s_ptr, size_t& returnArg) @@ -3780,7 +3776,7 @@ std::vector OICodeGen::Config::toOptions() const { options.reserve(allFeatures.size()); for (const auto f : allFeatures) { - if (features.contains(f)) { + if (features[f]) { options.emplace_back(std::string("-f") + featureToStr(f)); } else { options.emplace_back(std::string("-F") + featureToStr(f)); diff --git a/oi/OICodeGen.h b/oi/OICodeGen.h index 0e3a9bf..9c47072 100644 --- a/oi/OICodeGen.h +++ b/oi/OICodeGen.h @@ -57,7 +57,7 @@ class OICodeGen { */ bool useDataSegment; - std::set features{}; + FeatureSet features{}; std::set containerConfigPaths{}; std::set defaultHeaders{}; @@ -113,12 +113,6 @@ class OICodeGen { Config config{}; FuncGen funcGen; - bool chaseRawPointers; - bool packStructs; - bool genPaddingStats; - bool captureThriftIsset; - bool polymorphicInheritance; - using ContainerTypeMapEntry = std::pair, std::vector>; @@ -185,6 +179,9 @@ class OICodeGen { std::unique_ptr _data; }; + bool feature(Feature f) const { + return config.features[f]; + } static void prependQualifiers(enum drgn_qualifiers, std::string& sb); static std::string stripFullyQualifiedName( const std::string& fullyQualifiedName); diff --git a/oi/OIDebugger.cpp b/oi/OIDebugger.cpp index 82072f0..794904c 100644 --- a/oi/OIDebugger.cpp +++ b/oi/OIDebugger.cpp @@ -2852,7 +2852,7 @@ bool OIDebugger::processTargetData() { const auto& [rootType, typeHierarchy, paddingInfos] = typeInfo->second; VLOG(1) << "Root type addr: " << (void*)rootType.type.type; - if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) { + if (treeBuilderConfig.features[Feature::GenPaddingStats]) { paddingHunter.localPaddedStructs = paddingInfos; typeTree.setPaddedStructs(&paddingHunter.localPaddedStructs); } @@ -2876,7 +2876,7 @@ bool OIDebugger::processTargetData() { continue; } - if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) { + if (treeBuilderConfig.features[Feature::GenPaddingStats]) { paddingHunter.processLocalPaddingInfo(); } } @@ -2890,7 +2890,7 @@ bool OIDebugger::processTargetData() { typeTree.dumpJson(); } - if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) { + if (treeBuilderConfig.features[Feature::GenPaddingStats]) { paddingHunter.outputPaddingInfo(); } diff --git a/oi/OIUtils.cpp b/oi/OIUtils.cpp index 0bbd395..cd78b77 100644 --- a/oi/OIUtils.cpp +++ b/oi/OIUtils.cpp @@ -31,7 +31,7 @@ namespace OIUtils { using namespace ObjectIntrospection; using namespace std::literals; -std::optional> processConfigFile( +std::optional processConfigFile( const std::string& configFilePath, std::map featureMap, OICompiler::Config& compilerConfig, @@ -153,10 +153,10 @@ std::optional> processConfigFile( } } - std::set featuresSet; + ObjectIntrospection::FeatureSet featuresSet; for (auto [k, v] : featureMap) { if (v) { - featuresSet.insert(k); + featuresSet[k] = true; } } return featuresSet; diff --git a/oi/OIUtils.h b/oi/OIUtils.h index 5d92fc6..1d0f068 100644 --- a/oi/OIUtils.h +++ b/oi/OIUtils.h @@ -24,7 +24,7 @@ namespace OIUtils { -std::optional> processConfigFile( +std::optional processConfigFile( const std::string& configFilePath, std::map featureMap, OICompiler::Config& compilerConfig, diff --git a/oi/TreeBuilder.cpp b/oi/TreeBuilder.cpp index 400e9f8..23f8fe9 100644 --- a/oi/TreeBuilder.cpp +++ b/oi/TreeBuilder.cpp @@ -53,9 +53,6 @@ enum class TrackPointerTag : uint64_t { TreeBuilder::TreeBuilder(Config c) : config{std::move(c)} { buffer = std::make_unique(); - chaseRawPointers = config.features.contains(Feature::ChaseRawPointers); - genPaddingStats = config.features.contains(Feature::GenPaddingStats); - auto testdbPath = "/tmp/testdb_" + std::to_string(getpid()); if (auto status = rocksdb::DestroyDB(testdbPath, {}); !status.ok()) { LOG(FATAL) << "RocksDB error while destroying database: " @@ -429,7 +426,7 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) { if (!variable.isStubbed) { switch (drgn_type_kind(variable.type)) { case DRGN_TYPE_POINTER: - if (chaseRawPointers) { + if (config.features[Feature::ChaseRawPointers]) { // Pointers to incomplete types are stubbed out // See OICodeGen::enumeratePointerType if (th->knownDummyTypeList.contains(variable.type)) { @@ -544,7 +541,7 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) { break; } - if (genPaddingStats) { + if (config.features[Feature::GenPaddingStats]) { auto entry = paddedStructs->find(node.typeName); if (entry != paddedStructs->end()) { entry->second.instancesCnt++; diff --git a/oi/TreeBuilder.h b/oi/TreeBuilder.h index 28f0636..c0c989c 100644 --- a/oi/TreeBuilder.h +++ b/oi/TreeBuilder.h @@ -41,7 +41,7 @@ class TreeBuilder { struct Config { // Don't set default values for the config so the user gets // an "unitialized field" warning if he missed any. - std::set features; + ObjectIntrospection::FeatureSet features; bool logAllStructs; bool dumpDataSegment; std::optional jsonPath; @@ -69,9 +69,6 @@ class TreeBuilder { const std::vector* oidData = nullptr; std::map* paddedStructs = nullptr; - bool genPaddingStats; - bool chaseRawPointers; - /* * The RocksDB output needs versioning so they are imported correctly in * Scuba. Version 1 had no concept of versioning and no header. diff --git a/tools/OITB.cpp b/tools/OITB.cpp index d71216c..b896fec 100644 --- a/tools/OITB.cpp +++ b/tools/OITB.cpp @@ -120,10 +120,8 @@ static std::ostream& operator<<(std::ostream& out, TreeBuilder::Config tbc) { out << "TreeBuilde::Config = ["; out << "\n logAllStructs = " << tbc.logAllStructs; - out << "\n chaseRawPointers = " - << tbc.features.contains(Feature::ChaseRawPointers); - out << "\n genPaddingStats = " - << tbc.features.contains(Feature::GenPaddingStats); + out << "\n chaseRawPointers = " << tbc.features[Feature::ChaseRawPointers]; + out << "\n genPaddingStats = " << tbc.features[Feature::GenPaddingStats]; out << "\n dumpDataSegment = " << tbc.dumpDataSegment; out << "\n jsonPath = " << (tbc.jsonPath ? *tbc.jsonPath : "NONE"); out << "\n]\n"; @@ -157,10 +155,10 @@ int main(int argc, char* argv[]) { true; // Weird that we're setting it to true, again... break; case 'n': - tbConfig.features.insert(Feature::ChaseRawPointers); + tbConfig.features[Feature::ChaseRawPointers] = true; break; case 'w': - tbConfig.features.erase(Feature::GenPaddingStats); + tbConfig.features[Feature::GenPaddingStats] = false; break; case 'J': tbConfig.jsonPath = optarg ? optarg : "oid_out.json"; @@ -189,7 +187,7 @@ int main(int argc, char* argv[]) { TreeBuilder typeTree(tbConfig); - if (tbConfig.features.contains(Feature::GenPaddingStats)) { + if (tbConfig.features[Feature::GenPaddingStats]) { LOG(INFO) << "Setting-up PaddingHunter..."; typeTree.setPaddedStructs(&paddingInfos); }