Daniel Carvalho has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/43250 )
Change subject: base: Add unit test for SymbolTable
......................................................................
base: Add unit test for SymbolTable
Add a unit test for base/loader/symtab.*.
Change-Id: I81c14826ab629439897235cbaaf79047e603ff8d
Signed-off-by: Daniel R. Carvalho <oda...@yahoo.com.br>
---
M src/base/loader/SConscript
A src/base/loader/symtab.test.cc
2 files changed, 809 insertions(+), 0 deletions(-)
diff --git a/src/base/loader/SConscript b/src/base/loader/SConscript
index d17875f..f90c523 100644
--- a/src/base/loader/SConscript
+++ b/src/base/loader/SConscript
@@ -35,3 +35,5 @@
Source('memory_image.cc')
Source('object_file.cc')
Source('symtab.cc')
+GTest('symtab.test', 'symtab.test.cc', 'symtab.cc', '../../sim/serialize.cc',
+ '../inifile.cc', with_tag('gem5 trace'))
diff --git a/src/base/loader/symtab.test.cc b/src/base/loader/symtab.test.cc
new file mode 100644
index 0000000..0f9eb34
--- /dev/null
+++ b/src/base/loader/symtab.test.cc
@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2021 Daniel R. Carvalho
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest.h>
+
+#include <cassert>
+
+#include "base/loader/symtab.hh"
+
+/** Checks that a symbol's contents matches the expected contents. */
+void checkSymbol(const Loader::Symbol& symbol, const Loader::Symbol&
expected)
+{
+ ASSERT_EQ(symbol.binding, expected.binding);
+ ASSERT_EQ(symbol.name, expected.name);
+ ASSERT_EQ(symbol.address, expected.address);
+}
+
+/** Test that the constructor creates an empty table. */
+TEST(LoaderSymtabTest, EmptyConstruction)
+{
+ Loader::SymbolTable symtab;
+ ASSERT_TRUE(symtab.empty());
+ ASSERT_EQ(symtab.begin(), symtab.end());
+}
+
+/** Test that the insertion of a symbol with no name fails. */
+TEST(LoaderSymtabTest, InsertSymbolNoName)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "", 0x10};
+ ASSERT_FALSE(symtab.insert(symbol));
+}
+
+/** Test that the insertion of one symbol in an empty table works. */
+TEST(LoaderSymtabTest, InsertOneSymbol)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ ASSERT_TRUE(symtab.insert(symbol));
+
+ ASSERT_FALSE(symtab.empty());
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbol);
+}
+
+/** Test that the insertion of a symbol with an existing name fails. */
+TEST(LoaderSymtabTest, InsertSymbolExistingName)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ ASSERT_TRUE(symtab.insert(symbol));
+
+ Loader::Symbol symbol2 =
+ {Loader::Symbol::Binding::Local, symbol.name, 0x20};
+ ASSERT_FALSE(symtab.insert(symbol2));
+}
+
+/** Test that the insertion of a symbol with an existing address works. */
+TEST(LoaderSymtabTest, InsertSymbolExistingAddress)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ ASSERT_TRUE(symtab.insert(symbol));
+
+ Loader::Symbol symbol2 =
+ {Loader::Symbol::Binding::Local, "symbol2", symbol.address};
+ ASSERT_TRUE(symtab.insert(symbol2));
+}
+
+/** Test that the insertion of one symbol in a non-empty table works. */
+TEST(LoaderSymtabTest, InsertMultipleSymbols)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ ASSERT_EQ((it+3), symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+}
+
+/**
+ * Test that a table with multiple entries becomes empty after being
cleared.
+ */
+TEST(LoaderSymtabTest, ClearMultiple)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ symtab.clear();
+ ASSERT_TRUE(symtab.empty());
+ ASSERT_EQ(symtab.begin(), symtab.end());
+}
+
+/**
+ * Test the creation of a new table with offsets applied to the original
+ * symbols' addresses. Also verifies if the original table is kept the
same.
+ */
+TEST(LoaderSymtabTest, Offset)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ Addr offset = 0x5;
+ const auto symtab_new = symtab.offset(offset);
+
+ // Check that the original table is not modified
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+
+ // Check that the new table is offset
+ Loader::Symbol expected_symbols[3] = {
+ {symbols[0].binding, symbols[0].name, symbols[0].address + offset},
+ {symbols[1].binding, symbols[1].name, symbols[1].address + offset},
+ {symbols[2].binding, symbols[2].name, symbols[2].address + offset},
+ };
+ const auto it_new = symtab_new->begin();
+ ASSERT_NE(it_new, symtab_new->end());
+ ASSERT_EQ((it_new+3), symtab_new->end());
+ checkSymbol(*it_new, expected_symbols[0]);
+ checkSymbol(*(it_new+1), expected_symbols[1]);
+ checkSymbol(*(it_new+2), expected_symbols[2]);
+}
+
+/**
+ * Test the creation of a new table with masks applied to the original
+ * symbols' addresses. Also verifies if the original table is kept the
same.
+ */
+TEST(LoaderSymtabTest, Mask)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ Addr mask = 0x10;
+ const auto symtab_new = symtab.mask(mask);
+
+ // Check that the original table is not modified
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+
+ // Check that the new table is masked
+ Loader::Symbol expected_symbols[3] = {
+ {symbols[0].binding, symbols[0].name, symbols[0].address & mask},
+ {symbols[1].binding, symbols[1].name, symbols[1].address & mask},
+ {symbols[2].binding, symbols[2].name, symbols[2].address & mask},
+ };
+ const auto it_new = symtab_new->begin();
+ ASSERT_NE(it_new, symtab_new->end());
+ ASSERT_EQ((it_new+3), symtab_new->end());
+ checkSymbol(*it_new, expected_symbols[0]);
+ checkSymbol(*(it_new+1), expected_symbols[1]);
+ checkSymbol(*(it_new+2), expected_symbols[2]);
+}
+
+/**
+ * Test the creation of a new filtered table containing only the global
symbols
+ * of the original table. Also verifies if the original table is kept the
same.
+ */
+TEST(LoaderSymtabTest, Globals)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[5] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Global, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ {Loader::Symbol::Binding::Weak, "symbol4", 0x40},
+ {Loader::Symbol::Binding::Weak, "symbol5", 0x50}
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+ EXPECT_TRUE(symtab.insert(symbols[3]));
+ EXPECT_TRUE(symtab.insert(symbols[4]));
+
+ const auto symtab_new = symtab.globals();
+
+ // Check that the original table is not modified
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+
+ // Check that the new table only contains globals
+ const auto it_new = symtab_new->begin();
+ ASSERT_NE(it_new, symtab_new->end());
+ ASSERT_EQ((it_new+1), symtab_new->end());
+ checkSymbol(*it_new, symbols[1]);
+}
+
+/**
+ * Test the creation of a new filtered table containing only the local
symbols
+ * of the original table. Also verifies if the original table is kept the
same.
+ */
+TEST(LoaderSymtabTest, Locals)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[5] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Global, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ {Loader::Symbol::Binding::Weak, "symbol4", 0x40},
+ {Loader::Symbol::Binding::Weak, "symbol5", 0x50}
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+ EXPECT_TRUE(symtab.insert(symbols[3]));
+ EXPECT_TRUE(symtab.insert(symbols[4]));
+
+ const auto symtab_new = symtab.locals();
+
+ // Check that the original table is not modified
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+
+ // Check that the new table only contains locals
+ const auto it_new = symtab_new->begin();
+ ASSERT_NE(it_new, symtab_new->end());
+ ASSERT_EQ((it_new+2), symtab_new->end());
+ checkSymbol(*it_new, symbols[0]);
+ checkSymbol(*(it_new+1), symbols[2]);
+}
+
+/**
+ * Test the creation of a new filtered table containing only the weak
symbols
+ * of the original table. Also verifies if the original table is kept the
same.
+ */
+TEST(LoaderSymtabTest, Weaks)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[5] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Global, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ {Loader::Symbol::Binding::Weak, "symbol4", 0x40},
+ {Loader::Symbol::Binding::Weak, "symbol5", 0x50}
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+ EXPECT_TRUE(symtab.insert(symbols[3]));
+ EXPECT_TRUE(symtab.insert(symbols[4]));
+
+ const auto symtab_new = symtab.weaks();
+
+ // Check that the original table is not modified
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+
+ // Check that the new table only contains weaks
+ const auto it_new = symtab_new->begin();
+ ASSERT_NE(it_new, symtab_new->end());
+ ASSERT_EQ((it_new+2), symtab_new->end());
+ checkSymbol(*it_new, symbols[3]);
+ checkSymbol(*(it_new+1), symbols[4]);
+}
+
+/** Test searching for a non-existent address. */
+TEST(LoaderSymtabTest, FindNonExistentAddress)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ EXPECT_TRUE(symtab.insert(symbol));
+
+ ASSERT_EQ(symtab.find(0x0), symtab.end());
+}
+
+/** Test searching for a unique address. */
+TEST(LoaderSymtabTest, FindUniqueAddress)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ const auto it = symtab.find(symbols[2].address);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[2]);
+}
+
+/**
+ * Test that searching for a non-unique address returns the first
occurrence.
+ */
+TEST(LoaderSymtabTest, FindNonUniqueAddress)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", symbols[1].address},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ const auto it = symtab.find(symbols[1].address);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[1]);
+}
+
+/** Test searching for a non-existent name. */
+TEST(LoaderSymtabTest, FindNonExistentName)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ EXPECT_TRUE(symtab.insert(symbol));
+
+ const auto it = symtab.find("symbol2");
+ ASSERT_EQ(it, symtab.end());
+}
+
+/** Test searching for an existing name. */
+TEST(LoaderSymtabTest, FindExistingName)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ const auto it = symtab.find(symbols[1].name);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[1]);
+}
+
+/** Test searching for the an existent address using findNearest. */
+TEST(LoaderSymtabTest, FindNearestExact)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[2] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+
+ const auto it = symtab.findNearest(symbols[1].address);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[1]);
+}
+
+/**
+ * Test that searching for the nearest address of an address higher than
the
+ * lowest address works.
+ */
+TEST(LoaderSymtabTest, FindNearestRound)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ EXPECT_TRUE(symtab.insert(symbol));
+
+ const auto it = symtab.findNearest(symbol.address + 0x1);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbol);
+}
+
+/**
+ * Test that searching for the nearest address of an address higher than
the
+ * lowest address works and check the next address when there is a valid
+ * next address.
+ */
+TEST(LoaderSymtabTest, FindNearestRoundWithNext)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbols[2] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+
+ Addr next_addr;
+ const auto it = symtab.findNearest(symbols[0].address + 0x1,
next_addr);
+ ASSERT_NE(it, symtab.end());
+ checkSymbol(*it, symbols[0]);
+ ASSERT_EQ(next_addr, symbols[1].address);
+}
+
+/**
+ * Test that searching for the nearest address of an address higher than
the
+ * lowest address works and check the next address when there is no valid
+ * next address.
+ */
+TEST(LoaderSymtabTest, DISABLED_FindNearestRoundWithNextNonExistent)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ EXPECT_TRUE(symtab.insert(symbol));
+
+ // @todo What should be the expected result?
+ Addr next_addr;
+ const auto it = symtab.findNearest(symbol.address + 0x1, next_addr);
+ ASSERT_EQ(it, symtab.end());
+}
+
+/**
+ * Test that searching for the nearest address of an address lower than the
+ * lowest address fails.
+ */
+TEST(LoaderSymtabTest, FindNearestNonExistent)
+{
+ Loader::SymbolTable symtab;
+
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ EXPECT_TRUE(symtab.insert(symbol));
+
+ const auto it = symtab.findNearest(symbol.address - 0x1);
+ ASSERT_EQ(it, symtab.end());
+}
+
+/**
+ * Test that the insertion of a symbol table's symbols in another table
works
+ * when any symbol name conflicts.
+ */
+TEST(LoaderSymtabTest, InsertTableConflicting)
+{
+ Loader::Symbol symbols[5] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ {Loader::Symbol::Binding::Local, "symbol4", 0x40},
+ // Introduce name conflict
+ {Loader::Symbol::Binding::Local, symbols[0].name, 0x50},
+ };
+
+ // Populate table 1
+ Loader::SymbolTable symtab;
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ // Populate table 2
+ Loader::SymbolTable symtab2;
+ EXPECT_TRUE(symtab2.insert(symbols[3]));
+ EXPECT_TRUE(symtab2.insert(symbols[4]));
+
+ // Do the insertion
+ ASSERT_FALSE(symtab.insert(symtab2));
+
+ // Check that none of the tables change
+ const auto it2 = symtab2.begin();
+ ASSERT_NE(it2, symtab2.end());
+ ASSERT_EQ((it2+2), symtab2.end());
+ checkSymbol(*it2, symbols[3]);
+ checkSymbol(*(it2+1), symbols[4]);
+
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ ASSERT_EQ((it+3), symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+}
+
+/**
+ * Test that the insertion of a symbol table's symbols in another table
works
+ * when no symbols conflict.
+ */
+TEST(LoaderSymtabTest, InsertTable)
+{
+ Loader::Symbol symbols[5] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ {Loader::Symbol::Binding::Local, "symbol4", 0x40},
+ {Loader::Symbol::Binding::Local, "symbol5", 0x50},
+ };
+
+ // Populate table 1
+ Loader::SymbolTable symtab;
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ // Populate table 2
+ Loader::SymbolTable symtab2;
+ EXPECT_TRUE(symtab2.insert(symbols[3]));
+ EXPECT_TRUE(symtab2.insert(symbols[4]));
+
+ // Do the insertion
+ symtab.insert(symtab2);
+
+ // Check that symtab2 does not change
+ const auto it2 = symtab2.begin();
+ ASSERT_NE(it2, symtab2.end());
+ ASSERT_EQ((it2+2), symtab2.end());
+ checkSymbol(*it2, symbols[3]);
+ checkSymbol(*(it2+1), symbols[4]);
+
+ // Check that the symbols from symtab2 have been inserted in symtab
+ const auto it = symtab.begin();
+ ASSERT_NE(it, symtab.end());
+ ASSERT_EQ((it+5), symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+ checkSymbol(*(it+3), symbols[3]);
+ checkSymbol(*(it+4), symbols[4]);
+}
+
+/**
+ * Fixture class that handles temporary directory creation. These temporary
+ * directories are used by the tests in this file, in order to avoid that
+ * a failed test will not remove its directory, causing future runs to
fail.
+ */
+class LoaderSymtabFixture : public ::testing::Test
+{
+ private:
+ /**
+ * Temporary directory names are generated based on this number, which
+ * is updated every time the generator function is called.
+ */
+ static unsigned dirNumber;
+
+ /** The name of the temporary directory. */
+ std::string dirName;
+
+ public:
+ using ::testing::Test::Test;
+
+ /** Generate a temporary directory name. */
+ static std::string
+ generateTempDirName()
+ {
+ return "/tmp/loader_symtab_serialization_test" +
+ std::to_string(dirNumber++) + "/";
+ }
+
+ /** Get the name of the directory we have created on SetUp. */
+ std::string getDirName() { return dirName; }
+
+ void
+ SetUp() override
+ {
+ // Create the directory. We use mkdir, yet we do not include its
+ // respective header because if the way serialize.cc creates its
+ // dir changes, we want to increase the likelihood of triggering
+ // a compilation error so that the function is also updated here
+ dirName = generateTempDirName();
+ M5_VAR_USED int success = mkdir(dirName.c_str(), 0775);
+ assert(!(success == -1 && errno != EEXIST));
+ }
+
+ void
+ TearDown() override
+ {
+ // There may be a cpt file inside, so try to remove it; otherwise,
+ // rmdir does not work
+ remove((dirName + "m5.cpt").c_str());
+ // Remove the directory we created on SetUp
+ M5_VAR_USED int success = rmdir(dirName.c_str());
+ assert(success == 0);
+ }
+};
+unsigned LoaderSymtabFixture::dirNumber = 0;
+
+/** Test serialization. */
+TEST_F(LoaderSymtabFixture, Serialization)
+{
+ // Populate the table
+ Loader::SymbolTable symtab;
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+ EXPECT_TRUE(symtab.insert(symbols[0]));
+ EXPECT_TRUE(symtab.insert(symbols[1]));
+ EXPECT_TRUE(symtab.insert(symbols[2]));
+
+ // Serialization
+ std::ofstream cp(getDirName() + "m5.cpt");
+ Serializable::ScopedCheckpointSection scs(cp, "Section1");
+ symtab.serialize("test", cp);
+
+ // The checkpoint must be flushed, otherwise the file may not be up-
+ // to-date and the assertions below will fail
+ cp.close();
+
+ // Verify the output
+ std::ifstream is(getDirName() + "m5.cpt");
+ assert(is.good());
+ ASSERT_EQ(std::string(std::istreambuf_iterator<char>(is),
+ std::istreambuf_iterator<char>()), "\n[Section1]\ntest.size=3\n"
+ "test.addr_0=16\ntest.symbol_0=symbol\ntest.binding_0=1\n"
+ "test.addr_1=32\ntest.symbol_1=symbol2\ntest.binding_1=1\n"
+ "test.addr_2=48\ntest.symbol_2=symbol3\ntest.binding_2=1\n");
+}
+
+/** Test unserialization. */
+TEST_F(LoaderSymtabFixture, Unserialization)
+{
+ Loader::Symbol symbols[3] = {
+ {Loader::Symbol::Binding::Local, "symbol", 0x10},
+ {Loader::Symbol::Binding::Local, "symbol2", 0x20},
+ {Loader::Symbol::Binding::Local, "symbol3", 0x30},
+ };
+
+ // Simulate serialization
+ {
+ std::ofstream cp(getDirName() + "m5.cpt");
+ cp << "\n[Section1]\ntest.size=3\n"
+ "test.addr_0=16\ntest.symbol_0=symbol\ntest.binding_0=1\n"
+ "test.addr_1=32\ntest.symbol_1=symbol2\ntest.binding_1=1\n"
+ "test.addr_2=48\ntest.symbol_2=symbol3\ntest.binding_2=1\n";
+ cp.close();
+ }
+
+ // Unserialization
+ {
+ Loader::SymbolTable unserialized_symtab;
+ CheckpointIn cp(getDirName());
+ Serializable::ScopedCheckpointSection scs(cp, "Section1");
+ unserialized_symtab.unserialize("test", cp);
+
+ // Make sure that the symbols in symtab are present in the
+ // unserialized table
+ const auto it = unserialized_symtab.begin();
+ ASSERT_NE(it, unserialized_symtab.end());
+ ASSERT_EQ((it+3), unserialized_symtab.end());
+ checkSymbol(*it, symbols[0]);
+ checkSymbol(*(it+1), symbols[1]);
+ checkSymbol(*(it+2), symbols[2]);
+ }
+}
+
+/**
+ * Test unserialization missing binding.
+ * @todo Since there is no way to create a checkpoint without binding
anymore,
+ * this functionality should be deprecated at some point.
+ */
+TEST_F(LoaderSymtabFixture, UnserializationMissingBinding)
+{
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ Loader::Symbol symbol3 = {Loader::Symbol::Binding::Local, "symbol3",
0x30};
+
+ // Simulate serialization
+ {
+ std::ofstream cp(getDirName() + "m5.cpt");
+ cp << "\n[Section1]\ntest.size=3\n"
+ "test.addr_0=16\ntest.symbol_0=symbol\ntest.binding_0=1\n"
+ "test.addr_1=32\ntest.symbol_1=symbol2\n"
+ "test.addr_2=48\ntest.symbol_2=symbol3\ntest.binding_2=1\n";
+ cp.close();
+ }
+
+ // Unserialization
+ {
+ Loader::SymbolTable unserialized_symtab;
+ CheckpointIn cp(getDirName());
+ Serializable::ScopedCheckpointSection scs(cp, "Section1");
+
+ unserialized_symtab.unserialize("test", cp);
+
+ // Make sure that the symbols in symtab are present in the
+ // unserialized table
+ const auto it = unserialized_symtab.begin();
+ ASSERT_NE(it, unserialized_symtab.end());
+ ASSERT_EQ((it+3), unserialized_symtab.end());
+ checkSymbol(*it, symbol);
+ ASSERT_EQ((it+1)->binding, Loader::Symbol::Binding::Global);
+ ASSERT_EQ((it+1)->name, "symbol2");
+ ASSERT_EQ((it+1)->address, 0x20);
+ checkSymbol(*(it+2), symbol3);
+ }
+}
+
+/**
+ * Test unserialization missing binding with a different default value.
+ * @todo Since there is no way to create a checkpoint without binding
anymore,
+ * this functionality should be deprecated at some point.
+ */
+TEST_F(LoaderSymtabFixture, UnserializationMissingBindingChangeDefault)
+{
+ Loader::Symbol symbol = {Loader::Symbol::Binding::Local, "symbol",
0x10};
+ Loader::Symbol symbol3 = {Loader::Symbol::Binding::Local, "symbol3",
0x30};
+
+ // Simulate serialization
+ {
+ std::ofstream cp(getDirName() + "m5.cpt");
+ cp << "\n[Section1]\ntest.size=3\n"
+ "test.addr_0=16\ntest.symbol_0=symbol\ntest.binding_0=1\n"
+ "test.addr_1=32\ntest.symbol_1=symbol2\n"
+ "test.addr_2=48\ntest.symbol_2=symbol3\ntest.binding_2=1\n";
+ cp.close();
+ }
+
+ // Unserialization
+ {
+ Loader::SymbolTable unserialized_symtab;
+ CheckpointIn cp(getDirName());
+ Serializable::ScopedCheckpointSection scs(cp, "Section1");
+
+ unserialized_symtab.unserialize("test", cp,
+ Loader::Symbol::Binding::Weak);
+
+ // Make sure that the symbols in symtab are present in the
+ // unserialized table
+ const auto it = unserialized_symtab.begin();
+ ASSERT_NE(it, unserialized_symtab.end());
+ ASSERT_EQ((it+3), unserialized_symtab.end());
+ checkSymbol(*it, symbol);
+ ASSERT_EQ((it+1)->binding, Loader::Symbol::Binding::Weak);
+ ASSERT_EQ((it+1)->name, "symbol2");
+ ASSERT_EQ((it+1)->address, 0x20);
+ checkSymbol(*(it+2), symbol3);
+ }
+}
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/43250
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I81c14826ab629439897235cbaaf79047e603ff8d
Gerrit-Change-Number: 43250
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho <oda...@yahoo.com.br>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s