blob: e5533830281ea5abb48df20fab1f8e38b4d8aa7f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/symbols/module_symbol_index.h"
#include <inttypes.h>
#include <time.h>
#include <ostream>
#include "gtest/gtest.h"
#include "src/developer/debug/zxdb/common/string_util.h"
#include "src/developer/debug/zxdb/symbols/test_symbol_module.h"
#include "src/lib/fxl/strings/split_string.h"
namespace zxdb {
TEST(ModuleSymbolIndex, FindExactFunction) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.Load(&err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
// Standalone function search.
auto result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyFunctionName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Standalone function inside a namespace.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kNamespaceFunctionName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Namespace + class member function search.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyMemberOneName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Same but in the 2nd compilation unit (tests unit-relative addressing).
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kFunctionInTest2Name));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Namespace + class + struct with static member function search.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyMemberTwoName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Global variable.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kGlobalName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
// Class static variable.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kClassStaticName));
EXPECT_EQ(1u, result.size()) << "Symbol not found.";
}
TEST(ModuleSymbolIndex, FindPrefix) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.Load(&err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
// Querying an exact identifier should return it.
auto [found, end] = index.FindPrefix(Identifier("GetStructWithEnums"));
ASSERT_NE(found, end);
EXPECT_EQ("GetStructWithEnums", found->first);
// Empty query should return found == end.
std::tie(found, end) = index.FindPrefix(Identifier());
EXPECT_EQ(found, end);
// Something not found.
std::tie(found, end) = index.FindPrefix(Identifier("ThisDoesntExist"));
EXPECT_EQ(found, end);
// Something with multiple results (NOTE: if more functions are added to the
// test file with this prefix, the expected results might change).
std::tie(found, end) =
index.FindPrefix(Identifier(IdentifierComponent("Call")));
ASSERT_NE(found, end);
EXPECT_EQ("CallInline", found->first);
++found;
ASSERT_NE(found, end);
EXPECT_EQ("CallInlineMember", found->first);
// A nested namespace.
std::tie(found, end) =
index.FindPrefix(TestSymbolModule::SplitName("my_ns::Base"));
ASSERT_NE(found, end);
EXPECT_EQ("Base1", found->first);
++found;
ASSERT_NE(found, end);
EXPECT_EQ("Base2", found->first);
}
TEST(ModuleSymbolIndex, FindFileMatches) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.Load(&err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
// Simple filename-only query that succeeds.
std::vector<std::string> result =
index.FindFileMatches("zxdb_symbol_test.cc");
ASSERT_EQ(1u, result.size());
EXPECT_TRUE(
StringEndsWith(result[0], "symbols/test_data/zxdb_symbol_test.cc"));
// Save the full path for later.
std::string full_path = result[0];
// Simple filename-only query that fails.
result = index.FindFileMatches("nonexistant.cc");
EXPECT_EQ(0u, result.size());
// Multiple path components.
result = index.FindFileMatches("symbols/test_data/zxdb_symbol_test.cc");
EXPECT_EQ(1u, result.size());
// Ends-with match but doesn't start on a slash boundary.
result = index.FindFileMatches("nt/test_data/zxdb_symbol_test.cc");
EXPECT_EQ(0u, result.size());
// Full path match.
result = index.FindFileMatches(full_path);
EXPECT_EQ(1u, result.size());
// More-than-full path match.
result = index.FindFileMatches("/a" + full_path);
EXPECT_EQ(0u, result.size());
}
TEST(ModuleSymbolIndex, FindFilePrefixes) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.Load(&err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
// Should find both files. Order not guaranteed.
std::vector<std::string> result = index.FindFilePrefixes("z");
ASSERT_EQ(2u, result.size());
EXPECT_NE(result.end(),
std::find(result.begin(), result.end(), "zxdb_symbol_test.cc"));
EXPECT_NE(result.end(),
std::find(result.begin(), result.end(), "zxdb_symbol_test2.cc"));
}
TEST(ModuleSymbolIndex, FindTypeAndNamespace) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.Load(&err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
// Should have one namespace.
auto result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyNamespaceName));
EXPECT_EQ(1u, result.size()) << "Namespace not found.";
// Outer class name.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyClassName));
EXPECT_EQ(1u, result.size()) << "Class not found.";
// Inner class name.
result = index.FindExact(
TestSymbolModule::SplitName(TestSymbolModule::kMyInnerClassName));
EXPECT_EQ(1u, result.size()) << "Class not found.";
// Should also have deifned an "int" type.
result = index.FindExact(Identifier(IdentifierComponent("int")));
EXPECT_EQ(1u, result.size()) << "int not found.";
}
// Enable and substitute a path on your system to dump the index for a
// DWARF file.
#if 0
TEST(ModuleSymbolIndex, DumpFileIndex) {
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.LoadSpecific("chrome", &err)) << err;
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
std::cout << "Index dump:\n";
index.root().Dump(std::cout, 1);
index.DumpFileIndex(std::cout);
}
#endif
// Enable and substitute a path on your system for kFilename to run the
// indexing benchmark.
#if 0
static int64_t GetTickMicroseconds() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
constexpr int64_t kMicrosecondsPerSecond = 1000000;
constexpr int64_t kNanosecondsPerMicrosecond = 1000;
int64_t result = ts.tv_sec * kMicrosecondsPerSecond;
result += (ts.tv_nsec / kNanosecondsPerMicrosecond);
return result;
}
TEST(ModuleSymbolIndex, BenchmarkIndexing) {
const char kFilename[] = "chrome";
int64_t begin_us = GetTickMicroseconds();
TestSymbolModule module;
std::string err;
ASSERT_TRUE(module.LoadSpecific(kFilename, &err)) << err;
int64_t load_complete_us = GetTickMicroseconds();
ModuleSymbolIndex index;
index.CreateIndex(module.object_file());
int64_t index_complete_us = GetTickMicroseconds();
printf("\nIndexing results for %s:\n Load: %" PRId64
" µs\n Index: %" PRId64 " µs\n\n",
kFilename, load_complete_us - begin_us,
index_complete_us - load_complete_us);
sleep(10);
}
#endif // End indexing benchmark.
} // namespace zxdb