diff --git a/src/ccc/symbol_database.cpp b/src/ccc/symbol_database.cpp index 8c826c7..662af50 100644 --- a/src/ccc/symbol_database.cpp +++ b/src/ccc/symbol_database.cpp @@ -240,6 +240,95 @@ SymbolHandle SymbolList::first_handle_from_mangled_name( return iterator->second; } +template +std::vector SymbolList::symbols_from_raw_name(const std::string& raw_name) +{ + std::vector symbols; + std::set> handles; + + // All mangled names are raw names. + std::vector> mangled_name_handles = handles_from_mangled_name(raw_name); + for (SymbolHandle handle : mangled_name_handles) { + SymbolType* symbol = symbol_from_handle(handle); + CCC_ASSERT(symbol); + + symbols.emplace_back(symbol); + handles.emplace(handle); + } + + // Regular names are raw names if the symbol has no mangled name. + std::vector> name_handles = handles_from_name(raw_name); + for (SymbolHandle handle : name_handles) { + if (handles.contains(handle)) { + continue; + } + + SymbolType* symbol = symbol_from_handle(handle); + CCC_ASSERT(symbol); + + if constexpr (SymbolType::FLAGS & MANGLED_NAMES) { + if (!symbol->mangled_name().empty()) { + continue; + } + } + + symbols.emplace_back(symbol); + } + + return symbols; +} + +template +std::vector SymbolList::symbols_from_raw_name(const std::string& raw_name) const +{ + std::vector symbols = const_cast*>(this)->symbols_from_raw_name(raw_name); + + // Make a copy of the vector to add the const. Bit silly. + std::vector copy; + copy.reserve(symbols.size()); + for (const SymbolType* symbol : symbols) { + copy.emplace_back(symbol); + } + + return copy; +} + +template +SymbolType* SymbolList::first_symbol_from_raw_name(const std::string& raw_name) +{ + // All mangled names are raw names. + SymbolHandle mangled_handle = first_handle_from_mangled_name(raw_name); + if (mangled_handle.valid()) { + SymbolType* symbol = symbol_from_handle(mangled_handle); + CCC_ASSERT(symbol); + + return symbol; + } + + // Regular names are raw names if the symbol has no mangled name. + std::vector> name_handles = handles_from_name(raw_name); + for (SymbolHandle handle : name_handles) { + SymbolType* symbol = symbol_from_handle(handle); + CCC_ASSERT(symbol); + + if constexpr (SymbolType::FLAGS & MANGLED_NAMES) { + if (!symbol->mangled_name().empty()) { + continue; + } + } + + return symbol; + } + + return nullptr; +} + +template +const SymbolType* SymbolList::first_symbol_from_raw_name(const std::string& raw_name) const +{ + return const_cast*>(this)->first_symbol_from_raw_name(raw_name); +} + template s32 SymbolList::index_from_handle(SymbolHandle handle) const { @@ -1004,7 +1093,7 @@ const Symbol* SymbolDatabase::symbol_overlapping_address( return nullptr; } -const Symbol* SymbolDatabase::symbol_with_name( +const Symbol* SymbolDatabase::symbol_from_name( const std::string& name, u32 descriptors, SymbolDescriptor* descriptor_out) const { #define CCC_X(SymbolType, symbol_list) \ @@ -1025,6 +1114,26 @@ const Symbol* SymbolDatabase::symbol_with_name( return nullptr; } +const Symbol* SymbolDatabase::symbol_from_raw_name( + const std::string& name, u32 descriptors, SymbolDescriptor* descriptor_out) const +{ +#define CCC_X(SymbolType, symbol_list) \ + if constexpr (SymbolType::FLAGS & WITH_ADDRESS_MAP) { \ + if (descriptors & SymbolType::DESCRIPTOR) { \ + const SymbolType* symbol = symbol_list.first_symbol_from_raw_name(name); \ + if (symbol) { \ + if (descriptor_out) { \ + *descriptor_out = SymbolType::DESCRIPTOR; \ + } \ + return symbol; \ + } \ + } \ + } + CCC_FOR_EACH_SYMBOL_TYPE_DO_X +#undef CCC_X + return nullptr; +} + Result SymbolDatabase::get_symbol_source(const std::string& name) { SymbolSourceHandle handle = symbol_sources.first_handle_from_name(name); diff --git a/src/ccc/symbol_database.h b/src/ccc/symbol_database.h index cde0627..3703736 100644 --- a/src/ccc/symbol_database.h +++ b/src/ccc/symbol_database.h @@ -138,6 +138,12 @@ class SymbolList std::vector> handles_from_mangled_name(const std::string& mangled_name) const; SymbolHandle first_handle_from_mangled_name(const std::string& mangled_name) const; + // Lookup symbols by their raw name, mangled or not. + std::vector symbols_from_raw_name(const std::string& raw_name); + std::vector symbols_from_raw_name(const std::string& raw_name) const; + SymbolType* first_symbol_from_raw_name(const std::string& raw_name); + const SymbolType* first_symbol_from_raw_name(const std::string& raw_name) const; + // Convert handles to underlying array indices. s32 index_from_handle(SymbolHandle handle) const; @@ -667,7 +673,13 @@ class SymbolDatabase // Find a symbol of any of the specified types given its name. Symbols of // the types specified higher up in the CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro // are checked for first. - const Symbol* symbol_with_name( + const Symbol* symbol_from_name( + const std::string& name, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const; + + // Find a symbol of any of the specified types given its raw name. + // Symbols of the types specified higher up in the + // CCC_FOR_EACH_SYMBOL_TYPE_DO_X macro are checked for first. + const Symbol* symbol_from_raw_name( const std::string& name, u32 descriptors = ALL_SYMBOL_TYPES, SymbolDescriptor* descriptor_out = nullptr) const; // Finds a symbol source object with the given name or creates one if it diff --git a/test/ccc/symbol_database_tests.cpp b/test/ccc/symbol_database_tests.cpp index 30fb5c6..076df7e 100644 --- a/test/ccc/symbol_database_tests.cpp +++ b/test/ccc/symbol_database_tests.cpp @@ -263,6 +263,46 @@ TEST(CCCSymbolDatabase, UnmangledSymbolsNotInMangledNameMap) EXPECT_EQ(empty.size(), 0); } +TEST(CCCSymbolDatabase, SymbolsFromRawName) +{ + DemanglerFunctions demangler; + demangler.cplus_demangle = cplus_demangle; + demangler.cplus_demangle_opname = cplus_demangle_opname; + + u32 flags = NO_IMPORTER_FLAGS; + + SymbolDatabase database; + + Result source = database.symbol_sources.create_symbol("Source", SymbolSourceHandle()); + CCC_GTEST_FAIL_IF_ERROR(source); + + Result a = database.functions.create_symbol( + "A", (*source)->handle(), nullptr, Address(), flags, demangler); + CCC_GTEST_FAIL_IF_ERROR(a); + + Result b_1 = database.functions.create_symbol( + "B__Fi", (*source)->handle(), nullptr, Address(), flags, demangler); + CCC_GTEST_FAIL_IF_ERROR(b_1); + + auto functions_1 = database.functions.symbols_from_raw_name("A"); + EXPECT_EQ(functions_1.size(), 1); + + auto functions_2 = database.functions.symbols_from_raw_name("B__Fi"); + EXPECT_EQ(functions_2.size(), 1); + + auto functions_3 = database.functions.symbols_from_raw_name("B(int)"); + EXPECT_EQ(functions_3.size(), 0); + + const Function* function_1 = database.functions.first_symbol_from_raw_name("A"); + EXPECT_TRUE(function_1); + + const Function* function_2 = database.functions.first_symbol_from_raw_name("B__Fi"); + EXPECT_TRUE(function_2); + + const Function* function_3 = database.functions.first_symbol_from_raw_name("B(int)"); + EXPECT_FALSE(function_3); +} + static Result create_function( SymbolDatabase& database, SymbolSourceHandle source, const char* name, Address address, u32 size) {