diff --git a/src/ccc/symbol_database.cpp b/src/ccc/symbol_database.cpp index 65dd1e9..d9421e5 100644 --- a/src/ccc/symbol_database.cpp +++ b/src/ccc/symbol_database.cpp @@ -98,6 +98,18 @@ typename SymbolList::AddressToHandleMapIterators SymbolList +typename SymbolList::AddressToHandleMapIterators SymbolList::handles_from_address_range(AddressRange range) const +{ + if(range.low.valid()) { + return {m_address_to_handle.lower_bound(range.low.value), m_address_to_handle.lower_bound(range.high.value)}; + } else if(range.high.valid()) { + return {m_address_to_handle.begin(), m_address_to_handle.lower_bound(range.high.value)}; + } else { + return {m_address_to_handle.end(), m_address_to_handle.end()}; + } +} + template SymbolHandle SymbolList::first_handle_from_starting_address(Address address) const { @@ -130,7 +142,8 @@ SymbolHandle SymbolList::first_handle_from_name(const st template SymbolType* SymbolList::symbol_from_contained_address(Address address) { - auto iterator = m_address_to_handle.lower_bound(address.value); + auto iterator = m_address_to_handle.upper_bound(address.value); + iterator--; // Find the greatest element that is less than or equal to the address. if(iterator != m_address_to_handle.end()) { SymbolType* symbol = symbol_from_handle(iterator->second); if(symbol && address.value < symbol->m_address.value + symbol->m_size) { diff --git a/src/ccc/symbol_database.h b/src/ccc/symbol_database.h index 459a73b..d811ef1 100644 --- a/src/ccc/symbol_database.h +++ b/src/ccc/symbol_database.h @@ -132,7 +132,7 @@ class SymbolList { std::span optional_span(std::optional> range); std::span optional_span(std::optional> range) const; - using AddressToHandleMap = std::multimap, std::greater>; + using AddressToHandleMap = std::multimap>; using NameToHandleMap = std::multimap>; template @@ -151,6 +151,7 @@ class SymbolList { using NameToHandleMapIterators = Iterators; AddressToHandleMapIterators handles_from_starting_address(Address address) const; + AddressToHandleMapIterators handles_from_address_range(AddressRange range) const; SymbolHandle first_handle_from_starting_address(Address address) const; NameToHandleMapIterators handles_from_name(const std::string& name) const; SymbolHandle first_handle_from_name(const std::string& name) const; @@ -259,6 +260,7 @@ class Symbol { Address address() const { return m_address; } u32 size() const { return m_size; } void set_size(u32 size) { m_size = size; } + AddressRange address_range() const { return AddressRange(m_address, m_address.get_or_zero() + m_size); } ast::Node* type() { return m_type.get(); } const ast::Node* type() const { return m_type.get(); } diff --git a/src/ccc/symbol_json.cpp b/src/ccc/symbol_json.cpp index 5feb044..54edbf0 100644 --- a/src/ccc/symbol_json.cpp +++ b/src/ccc/symbol_json.cpp @@ -226,7 +226,7 @@ static void write_json(JsonWriter& json, const LocalVariable& symbol, const Symb write_json(json, *storage, database); } - if(symbol.live_range.valid()) { + if(symbol.live_range.low.valid() && symbol.live_range.high.valid()) { json.Key("live_range"); json.StartArray(); json.Uint(symbol.live_range.low.value); diff --git a/src/ccc/util.h b/src/ccc/util.h index 00e2ad5..d5a5a0c 100644 --- a/src/ccc/util.h +++ b/src/ccc/util.h @@ -250,8 +250,11 @@ struct AddressRange { Address low; Address high; + AddressRange() {} + AddressRange(Address address) : low(address), high(address) {} + AddressRange(Address l, Address h) : low(l), high(h) {} + friend auto operator<=>(const AddressRange& lhs, const AddressRange& rhs) = default; - bool valid() const { return low.valid(); } }; // These functions are to be used only for source file paths present in the diff --git a/test/ccc/symbol_database_tests.cpp b/test/ccc/symbol_database_tests.cpp index f3eb5b2..4f8dde9 100644 --- a/test/ccc/symbol_database_tests.cpp +++ b/test/ccc/symbol_database_tests.cpp @@ -80,7 +80,54 @@ TEST(CCCSymbolDatabase, SymbolListSpan) } } -TEST(CCCSymbolDatabase, HandleFromAddress) +TEST(CCCSymbolDatabase, HandlesFromAddressRange) +{ + SymbolDatabase database; + FunctionHandle handles[20]; + + Result source = database.symbol_sources.create_symbol("Source", SymbolSourceHandle()); + CCC_GTEST_FAIL_IF_ERROR(source); + + // Create the symbols. + for(u32 address = 10; address < 20; address++) { + Result function = database.functions.create_symbol("", (*source)->handle(), nullptr, address); + CCC_GTEST_FAIL_IF_ERROR(function); + handles[address] = (*function)->handle(); + } + + // Try various address ranges. + auto empty_before = database.functions.handles_from_address_range(AddressRange(0, 10)); + EXPECT_EQ(empty_before.begin(), empty_before.end()); + + auto empty_after = database.functions.handles_from_address_range(AddressRange(21, 30)); + EXPECT_EQ(empty_after.begin(), empty_after.end()); + + auto empty_before_open = database.functions.handles_from_address_range(AddressRange(Address(), 10)); + EXPECT_EQ(empty_before_open.begin(), empty_before_open.end()); + + auto empty_after_open = database.functions.handles_from_address_range(AddressRange(21, Address())); + EXPECT_EQ(empty_after_open.begin(), empty_after_open.end()); + + auto last = database.functions.handles_from_address_range(AddressRange(19, 30)); + EXPECT_EQ(last.begin()->second, handles[19]); + + auto last_open = database.functions.handles_from_address_range(AddressRange(19, Address())); + EXPECT_EQ(last_open.begin()->second, handles[19]); + + auto first_half = database.functions.handles_from_address_range(AddressRange(5, 15)); + EXPECT_EQ(first_half.begin()->second, handles[10]); + EXPECT_EQ(first_half.end()->second, handles[15]); + + auto second_half = database.functions.handles_from_address_range(AddressRange(15, 25)); + EXPECT_EQ(second_half.begin()->second, handles[15]); + EXPECT_EQ((--second_half.end())->second, handles[19]); + + auto whole_range = database.functions.handles_from_address_range(AddressRange(10, 20)); + EXPECT_EQ(whole_range.begin()->second, handles[10]); + EXPECT_EQ((--whole_range.end())->second, handles[19]); +} + +TEST(CCCSymbolDatabase, HandleFromStartingAddress) { SymbolDatabase database; FunctionHandle handles[10];