mirror of
https://github.com/openharmony/third_party_libabigail.git
synced 2026-07-01 06:09:52 -04:00
a506c1d186
Signed-off-by: lizhenlin <lizhenlin2@h-partners.com>
1347 lines
39 KiB
C++
1347 lines
39 KiB
C++
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
// -*- Mode: C++ -*-
|
|
//
|
|
// Copyright (C) 2022-2025 Red Hat, Inc.
|
|
//
|
|
// Author: Dodji Seketeli
|
|
|
|
/// @file
|
|
///
|
|
/// This file contains the definitions of the front-end to analyze the
|
|
/// BTF information contained in an ELF file.
|
|
|
|
#include "abg-internal.h"
|
|
|
|
#ifdef WITH_BTF
|
|
|
|
#include <bpf/btf.h>
|
|
#include <iostream>
|
|
#include <unordered_map>
|
|
|
|
#include "abg-elf-helpers.h"
|
|
#include "abg-ir-priv.h"
|
|
|
|
// <headers defining libabigail's API go under here>
|
|
ABG_BEGIN_EXPORT_DECLARATIONS
|
|
|
|
#include "abg-btf-reader.h"
|
|
#include "abg-ir.h"
|
|
#include "abg-tools-utils.h"
|
|
|
|
ABG_END_EXPORT_DECLARATIONS
|
|
// </headers defining libabigail's API>
|
|
|
|
namespace abigail
|
|
{
|
|
using namespace ir;
|
|
|
|
/// Namespace of the reader for the BTF debug information.
|
|
namespace btf
|
|
{
|
|
|
|
class reader;
|
|
|
|
/// A convenience typedef for a shared pointer to
|
|
/// abigail::btf::reader.
|
|
typedef shared_ptr<reader> reader_sptr;
|
|
|
|
static const char*
|
|
btf_offset_to_string(const ::btf* btf, uint32_t offset)
|
|
{
|
|
if (!offset)
|
|
return "__anonymous__";
|
|
return btf__name_by_offset(btf, offset) ?: "(invalid string offset)";
|
|
}
|
|
|
|
/// A convenience typedef of a map that associates a btf type to a
|
|
/// libabigail ABI artifact. The type is allocated inside a given btf
|
|
/// handle (of type ::btf*). All handles (one for each kernel binary)
|
|
/// should be kept around until a complete corpus group is built.
|
|
typedef std::unordered_map<const btf_type*, type_or_decl_base_sptr>
|
|
btf_type_to_abi_artifact_map_type;
|
|
|
|
/// The BTF front-end abstraction type.
|
|
///
|
|
/// Note that one instance of front-end is meant to analyze one
|
|
/// vmlinux file and all its associated modules. For now, the
|
|
/// front-end doesn't know how to analyze a module without having
|
|
/// analyzed a vmlinux first.
|
|
///
|
|
/// The BTF information of a vmlinux is parsed with the btf__parse
|
|
/// function. The result is called a "base BTF" handle.
|
|
///
|
|
/// The BTF information of a kernel module is parsed with the function
|
|
/// btf__parse_split. The result is called a "split BTF" handle. A
|
|
/// split BTF handle references information that are in the base BTF
|
|
/// handle. The base BTF handle can be retrieved from a split BTF
|
|
/// handle using btf__base_btf.
|
|
class reader : public elf_based_reader
|
|
{
|
|
::btf* base_btf_handle_ = nullptr;
|
|
// The path to the binary that contains the base BTF information
|
|
// held in base_btf_handle_
|
|
string base_btf_file_name_;
|
|
::btf* split_btf_handle_ = nullptr;
|
|
// The path to the binary that contains the split BTF information
|
|
// held in split_btf_handle_
|
|
string split_btf_file_name_;
|
|
// A vector of (split) BTF objects that are to be freed once the
|
|
// corpus group is built for an entire kernel (vmliunx + modules).
|
|
vector<::btf*> split_btfs_to_free_;
|
|
translation_unit_sptr cur_tu_;
|
|
vector<type_base_sptr> types_to_canonicalize_;
|
|
btf_type_to_abi_artifact_map_type btf_type_to_artifacts_;
|
|
|
|
/// Getter of the "do_log" flag.
|
|
///
|
|
/// This flag tells if we should log about various internal
|
|
/// details.
|
|
///
|
|
/// return the "do_log" flag.
|
|
bool
|
|
do_log() const
|
|
{return options().do_log;}
|
|
|
|
/// Setter of the "do_log" flag.
|
|
///
|
|
/// This flag tells if we should log about various internal details.
|
|
///
|
|
/// @param f the new value of the flag.
|
|
void
|
|
do_log(bool f)
|
|
{options().do_log = f;}
|
|
|
|
/// Getter of the "show_stats" flag.
|
|
///
|
|
/// This flag tells if we should emit statistics about various
|
|
/// internal stuff.
|
|
///
|
|
/// @return the value of the flag.
|
|
bool
|
|
show_stats() const
|
|
{return options().show_stats;}
|
|
|
|
/// Setter of the "show_stats" flag.
|
|
///
|
|
/// This flag tells if we should emit statistics about various
|
|
/// internal stuff.
|
|
///
|
|
/// @param f the value of the flag.
|
|
void
|
|
show_stats(bool f)
|
|
{options().show_stats = f;}
|
|
|
|
/// Getter of the handle to the base BTF object of the current
|
|
/// binary being analyzed.
|
|
///
|
|
/// The base BTF object ALWAYS represents the BTF information of the
|
|
/// vmlinux binary, even if the current binary being analyzed is a
|
|
/// kernel module.
|
|
///
|
|
/// @return handle to the base BTF object of the current binary
|
|
/// being analyzed.
|
|
::btf*
|
|
base_btf_handle()
|
|
{
|
|
if (base_btf_handle_ == nullptr)
|
|
{
|
|
base_btf_handle_ = btf__parse(corpus_path().c_str(), nullptr);
|
|
if (!base_btf_handle_)
|
|
{
|
|
std::cerr << "Could not parse base BTF information from file '"
|
|
<< corpus_path().c_str() << "'" << std::endl;
|
|
return nullptr;
|
|
}
|
|
base_btf_file_name_ = corpus_path();
|
|
}
|
|
return base_btf_handle_;
|
|
}
|
|
|
|
/// Read the BTF information of the current binary which path is
|
|
/// @ref fe_iface::corpus_path() and return its associated object
|
|
/// handle. This is called the split BTF object.
|
|
///
|
|
/// Note that this function expects the base BTF object (the one for
|
|
/// the vmlinux binary) to be already present, otherwise, it returns
|
|
/// nullptr.
|
|
///
|
|
/// @return the split BTF object for the file designed by
|
|
/// fe_iface::corpus_path().
|
|
::btf*
|
|
read_split_btf()
|
|
{
|
|
if (!base_btf_handle_)
|
|
{
|
|
std::cerr << "Base BTF information not present. "
|
|
<< "Not attempting to parse split BTF information"
|
|
<< std::endl;
|
|
return nullptr;
|
|
}
|
|
|
|
if (corpus_path().empty() || corpus_path() == base_btf_file_name_)
|
|
{
|
|
std::cerr << "BTF reader not initialized with split file name. "
|
|
<< "Not attending to read split BTF information"
|
|
<< std::endl;
|
|
return nullptr;
|
|
}
|
|
|
|
split_btf_handle_ = btf__parse_split(corpus_path().c_str(),
|
|
base_btf_handle());
|
|
if (!split_btf_handle_)
|
|
{
|
|
std::cerr << "Could not read split BTF information from file "
|
|
<< corpus_path() << std::endl;
|
|
return nullptr;
|
|
}
|
|
split_btf_file_name_ = corpus_path();
|
|
|
|
return split_btf_handle_;
|
|
}
|
|
|
|
/// Getter of the handle to the BTF object as returned by libbpf.
|
|
///
|
|
/// This returns the handle to the current BTF object. If the
|
|
/// current BTF object is for a vmlinux binary, then it's the base
|
|
/// BTF object that is returned. Otherwise, if the current BTF
|
|
/// object if for a kernel module then it's the split BTF object
|
|
/// that is returned.
|
|
///
|
|
/// @return the handle to the BTF object of the current binary being
|
|
/// analyeed by this front-end.
|
|
::btf*
|
|
btf_handle()
|
|
{
|
|
if (split_btf_handle_)
|
|
return split_btf_handle_;
|
|
|
|
if (!base_btf_handle_)
|
|
return base_btf_handle();
|
|
|
|
if (corpus_path() != base_btf_file_name_)
|
|
// The reader was re-initialized with a corpus_path that is
|
|
// different from the the BTF base file. That means we are
|
|
// instructed to read a split BTF file information.
|
|
return read_split_btf();
|
|
|
|
return base_btf_handle();
|
|
}
|
|
|
|
/// Getter of the environment of the current front-end.
|
|
///
|
|
/// @return The environment of the current front-end.
|
|
environment&
|
|
env()
|
|
{return options().env;}
|
|
|
|
/// Getter of the environment of the current front-end.
|
|
///
|
|
/// @return The environment of the current front-end.
|
|
const environment&
|
|
env() const
|
|
{return const_cast<reader*>(this)->env();}
|
|
|
|
/// Getter of the current translation unit being built.
|
|
///
|
|
/// Actually, BTF doesn't keep track of the translation unit each
|
|
/// ABI artifact originates from. So an "artificial" translation
|
|
/// unit is built. It contains all the ABI artifacts of the binary.
|
|
///
|
|
/// @return The current translation unit being built.
|
|
translation_unit_sptr&
|
|
cur_tu()
|
|
{return cur_tu_;}
|
|
|
|
/// Getter of the current translation unit being built.
|
|
///
|
|
/// Actually, BTF doesn't keep track of the translation unit each
|
|
/// ABI artifact originates from. So an "artificial" translation
|
|
/// unit is built. It contains all the ABI artifacts of the binary.
|
|
///
|
|
/// @return The current translation unit being built.
|
|
const translation_unit_sptr&
|
|
cur_tu() const
|
|
{return cur_tu_;}
|
|
|
|
/// Getter of the current translation unit being built.
|
|
///
|
|
/// Actually, BTF doesn't keep track of the translation unit each
|
|
/// ABI artifact originates from. So an "artificial" translation
|
|
/// unit is built. It contains all the ABI artifacts of the binary.
|
|
///
|
|
/// @return The current translation unit being built.
|
|
void
|
|
cur_tu(const translation_unit_sptr& tu)
|
|
{cur_tu_ = tu;}
|
|
|
|
/// Getter of the map that associates a BTF type to the internal
|
|
/// representation of an ABI artifact.
|
|
///
|
|
/// @return The map that associates a BTF type to the IR of an ABI
|
|
/// artifact.
|
|
btf_type_to_abi_artifact_map_type&
|
|
btf_type_to_artifacts()
|
|
{return btf_type_to_artifacts_;}
|
|
|
|
/// Getter of the map that associates a BTF type to the IR of an ABI
|
|
/// artifact.
|
|
///
|
|
/// @return The map that associates a BTF type to the IR of an ABI
|
|
/// artifact.
|
|
const btf_type_to_abi_artifact_map_type&
|
|
btf_type_to_artifacts() const
|
|
{return btf_type_to_artifacts_;}
|
|
|
|
/// Get the IR of the ABI artifact that is associated to a given BTF
|
|
/// type.
|
|
///
|
|
/// If no ABI artifact is associated to the BTF type, then return
|
|
/// nullptr.
|
|
///
|
|
/// @return the ABI artifact that is associated to a given BTF type.
|
|
type_or_decl_base_sptr
|
|
lookup_artifact_from_btf_type(const btf_type* t)
|
|
{
|
|
auto i = btf_type_to_artifacts().find(t);
|
|
if (i != btf_type_to_artifacts().end())
|
|
return i->second;
|
|
return type_or_decl_base_sptr();
|
|
}
|
|
|
|
/// Associate an ABI artifact to a given BTF type.
|
|
///
|
|
/// @param artifact the ABI artifact to consider.
|
|
///
|
|
/// @param btf_type_id the BTF type to associate to @p artifact.
|
|
void
|
|
associate_artifact_to_btf_type(const type_or_decl_base_sptr& artifact,
|
|
const btf_type* t)
|
|
{btf_type_to_artifacts()[t] = artifact;}
|
|
|
|
/// Schecule a type for canonicalization at the end of the debug
|
|
/// info loading.
|
|
///
|
|
/// @param t the type to schedule.
|
|
void
|
|
schedule_type_for_canonicalization(const type_base_sptr& t)
|
|
{
|
|
if (t && !t->get_naked_canonical_type())
|
|
types_to_canonicalize_.push_back(t);
|
|
}
|
|
|
|
/// Canonicalize all the types scheduled for canonicalization using
|
|
/// abigail::ir::canonicalize_types() which performs some sanity
|
|
/// checking around type canonicalization if necessary.
|
|
void
|
|
canonicalize_types()
|
|
{
|
|
tools_utils::timer cn_timer;
|
|
if (do_log())
|
|
{
|
|
std::cerr << "BTF Reader is going to canonicalize "
|
|
<< std::dec
|
|
<< types_to_canonicalize_.size()
|
|
<< " types";
|
|
corpus_sptr c = corpus();
|
|
if (c)
|
|
std::cerr << " from corpus " << corpus()->get_path() << "\n";
|
|
cn_timer.start();
|
|
}
|
|
|
|
ir::hash_and_canonicalize_types(types_to_canonicalize_.begin(),
|
|
types_to_canonicalize_.end(),
|
|
[](const vector<type_base_sptr>::const_iterator& i)
|
|
{return *i;}, do_log(), show_stats());
|
|
|
|
if (do_log())
|
|
{
|
|
cn_timer.stop();
|
|
std::cerr << "BTF Reader finished types "
|
|
<< "sorting, hashing & canonicalizing in: "
|
|
<< cn_timer << "\n";
|
|
}
|
|
|
|
}
|
|
|
|
/// Getter of the number of types carried by a given BTF object.
|
|
///
|
|
/// @param handle the BTF object to consider.
|
|
///
|
|
/// @return the number of types carried by a given BTF object.
|
|
uint64_t
|
|
nr_btf_types(const ::btf* handle) const
|
|
{
|
|
#ifdef WITH_BTF__GET_NR_TYPES
|
|
#define GET_NB_TYPES btf__get_nr_types
|
|
#endif
|
|
|
|
#ifdef WITH_BTF__TYPE_CNT
|
|
#undef GET_NB_TYPES
|
|
#define GET_NB_TYPES btf__type_cnt
|
|
#endif
|
|
|
|
#ifndef GET_NB_TYPES
|
|
ABG_ASSERT_NOT_REACHED;
|
|
return 0;
|
|
#endif
|
|
|
|
return GET_NB_TYPES(handle);
|
|
}
|
|
|
|
protected:
|
|
reader() = delete;
|
|
|
|
/// Initializer of the current instance of @ref btf::reader.
|
|
///
|
|
/// This frees the resources used by the current instance of @ref
|
|
/// btf::reader and gets it ready to analyze another ELF
|
|
/// file.
|
|
///
|
|
/// @param elf_path the path to the ELF file to read from.
|
|
///
|
|
/// @param debug_info_root_paths the paths where to look for
|
|
/// seperate debug info.
|
|
///
|
|
/// @param load_all_types if true, then load all the types described
|
|
/// in the binary, rather than loading only the types reachable from
|
|
/// the exported decls.
|
|
///
|
|
/// @param linux_kernel_mode
|
|
void
|
|
initialize(const string& elf_path,
|
|
const vector<string>& debug_info_root_paths,
|
|
bool load_all_types,
|
|
bool linux_kernel_mode)
|
|
{
|
|
if (split_btf_handle_)
|
|
{
|
|
// We need to keep this split_btf_handle_ on the side so that
|
|
// we can free it when we are done analyzing all the kernel
|
|
// modules. We cannot free it right now because the memory of
|
|
// all btf types lives in it.
|
|
split_btfs_to_free_.push_back(split_btf_handle_);
|
|
split_btf_handle_ = nullptr;
|
|
}
|
|
|
|
split_btf_file_name_.clear();
|
|
types_to_canonicalize_.clear();
|
|
cur_tu_.reset();
|
|
elf_based_reader::initialize(elf_path, debug_info_root_paths);
|
|
corpus_path(elf_path);
|
|
options().load_all_types = load_all_types;
|
|
options().load_in_linux_kernel_mode = linux_kernel_mode;
|
|
}
|
|
|
|
/// Constructor of the btf::reader type.
|
|
///
|
|
/// @param elf_path the path to the ELF file to analyze.
|
|
///
|
|
/// @param debug_info_root_paths the set of directory where to look
|
|
/// debug info from, for cases where the debug is split.
|
|
///
|
|
/// @param environment the environment of the current front-end.
|
|
///
|
|
/// @param load_all_types if true load all the types described by
|
|
/// the BTF debug info, as opposed to loading only the types
|
|
/// reachable from the decls that are defined and exported.
|
|
///
|
|
/// @param linux_kernel_mode if true, then consider the binary being
|
|
/// analyzed as a linux kernel binary.
|
|
reader(const string& elf_path,
|
|
const vector<string>& debug_info_root_paths,
|
|
environment& environment,
|
|
bool load_all_types,
|
|
bool linux_kernel_mode)
|
|
: elf_based_reader(elf_path,
|
|
debug_info_root_paths,
|
|
environment)
|
|
{
|
|
initialize(elf_path, debug_info_root_paths,
|
|
load_all_types, linux_kernel_mode);
|
|
}
|
|
|
|
public:
|
|
|
|
/// Constructor of the btf::reader type.
|
|
///
|
|
/// @param elf_path the path to the ELF file to analyze.
|
|
///
|
|
/// @param debug_info_root_paths the set of directory where to look
|
|
/// debug info from, for cases where the debug is split.
|
|
///
|
|
/// @param environment the environment of the current front-end.
|
|
///
|
|
/// @param load_all_types if true load all the types described by
|
|
/// the BTF debug info, as opposed to loading only the types
|
|
/// reachable from the decls that are defined and exported.
|
|
///
|
|
/// @param linux_kernel_mode if true, then consider the binary being
|
|
/// analyzed as a linux kernel binary.
|
|
static btf::reader_sptr
|
|
create(const string& elf_path,
|
|
const vector<string>& debug_info_root_paths,
|
|
environment& environment,
|
|
bool load_all_types,
|
|
bool linux_kernel_mode)
|
|
{
|
|
reader_sptr result(new reader(elf_path, debug_info_root_paths, environment,
|
|
load_all_types, linux_kernel_mode));
|
|
return result;
|
|
}
|
|
|
|
/// Destructor of the btf::reader type.
|
|
~reader()
|
|
{
|
|
for (auto b : split_btfs_to_free_)
|
|
btf__free(b);
|
|
btf__free(split_btf_handle_);
|
|
btf__free(base_btf_handle_);
|
|
split_btf_handle_ = nullptr;
|
|
base_btf_handle_ = nullptr;
|
|
}
|
|
|
|
/// Read the ELF information as well as the BTF type information to
|
|
/// build an ABI corpus.
|
|
///
|
|
/// @param status output parameter. The status of the analysis.
|
|
///
|
|
/// @return the resulting ABI corpus.
|
|
corpus_sptr
|
|
read_corpus(status& status)
|
|
{
|
|
// Read the properties of the ELF file.
|
|
elf::reader::read_corpus(status);
|
|
|
|
corpus::origin origin = corpus()->get_origin();
|
|
origin |= corpus::BTF_ORIGIN;
|
|
corpus()->set_origin(origin);
|
|
if (corpus_group())
|
|
{
|
|
origin |= corpus_group()->get_origin();
|
|
corpus_group()->set_origin(origin);
|
|
}
|
|
|
|
if ((status & STATUS_NO_SYMBOLS_FOUND)
|
|
|| !(status & STATUS_OK))
|
|
// Either we couldn't find ELF symbols or something went badly
|
|
// wrong. There is nothing we can do with this ELF file. Bail
|
|
// out.
|
|
return corpus_sptr();
|
|
|
|
if (find_btf_section() == nullptr)
|
|
status |= STATUS_DEBUG_INFO_NOT_FOUND;
|
|
|
|
read_debug_info_into_corpus();
|
|
|
|
status |= STATUS_OK;
|
|
|
|
return corpus();
|
|
}
|
|
|
|
/// Read the BTF debug info to construct the ABI corpus.
|
|
///
|
|
/// @return the resulting ABI corpus.
|
|
corpus_sptr
|
|
read_debug_info_into_corpus()
|
|
{
|
|
if (!btf_handle())
|
|
return corpus_sptr();
|
|
|
|
translation_unit_sptr artificial_tu
|
|
(new translation_unit(env(), "", /*address_size=*/64));
|
|
corpus()->add(artificial_tu);
|
|
cur_tu(artificial_tu);
|
|
|
|
#ifdef WITH_DEBUG_SELF_COMPARISON
|
|
if (env().self_comparison_debug_is_on())
|
|
{
|
|
corpus_group_sptr g = corpus_group();
|
|
if (g)
|
|
env().set_self_comparison_debug_input(g);
|
|
else
|
|
env().set_self_comparison_debug_input(corpus());
|
|
}
|
|
#endif
|
|
|
|
int number_of_types = nr_btf_types(btf_handle());
|
|
int first_type_id = 1;
|
|
// Are we looking at the BTF for a kernel module?
|
|
const ::btf* base = btf__base_btf(btf_handle());
|
|
if (base)
|
|
{
|
|
// So, base is non-nil. This means we are looking at the BTF
|
|
// for a kernel module and base points to the BTF for the
|
|
// corresponding vmlinux. That base BTF should be the same as
|
|
// base_btf_handle().
|
|
ABG_ASSERT(base == base_btf_handle());
|
|
|
|
// The ID of the first type that is contained in this BTF
|
|
// representing a kernel module is the number of types
|
|
// contained in the base BTF (i.e, the BTF for the vmlinux
|
|
// binary).
|
|
first_type_id = nr_btf_types(base);
|
|
}
|
|
|
|
// Let's cycle through whatever is described in the BTF section
|
|
// and emit libabigail IR for it.
|
|
for (int type_id = first_type_id;
|
|
type_id < number_of_types;
|
|
++type_id)
|
|
{
|
|
// Build IR nodes only for decls (functions and variables)
|
|
// that have associated ELF symbols that are publicly defined
|
|
// and exported, unless the user asked to load all types.
|
|
|
|
bool do_construct_ir_node = false;
|
|
|
|
const btf_type* t = btf__type_by_id(btf_handle(), type_id);
|
|
string name;
|
|
if (t->name_off)
|
|
name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
|
|
int kind = btf_kind(t);
|
|
if (kind == BTF_KIND_FUNC)
|
|
{
|
|
ABG_ASSERT(!name.empty());
|
|
if (btf_vlen(t) == BTF_FUNC_GLOBAL
|
|
|| btf_vlen(t) == BTF_FUNC_EXTERN
|
|
|| function_symbol_is_exported(name))
|
|
do_construct_ir_node = true;
|
|
}
|
|
else if (kind == BTF_KIND_VAR)
|
|
{
|
|
ABG_ASSERT(!name.empty());
|
|
if (btf_vlen(t) == BTF_VAR_GLOBAL_ALLOCATED
|
|
|| btf_vlen(t) == BTF_VAR_GLOBAL_EXTERN
|
|
|| variable_symbol_is_exported(name))
|
|
do_construct_ir_node = true;
|
|
}
|
|
else if (options().load_all_types)
|
|
do_construct_ir_node = true;
|
|
|
|
if (do_construct_ir_node)
|
|
build_ir_node_from_btf_type(type_id);
|
|
}
|
|
|
|
canonicalize_types();
|
|
corpus()->sort_functions();
|
|
corpus()->sort_variables();
|
|
return corpus();
|
|
}
|
|
|
|
/// Build an abigail IR node for a given type described by a BTF
|
|
/// type ID. The node is added to the ABI corpus.
|
|
///
|
|
/// @param type_id the ID of the type to build and IR node for.
|
|
///
|
|
/// @return the IR node representing the type @p type_id.
|
|
type_or_decl_base_sptr
|
|
build_ir_node_from_btf_type(int type_id)
|
|
{
|
|
type_or_decl_base_sptr result;
|
|
const btf_type *t = nullptr;
|
|
|
|
t = btf__type_by_id(btf_handle(), type_id);
|
|
|
|
if ((result = lookup_artifact_from_btf_type(t)))
|
|
return result;
|
|
|
|
if (!result)
|
|
{
|
|
ABG_ASSERT(t);
|
|
int type_kind = btf_kind(t);
|
|
|
|
switch(type_kind)
|
|
{
|
|
case BTF_KIND_UNKN/* Unknown: This is really for the void
|
|
type. */:
|
|
result = build_ir_node_for_void_type();
|
|
break;
|
|
|
|
case BTF_KIND_INT/* Integer */:
|
|
result = build_int_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_FLOAT/* Floating point */:
|
|
result = build_float_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_TYPEDEF/* Typedef*/:
|
|
result = build_typedef_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_PTR/* Pointer */:
|
|
result = build_pointer_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_ARRAY/* Array */:
|
|
result = build_array_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_ENUM/* Enumeration up to 32-bit values */:
|
|
#ifdef WITH_BTF_ENUM64
|
|
case BTF_KIND_ENUM64/* Enumeration up to 64-bit values */:
|
|
#endif
|
|
result = build_enum_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_STRUCT/* Struct */:
|
|
case BTF_KIND_UNION/* Union */:
|
|
result = build_class_or_union_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_FWD/* Forward */:
|
|
result = build_class_or_union_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_CONST/* Const */:
|
|
case BTF_KIND_VOLATILE/* Volatile */:
|
|
case BTF_KIND_RESTRICT/* Restrict */:
|
|
result = build_qualified_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_FUNC/* Function */:
|
|
result = build_function_decl(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_FUNC_PROTO/* Function Proto */:
|
|
result = build_function_type(type_id);
|
|
break;
|
|
|
|
case BTF_KIND_VAR/* Variable */:
|
|
result = build_variable_decl(type_id);
|
|
break;
|
|
|
|
#ifdef WITH_BTF_KIND_TYPE_TAG
|
|
case BTF_KIND_TYPE_TAG/* Type Tag */:
|
|
break;
|
|
#endif
|
|
#ifdef WITH_BTF_KIND_DECL_TAG
|
|
case BTF_KIND_DECL_TAG/* Decl Tag */:
|
|
break;
|
|
#endif
|
|
case BTF_KIND_DATASEC/* Section */:
|
|
break;
|
|
default:
|
|
ABG_ASSERT_NOT_REACHED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
add_decl_to_scope(is_decl(result), cur_tu()->get_global_scope());
|
|
|
|
if (type_base_sptr type = is_type(result))
|
|
schedule_type_for_canonicalization(type);
|
|
|
|
associate_artifact_to_btf_type(result, t);
|
|
|
|
if (function_decl_sptr fn = is_function_decl(result))
|
|
add_fn_to_exported_or_undefined_decls(fn.get());
|
|
else if (var_decl_sptr var = is_var_decl(result))
|
|
add_var_to_exported_or_undefined_decls(var);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for the "void" type.
|
|
///
|
|
/// @return the IR node for the void type.
|
|
type_base_sptr
|
|
build_ir_node_for_void_type()
|
|
{
|
|
type_base_sptr t = env().get_void_type();
|
|
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
|
|
schedule_type_for_canonicalization(t);
|
|
return t;
|
|
}
|
|
|
|
/// Build an IR node for the "void" type.
|
|
///
|
|
/// @return the IR node for the void type.
|
|
type_base_sptr
|
|
build_ir_node_for_void_pointer_type()
|
|
{
|
|
type_base_sptr t = env().get_void_pointer_type();
|
|
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
|
|
schedule_type_for_canonicalization(t);
|
|
return t;
|
|
}
|
|
|
|
/// Build an IR node for the "variadic parameter" type.
|
|
///
|
|
/// @return the IR node for the "variadic parameter" type.
|
|
type_base_sptr
|
|
build_ir_node_for_variadic_parameter_type()
|
|
{
|
|
type_base_sptr t = env().get_variadic_parameter_type();
|
|
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
|
|
decl_base_sptr t_decl = get_type_declaration(t);
|
|
schedule_type_for_canonicalization(t);
|
|
return t;
|
|
}
|
|
|
|
/// Build an IR node for an integer type expressed in BTF.
|
|
///
|
|
/// @param t a pointer a BTF type describing an integer.
|
|
///
|
|
/// @return a pointer to @ref type_decl representing an integer
|
|
/// type.
|
|
type_or_decl_base_sptr
|
|
build_int_type(int type_id)
|
|
{
|
|
type_decl_sptr result;
|
|
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
ABG_ASSERT(btf_kind(t) == BTF_KIND_INT);
|
|
|
|
uint32_t info = *reinterpret_cast<const uint32_t*>(t + 1);
|
|
uint64_t byte_size = 0, bit_size = 0;
|
|
string type_name;
|
|
|
|
byte_size = t->size;
|
|
bit_size = byte_size * 8;
|
|
|
|
if (BTF_INT_ENCODING(info) & BTF_INT_CHAR)
|
|
{
|
|
if (!(BTF_INT_ENCODING(info) & BTF_INT_SIGNED))
|
|
type_name = "unsigned ";
|
|
type_name += "char";
|
|
}
|
|
else if (BTF_INT_ENCODING(info) & BTF_INT_BOOL)
|
|
type_name = "bool";
|
|
else if (!(BTF_INT_ENCODING(info) & BTF_INT_SIGNED))
|
|
{
|
|
type_name = "unsigned ";
|
|
type_name += btf_offset_to_string(btf_handle(), t->name_off);
|
|
}
|
|
else
|
|
type_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
|
|
location loc;
|
|
result.reset(new type_decl(env(), type_name,
|
|
bit_size, /*alignment=*/0,
|
|
loc, type_name));
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a float type expressed in BTF.
|
|
///
|
|
/// @return a pointer to @ref type_decl representing a float type.
|
|
type_or_decl_base_sptr
|
|
build_float_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
ABG_ASSERT(btf_kind(t) == BTF_KIND_FLOAT);
|
|
|
|
string type_name = btf_offset_to_string(btf_handle(), t->name_off);;
|
|
uint64_t byte_size = t->size, bit_size = byte_size * 8;
|
|
location loc;
|
|
type_decl_sptr result(new type_decl(env(), type_name, bit_size,
|
|
/*alignment=*/0, loc, type_name));
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR type that represents the underlying type of an enum type.
|
|
///
|
|
/// This is a sub-routine of the build_enum_type() function.
|
|
///
|
|
/// @param enum_name the name of the enum type this type is an
|
|
/// underlying type for.
|
|
///
|
|
/// @param enum_size the size of the enum.
|
|
///
|
|
/// @param is_anonymous if true, the enum type is anonymous.
|
|
///
|
|
/// @return a pointer to type_decl that represents a integer type
|
|
/// that is the underlying type of an enum type.
|
|
type_decl_sptr
|
|
build_enum_underlying_type(const string enum_name, uint64_t enum_size,
|
|
bool is_anonymous = true)
|
|
{
|
|
string underlying_type_name =
|
|
build_internal_underlying_enum_type_name(enum_name,
|
|
is_anonymous,
|
|
enum_size);
|
|
type_decl_sptr result(new type_decl(env(), underlying_type_name,
|
|
enum_size, enum_size, location()));
|
|
result->set_is_anonymous(is_anonymous);
|
|
result->set_is_artificial(true);
|
|
add_decl_to_scope(result, cur_tu()->get_global_scope());
|
|
schedule_type_for_canonicalization(result);
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node that represents an enum type expressed in BTF.
|
|
///
|
|
/// @param type_id the ID of the BTF representation of the enum.
|
|
///
|
|
/// @return a pointer to @ref enum_type_decl representing @p t.
|
|
type_or_decl_base_sptr
|
|
build_enum_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
#ifdef WITH_BTF_ENUM64
|
|
ABG_ASSERT(kind == BTF_KIND_ENUM || kind == BTF_KIND_ENUM64);
|
|
#else
|
|
ABG_ASSERT(kind == BTF_KIND_ENUM);
|
|
#endif
|
|
|
|
int byte_size = t->size, bit_size = byte_size * 8;
|
|
|
|
string enum_name;
|
|
if (t->name_off)
|
|
enum_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
bool is_anonymous = enum_name.empty();
|
|
|
|
int num_enms = btf_vlen(t);
|
|
enum_type_decl::enumerators enms;
|
|
string e_name;
|
|
if (kind == BTF_KIND_ENUM)
|
|
{
|
|
const struct btf_enum* e = btf_enum(t);
|
|
uint32_t e_value = 0;
|
|
for (int i = 0; i < num_enms; ++i, ++e)
|
|
{
|
|
e_name = btf_offset_to_string(btf_handle(), e->name_off);
|
|
e_value = e->val;
|
|
enms.push_back(enum_type_decl::enumerator(e_name, e_value));
|
|
}
|
|
}
|
|
#ifdef WITH_BTF_ENUM64
|
|
else if (kind == BTF_KIND_ENUM64)
|
|
{
|
|
const struct btf_enum64* e =
|
|
reinterpret_cast<const struct btf_enum64*>(t + 1);
|
|
uint64_t e_value = 0;
|
|
for (int i = 0; i < num_enms; ++i, ++e)
|
|
{
|
|
e_name = btf_offset_to_string(btf_handle(), e->name_off);
|
|
e_value = (static_cast<uint64_t>(e->val_hi32) << 32) | e->val_lo32;
|
|
enms.push_back(enum_type_decl::enumerator(e_name, e_value));
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
ABG_ASSERT_NOT_REACHED;
|
|
|
|
type_decl_sptr underlying_type =
|
|
build_enum_underlying_type(enum_name, bit_size, is_anonymous);
|
|
enum_type_decl_sptr result(new enum_type_decl(enum_name,
|
|
location(),
|
|
underlying_type,
|
|
enms, enum_name));
|
|
result->set_is_anonymous(is_anonymous);
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a typedef that is expressed in BTF.
|
|
///
|
|
/// @param type_id the ID of the BTF representation of a typedef.
|
|
///
|
|
/// @return a pointer to @ref typedef_decl representing @p t.
|
|
type_or_decl_base_sptr
|
|
build_typedef_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_TYPEDEF);
|
|
|
|
string type_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
type_base_sptr underlying_type =
|
|
is_type(build_ir_node_from_btf_type(t->type));
|
|
if (!underlying_type)
|
|
return type_or_decl_base_sptr();
|
|
|
|
typedef_decl_sptr result(new typedef_decl(type_name, underlying_type,
|
|
location(),
|
|
/*linkage_name=*/type_name));
|
|
if ((is_class_or_union_type(underlying_type)
|
|
|| is_enum_type(underlying_type))
|
|
&& is_anonymous_type(underlying_type))
|
|
get_type_declaration(underlying_type)->set_naming_typedef(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node representing a pointer described in BTF.
|
|
///
|
|
/// @param type_id the ID of a BTF representation of a pointer type.
|
|
///
|
|
/// @return a pointer to pointer_type_def that represents @p t.
|
|
type_or_decl_base_sptr
|
|
build_pointer_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_PTR);
|
|
|
|
type_base_sptr underlying_type =
|
|
is_type(build_ir_node_from_btf_type(t->type));
|
|
if (!underlying_type)
|
|
return type_or_decl_base_sptr();
|
|
if (env().is_void_type(underlying_type))
|
|
// Recognize a pointer to void and return a special unique IR
|
|
// for it.
|
|
return build_ir_node_for_void_pointer_type();
|
|
|
|
int size = elf_helpers::get_architecture_word_size(elf_handle());
|
|
size *= 8;
|
|
pointer_type_def_sptr result(new pointer_type_def(underlying_type, size,
|
|
/*alignment=*/0,
|
|
location()));
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node representing an array type described in BTF.
|
|
///
|
|
/// @param type_id the ID of the BTF representation of an array
|
|
/// type.
|
|
///
|
|
/// return a pointer to @ref array_type_def representing @p t.
|
|
type_or_decl_base_sptr
|
|
build_array_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_ARRAY);
|
|
|
|
const struct btf_array* arr = btf_array(t);
|
|
|
|
type_base_sptr underlying_type =
|
|
is_type(build_ir_node_from_btf_type(arr->type));
|
|
if (!underlying_type)
|
|
return type_or_decl_base_sptr();
|
|
|
|
uint64_t lower_bound = 0;
|
|
// Note that arr->nelems can be 0;
|
|
uint64_t upper_bound = arr->nelems ? arr->nelems - 1: 0;
|
|
|
|
array_type_def::subrange_sptr subrange(new array_type_def::subrange_type
|
|
(env(), /*name=*/"",
|
|
lower_bound, upper_bound,
|
|
location()));
|
|
subrange->is_non_finite(!arr->nelems);
|
|
subrange->set_size_in_bits(cur_tu()->get_address_size());
|
|
add_decl_to_scope(subrange, cur_tu()->get_global_scope());
|
|
schedule_type_for_canonicalization(subrange);
|
|
array_type_def::subranges_type subranges = {subrange};
|
|
array_type_def_sptr result(new array_type_def(underlying_type,
|
|
subranges, location()));
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node representing a qualified type described in BTF.
|
|
///
|
|
/// @param type_id the ID of the BTF representation of an array
|
|
/// type.
|
|
///
|
|
/// @return a pointer to a qualified_type_def representing @ t.
|
|
type_or_decl_base_sptr
|
|
build_qualified_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_CONST
|
|
|| kind == BTF_KIND_VOLATILE
|
|
|| kind == BTF_KIND_RESTRICT);
|
|
|
|
type_base_sptr underlying_type =
|
|
is_type(build_ir_node_from_btf_type(t->type));
|
|
if (!underlying_type)
|
|
return type_or_decl_base_sptr();
|
|
|
|
qualified_type_def::CV qual = qualified_type_def::CV_NONE;
|
|
if (kind == BTF_KIND_CONST)
|
|
qual |= qualified_type_def::CV_CONST;
|
|
else if (kind == BTF_KIND_VOLATILE)
|
|
qual |= qualified_type_def::CV_VOLATILE;
|
|
else if (kind == BTF_KIND_RESTRICT)
|
|
qual |= qualified_type_def::CV_RESTRICT;
|
|
else
|
|
ABG_ASSERT_NOT_REACHED;
|
|
|
|
qualified_type_def_sptr result(new qualified_type_def(underlying_type,
|
|
qual, location()));
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a class or union type expressed in BTF.
|
|
///
|
|
/// @param type_id the ID of a pointer to a BTF type describing a
|
|
/// class or union type.
|
|
///
|
|
/// @return a pointer to either a @ref class_decl or a @ref
|
|
/// union_decl type representing the type expressed by @p t.
|
|
type_or_decl_base_sptr
|
|
build_class_or_union_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_STRUCT
|
|
|| kind == BTF_KIND_UNION
|
|
|| kind == BTF_KIND_FWD);
|
|
|
|
string type_name;
|
|
if (t->name_off)
|
|
type_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
|
|
bool is_anonymous = type_name.empty();
|
|
uint64_t size = t->size;
|
|
size *= 8;
|
|
|
|
bool is_decl_only = (kind == BTF_KIND_FWD);
|
|
|
|
class_or_union_sptr result;
|
|
if (kind == BTF_KIND_STRUCT
|
|
|| (kind == BTF_KIND_FWD
|
|
&& BTF_INFO_KFLAG(t->info) == 0 /*struct*/))
|
|
result.reset(new class_decl(env(), type_name, size,
|
|
/*alignment=*/0,
|
|
/*is_struct=*/true,
|
|
location(),
|
|
decl_base::VISIBILITY_DEFAULT,
|
|
is_anonymous));
|
|
else if (kind == BTF_KIND_UNION
|
|
|| (kind == BTF_KIND_FWD
|
|
&& BTF_INFO_KFLAG(t->info) == 1/*union*/))
|
|
result.reset(new union_decl(env(), type_name, size, location(),
|
|
decl_base::VISIBILITY_DEFAULT,
|
|
is_anonymous));
|
|
else
|
|
ABG_ASSERT_NOT_REACHED;
|
|
|
|
if (is_decl_only)
|
|
result->set_is_declaration_only(is_decl_only);
|
|
|
|
add_decl_to_scope(result, cur_tu()->get_global_scope());
|
|
|
|
associate_artifact_to_btf_type(result, t);
|
|
|
|
// For defined classes and unions, add data members to the type
|
|
// being built.
|
|
if (!is_decl_only)
|
|
{
|
|
const struct btf_member *m =
|
|
reinterpret_cast<const struct btf_member*>(t + 1);
|
|
uint64_t nb_members = btf_vlen(t);
|
|
|
|
for (uint64_t i = 0; i < nb_members; ++i, ++m)
|
|
{
|
|
type_base_sptr member_type =
|
|
is_type(build_ir_node_from_btf_type(m->type));
|
|
if (!member_type)
|
|
continue;
|
|
|
|
string member_name;
|
|
if (m->name_off)
|
|
member_name = btf_offset_to_string(btf_handle(), m->name_off);
|
|
var_decl_sptr data_member(new var_decl(member_name,
|
|
member_type,
|
|
location(),
|
|
/*linkage_name=*/""));
|
|
uint64_t offset_in_bits =
|
|
BTF_INFO_KFLAG(t->info)
|
|
? BTF_MEMBER_BIT_OFFSET(m->offset)
|
|
: m->offset;
|
|
|
|
result->add_data_member(data_member,
|
|
public_access,
|
|
/*is_laid_out=*/true,
|
|
/*is_static=*/false,
|
|
offset_in_bits);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a function type expressed in BTF.
|
|
///
|
|
/// @param type_id the ID of a pointer to a BTF type describing a
|
|
/// function type.
|
|
///
|
|
/// @return a pointer to a @ref function_type representing the
|
|
/// function type expressed by @p t.
|
|
type_or_decl_base_sptr
|
|
build_function_type(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_FUNC_PROTO);
|
|
|
|
type_base_sptr return_type = is_type(build_ir_node_from_btf_type(t->type));
|
|
if (return_type == nullptr)
|
|
return type_or_decl_base_sptr();
|
|
|
|
int address_size = elf_helpers::get_architecture_word_size(elf_handle());
|
|
address_size *= 8;
|
|
function_type_sptr result(new function_type(env(), address_size,
|
|
/*alignment=*/0));
|
|
result->set_return_type(return_type);
|
|
|
|
associate_artifact_to_btf_type(result, t);
|
|
|
|
uint16_t nb_parms = btf_vlen(t);
|
|
const struct btf_param* parm =
|
|
reinterpret_cast<const struct btf_param*>(t + 1);
|
|
|
|
function_decl::parameters function_parms;
|
|
for (uint16_t i = 0; i < nb_parms; ++i, ++parm)
|
|
{
|
|
type_base_sptr parm_type;
|
|
string parm_name;
|
|
bool is_variadic = false;
|
|
|
|
if (parm->name_off == 0 && parm->type == 0)
|
|
{
|
|
is_variadic = true;
|
|
parm_type = build_ir_node_for_variadic_parameter_type();
|
|
}
|
|
else
|
|
{
|
|
parm_name = btf_offset_to_string(btf_handle(), parm->name_off);
|
|
parm_type = is_type(build_ir_node_from_btf_type(parm->type));
|
|
}
|
|
|
|
if (!parm_type)
|
|
continue;
|
|
|
|
function_decl::parameter_sptr p
|
|
(new function_decl::parameter(parm_type, parm_name,
|
|
location(), is_variadic));
|
|
function_parms.push_back(p);
|
|
}
|
|
result->set_parameters(function_parms);
|
|
|
|
cur_tu()->bind_function_type_life_time(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a function declaration expressed in BTF.
|
|
///
|
|
/// @param type_id the ID of a pointer to a BTF "type" which realy
|
|
/// describes a function declaration.
|
|
///
|
|
/// @return a pointer to a @ref function_decl representing the
|
|
/// function declaration expressed by @p t.
|
|
type_or_decl_base_sptr
|
|
build_function_decl(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_FUNC);
|
|
|
|
function_decl_sptr result;
|
|
|
|
string fn_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
|
|
type_base_sptr fn_type = is_type(build_ir_node_from_btf_type(t->type));
|
|
if (!fn_type)
|
|
return result;
|
|
|
|
result.reset(new function_decl(fn_name, fn_type, /*is_inline=*/false,
|
|
location(), /*linkage_name=*/fn_name));
|
|
|
|
elf_symbol_sptr fn_sym;
|
|
if ((fn_sym = function_symbol_is_exported(fn_name))
|
|
|| (fn_sym = function_symbol_is_undefined(fn_name)))
|
|
{
|
|
result->set_symbol(fn_sym);
|
|
if (fn_sym->is_defined())
|
|
result->set_is_in_public_symbol_table(true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// Build an IR node for a variable declaration expressed in BTF.
|
|
///
|
|
/// @param t a pointer to a BTF "type" describing a variable
|
|
/// declaration.
|
|
///
|
|
/// @return a pointer to @ref var_decl representing the variable
|
|
/// declaration expressed by @p t.
|
|
type_or_decl_base_sptr
|
|
build_variable_decl(int type_id)
|
|
{
|
|
const btf_type *t = btf__type_by_id(btf_handle(), type_id);
|
|
int kind = btf_kind(t);
|
|
ABG_ASSERT(kind == BTF_KIND_VAR);
|
|
|
|
var_decl_sptr result;
|
|
|
|
string var_name = btf_offset_to_string(btf_handle(), t->name_off);
|
|
|
|
type_base_sptr var_type = is_type(build_ir_node_from_btf_type(t->type));
|
|
if (!var_type)
|
|
return result;
|
|
|
|
result.reset(new var_decl(var_name, var_type, location(),
|
|
/*linkage_name=*/var_name));
|
|
|
|
elf_symbol_sptr var_sym;
|
|
if ((var_sym = variable_symbol_is_exported(var_name))
|
|
|| (var_sym = variable_symbol_is_undefined(var_name)))
|
|
{
|
|
result->set_symbol(var_sym);
|
|
if (var_sym->is_defined())
|
|
result->set_is_in_public_symbol_table(true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
}; // end class reader.
|
|
|
|
/// Create and return a BTF reader (or front-end) which is an instance
|
|
/// of @ref btf::reader.
|
|
///
|
|
/// @param elf_path the path to the path to the elf file the reader is
|
|
/// to be used for.
|
|
///
|
|
/// @param debug_info_root_paths a vector to the paths to the
|
|
/// directories under which the debug info is to be found for @p
|
|
/// elf_path. Pass an empty vector if th debug info is not in a split
|
|
/// file.
|
|
///
|
|
/// @param environment the environment used by the current context.
|
|
/// This environment contains resources needed by the BTF reader and
|
|
/// by the types and declarations that are to be created later. Note
|
|
/// that ABI artifacts that are to be compared all need to be created
|
|
/// within the same environment.
|
|
///
|
|
/// Please also note that the life time of this environment object
|
|
/// must be greater than the life time of the resulting @ref
|
|
/// reader the context uses resources that are allocated in the
|
|
/// environment.
|
|
///
|
|
/// @param load_all_types if set to false only the types that are
|
|
/// reachable from publicly exported declarations (of functions and
|
|
/// variables) are read. If set to true then all types found in the
|
|
/// debug information are loaded.
|
|
///
|
|
/// @param linux_kernel_mode if set to true, then consider the special
|
|
/// linux kernel symbol tables when determining if a symbol is
|
|
/// exported or not.
|
|
///
|
|
/// @return a smart pointer to the resulting btf::reader.
|
|
elf_based_reader_sptr
|
|
create_reader(const std::string& elf_path,
|
|
const vector<string>& debug_info_root_paths,
|
|
environment& env,
|
|
bool load_all_types,
|
|
bool linux_kernel_mode)
|
|
{
|
|
reader_sptr rdr = reader::create(elf_path, debug_info_root_paths, env,
|
|
load_all_types, linux_kernel_mode);
|
|
return rdr;
|
|
}
|
|
|
|
} // end namespace btf
|
|
} // end namespace abigail
|
|
|
|
#endif //WITH_BTF
|