mirror of
git://sourceware.org/git/libabigail.git
synced 2025-02-08 17:47:13 +00:00
7851ca2b91
With the prework in previous commits, we are now able to drop the public symbols maps in corpus::priv and replace them by private members with access through getters. The getters use the new symtab implementation to generate the maps on the fly. Setters are not required anymore and are removed. Also remove redundant getters. We could also remove the getters for the symbol maps and the local caching variable and leave it all to lookup_symbol, but this is left for a later change. * include/abg-corpus.h (corpus::set_fun_symbol_map): Remove method declaration. (corpus::set_undefined_fun_symbol_map): Likewise. (corpus::set_var_symbol_map): Likewise. (corpus::set_undefined_var_symbol_map): Likewise. (corpus::get_fun_symbol_map_sptr): Likewise. (corpus::get_undefined_fun_symbol_map_sptr): Likewise. (corpus::get_var_symbol_map_sptr): Likewise. (corpus::get_undefined_var_symbol_map_sptr): Likewise. * src/abg-corpus-priv.h (corpus::priv::var_symbol_map): make private and mutable (corpus::priv::undefined_var_symbol_map): Likewise. (corpus::priv::fun_symbol_map): Likewise. (corpus::priv::undefined_fun_symbol_map): Likewise. (corpus::priv::get_fun_symbol_map): New method declaration. (corpus::priv::get_undefined_fun_symbol_map): Likewise. (corpus::priv::get_var_symbol_map): Likewise. (corpus::priv::get_undefined_var_symbol_map): Likewise. * src/abg-corpus.cc (corpus::priv::get_fun_symbol_map): New method implementation. (corpus::priv::get_undefined_fun_symbol_map): Likewise. (corpus::priv::get_var_symbol_map): Likewise. (corpus::priv::get_undefined_var_symbol_map): Likewise. (corpus::is_empty): depend on symtab only. (corpus::set_fun_symbol_map): Remove method. (corpus::set_undefined_fun_symbol_map): Likewise. (corpus::set_var_symbol_map): Likewise. (corpus::set_undefined_var_symbol_map): Likewise. (corpus::get_fun_symbol_map_sptr): Likewise. (corpus::get_undefined_fun_symbol_map_sptr): Likewise. (corpus::get_var_symbol_map_sptr): Likewise. (corpus::get_undefined_var_symbol_map_sptr): Likewise. (corpus::get_fun_symbol_map): Use corpus::priv proxy method. (corpus::get_undefined_fun_symbol_map): Likewise. (corpus::get_var_symbol_map): Likewise. (corpus::get_undefined_var_symbol_map): Likewise. * src/abg-dwarf-reader.cc (read_debug_info_into_corpus): Do not set corpus symbol maps anymore. * src/abg-reader.cc (read_corpus_from_input): Likewise. * tests/test-symtab.cc (assert_symbol_count): Do not access the corpus symbol maps through sptr anymore. * tests/data/test-read-dwarf/PR25007-sdhci.ko.abi: Adjust expected test output. Reviewed-by: Giuliano Procida <gprocida@google.com> Reviewed-by: Dodji Seketeli <dodji@seketeli.org> Signed-off-by: Matthias Maennich <maennich@google.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com>
277 lines
9.5 KiB
C++
277 lines
9.5 KiB
C++
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
// -*- Mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2020 Google, Inc.
|
|
//
|
|
// Author: Matthias Maennich
|
|
|
|
/// @file
|
|
///
|
|
/// This program tests symtab invariants through abg-corpus.
|
|
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <vector>
|
|
|
|
#include "abg-corpus.h"
|
|
#include "abg-dwarf-reader.h"
|
|
#include "abg-ir.h"
|
|
#include "lib/catch.hpp"
|
|
#include "test-utils.h"
|
|
|
|
using namespace abigail;
|
|
|
|
using dwarf_reader::create_read_context;
|
|
using dwarf_reader::read_context_sptr;
|
|
using dwarf_reader::read_corpus_from_elf;
|
|
using ir::environment;
|
|
using ir::environment_sptr;
|
|
|
|
static const std::string test_data_dir =
|
|
std::string(abigail::tests::get_src_dir()) + "/tests/data/test-symtab/";
|
|
|
|
dwarf_reader::status
|
|
read_corpus(const std::string path, corpus_sptr& result)
|
|
{
|
|
const std::string& absolute_path = test_data_dir + path;
|
|
|
|
environment_sptr env(new environment);
|
|
const std::vector<char**> debug_info_root_paths;
|
|
read_context_sptr ctxt = create_read_context(
|
|
absolute_path, debug_info_root_paths, env.get(),
|
|
/* load_all_type = */ true, /* linux_kernel_mode = */ true);
|
|
|
|
dwarf_reader::status status = dwarf_reader::STATUS_UNKNOWN;
|
|
result = read_corpus_from_elf(*ctxt, status);
|
|
|
|
REQUIRE(status != dwarf_reader::STATUS_UNKNOWN);
|
|
return status;
|
|
}
|
|
|
|
TEST_CASE("Symtab::Empty", "[symtab, basic]")
|
|
{
|
|
const std::string binary = "basic/empty.so";
|
|
corpus_sptr corpus_ptr;
|
|
const dwarf_reader::status status = read_corpus(binary, corpus_ptr);
|
|
REQUIRE(!corpus_ptr);
|
|
|
|
REQUIRE((status & dwarf_reader::STATUS_NO_SYMBOLS_FOUND));
|
|
}
|
|
|
|
TEST_CASE("Symtab::NoDebugInfo", "[symtab, basic]")
|
|
{
|
|
const std::string binary = "basic/no_debug_info.so";
|
|
corpus_sptr corpus_ptr;
|
|
const dwarf_reader::status status = read_corpus(binary, corpus_ptr);
|
|
REQUIRE(corpus_ptr);
|
|
|
|
REQUIRE(status
|
|
== (dwarf_reader::STATUS_OK
|
|
| dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND));
|
|
}
|
|
|
|
// this value indicates in the following helper method, that we do not want to
|
|
// assert for this particular value. In other words, N is a placeholder for an
|
|
// arbitrary value.
|
|
#define N std::numeric_limits<size_t>::max()
|
|
|
|
corpus_sptr
|
|
assert_symbol_count(const std::string& path,
|
|
size_t function_symbols = 0,
|
|
size_t variable_symbols = 0,
|
|
size_t undefined_function_symbols = 0,
|
|
size_t undefined_variable_symbols = 0)
|
|
{
|
|
corpus_sptr corpus_ptr;
|
|
const dwarf_reader::status status = read_corpus(path, corpus_ptr);
|
|
REQUIRE(corpus_ptr);
|
|
|
|
REQUIRE((status & dwarf_reader::STATUS_OK));
|
|
const corpus& corpus = *corpus_ptr;
|
|
|
|
size_t total_symbols = 0;
|
|
|
|
if (function_symbols != N)
|
|
{
|
|
CHECK(corpus.get_sorted_fun_symbols().size() == function_symbols);
|
|
CHECK(corpus.get_fun_symbol_map().size() == function_symbols);
|
|
total_symbols += function_symbols;
|
|
}
|
|
if (variable_symbols != N)
|
|
{
|
|
CHECK(corpus.get_sorted_var_symbols().size() == variable_symbols);
|
|
CHECK(corpus.get_var_symbol_map().size() == variable_symbols);
|
|
total_symbols += variable_symbols;
|
|
}
|
|
if (undefined_variable_symbols != N)
|
|
{
|
|
CHECK(corpus.get_sorted_undefined_fun_symbols().size()
|
|
== undefined_function_symbols);
|
|
CHECK(corpus.get_undefined_fun_symbol_map().size()
|
|
== undefined_function_symbols);
|
|
total_symbols += undefined_function_symbols;
|
|
}
|
|
if (undefined_function_symbols != N)
|
|
{
|
|
CHECK(corpus.get_sorted_undefined_var_symbols().size()
|
|
== undefined_variable_symbols);
|
|
CHECK(corpus.get_undefined_var_symbol_map().size()
|
|
== undefined_variable_symbols);
|
|
total_symbols += undefined_variable_symbols;
|
|
}
|
|
|
|
// assert the corpus reports being empty consistently with the symbol count
|
|
CHECK(corpus.is_empty() == (total_symbols == 0));
|
|
|
|
return corpus_ptr;
|
|
}
|
|
|
|
TEST_CASE("Symtab::SimpleSymtabs", "[symtab, basic]")
|
|
{
|
|
GIVEN("a binary with no exported symbols")
|
|
{
|
|
// TODO: should pass, but does currently not as empty tables are treated
|
|
// like the error case, but this is an edge case anyway.
|
|
// assert_symbol_count("empty.so");
|
|
}
|
|
|
|
GIVEN("a binary with a single exported function")
|
|
{
|
|
const std::string binary = "basic/single_function.so";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 1, 0);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_function_symbol("exported_function");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function"));
|
|
CHECK(symbol == corpus->lookup_function_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_variable_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a binary with a single exported variable")
|
|
{
|
|
const std::string binary = "basic/single_variable.so";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 0, 1);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_variable_symbol("exported_variable");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable"));
|
|
CHECK(symbol == corpus->lookup_variable_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_function_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a binary with one function and one variable exported")
|
|
{
|
|
const std::string binary = "basic/one_function_one_variable.so";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 1, 1);
|
|
CHECK(corpus->lookup_function_symbol("exported_function"));
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function"));
|
|
CHECK(corpus->lookup_variable_symbol("exported_variable"));
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable"));
|
|
}
|
|
|
|
GIVEN("a binary with a single undefined function")
|
|
{
|
|
const std::string binary = "basic/single_undefined_function.so";
|
|
const corpus_sptr corpus = assert_symbol_count(binary, 0, 0, 1, 0);
|
|
}
|
|
|
|
GIVEN("a binary with a single undefined variable")
|
|
{
|
|
const std::string binary = "basic/single_undefined_variable.so";
|
|
const corpus_sptr corpus = assert_symbol_count(binary, 0, 0, 0, 1);
|
|
}
|
|
|
|
GIVEN("a binary with one function and one variable undefined")
|
|
{
|
|
const std::string binary = "basic/one_function_one_variable_undefined.so";
|
|
const corpus_sptr corpus = assert_symbol_count(binary, 0, 0, 1, 1);
|
|
}
|
|
}
|
|
|
|
static const char* kernel_versions[] = { "4.14", "4.19", "5.4", "5.6" };
|
|
static const size_t nr_kernel_versions =
|
|
sizeof(kernel_versions) / sizeof(kernel_versions[0]);
|
|
|
|
TEST_CASE("Symtab::SimpleKernelSymtabs", "[symtab, basic, kernel, ksymtab]")
|
|
{
|
|
for (size_t i = 0; i < nr_kernel_versions; ++i)
|
|
{
|
|
const std::string base_path =
|
|
"kernel-" + std::string(kernel_versions[i]) + "/";
|
|
|
|
GIVEN("The binaries in " + base_path)
|
|
{
|
|
|
|
GIVEN("a kernel module with no exported symbols")
|
|
{
|
|
// TODO: should pass, but does currently not as empty tables are
|
|
// treated
|
|
// like the error case, but this is an edge case anyway.
|
|
// assert_symbol_count(base_path + "empty.so");
|
|
}
|
|
|
|
GIVEN("a kernel module with a single exported function")
|
|
{
|
|
const std::string binary = base_path + "single_function.ko";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 1, 0);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_function_symbol("exported_function");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function"));
|
|
CHECK(symbol == corpus->lookup_function_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_variable_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a kernel module with a single GPL exported function")
|
|
{
|
|
const std::string binary = base_path + "single_function_gpl.ko";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 1, 0);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_function_symbol("exported_function_gpl");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function_gpl"));
|
|
CHECK(symbol == corpus->lookup_function_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_variable_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a binary with a single exported variable")
|
|
{
|
|
const std::string binary = base_path + "single_variable.ko";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 0, 1);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_variable_symbol("exported_variable");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable"));
|
|
CHECK(symbol == corpus->lookup_variable_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_function_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a binary with a single GPL exported variable")
|
|
{
|
|
const std::string binary = base_path + "single_variable_gpl.ko";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 0, 1);
|
|
const elf_symbol_sptr& symbol =
|
|
corpus->lookup_variable_symbol("exported_variable_gpl");
|
|
REQUIRE(symbol);
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable_gpl"));
|
|
CHECK(symbol == corpus->lookup_variable_symbol(*symbol));
|
|
CHECK(symbol != corpus->lookup_function_symbol(*symbol));
|
|
}
|
|
|
|
GIVEN("a binary with one function and one variable (GPL) exported")
|
|
{
|
|
const std::string binary = base_path + "one_of_each.ko";
|
|
const corpus_sptr& corpus = assert_symbol_count(binary, 2, 2);
|
|
CHECK(corpus->lookup_function_symbol("exported_function"));
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function"));
|
|
CHECK(corpus->lookup_function_symbol("exported_function_gpl"));
|
|
CHECK(!corpus->lookup_variable_symbol("exported_function_gpl"));
|
|
CHECK(corpus->lookup_variable_symbol("exported_variable"));
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable"));
|
|
CHECK(corpus->lookup_variable_symbol("exported_variable_gpl"));
|
|
CHECK(!corpus->lookup_function_symbol("exported_variable_gpl"));
|
|
}
|
|
}
|
|
}
|
|
}
|