13 #include <sys/types.h>
23 #include <sys/types.h>
36#include <libxml/parser.h>
37#include <libxml/xmlversion.h>
54#include "abg-internal.h"
58ABG_BEGIN_EXPORT_DECLARATIONS
64ABG_END_EXPORT_DECLARATIONS
103#ifndef ABIGAIL_ROOT_SYSTEM_LIBDIR
104#error the macro ABIGAIL_ROOT_SYSTEM_LIBDIR must be set at compile time
107 static __thread
const char* system_libdir(ABIGAIL_ROOT_SYSTEM_LIBDIR);
108 return system_libdir;
121 |
static_cast<unsigned>(r));}
133 &
static_cast<unsigned>(r));}
146 |
static_cast<unsigned>(r));
191#define DECLARE_STAT(st) \
193 memset(&st, 0, sizeof(st))
201 struct timeval begin_timeval;
202 struct timeval end_timeval;
215 : priv_(new
timer::priv(k))
230 if (gettimeofday(&priv_->begin_timeval, 0))
244 if (gettimeofday(&priv_->end_timeval, 0))
255{
return priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;}
275 time_t& milliseconds)
const
277 time_t elapsed_seconds =
278 priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;
279 suseconds_t elapsed_usecs =
280 ((priv_->end_timeval.tv_sec * 1000000) + priv_->end_timeval.tv_usec)
281 - ((priv_->begin_timeval.tv_sec * 1000000) + priv_->begin_timeval.tv_usec);
285 hours = elapsed_seconds / 3600;
286 minutes = (elapsed_seconds % 3600) / 60;
287 seconds = (elapsed_seconds % 3600) % 60;
288 if (elapsed_seconds == 0)
289 milliseconds = elapsed_usecs / 1000;
300 time_t hours = 0, minutes = 0, seconds = 0;
303 value(hours, minutes, seconds, msecs);
305 std::ostringstream o;
353get_stat(
const string& path,
355{
return (lstat(path.c_str(), s) == 0);}
367 return get_stat(path, &st);
388 DIR* dir = opendir(path.c_str());
393 dirent *result = readdir(dir);
394 if (result == NULL && errno != 0)
399 return result == NULL;
413 if (!get_stat(path, &st))
416 if (S_ISREG(st.st_mode))
419 if (S_ISLNK(st.st_mode))
421 string symlink_target_path;
438 const string& archive_prefix)
440 string ctf_archive = directory +
"/" + archive_prefix +
".ctfa";
462 const vector<char**>& debug_info_root_paths)
469 debug_info_root_paths,
498 const vector<char**>& debug_info_root_paths)
505 debug_info_root_paths,
515 if (
dir_name(elf_file_path, dirname)
521 for (
const auto& path : debug_info_root_paths)
542 const vector<char**>& debug_info_root_paths)
548 elf::reader r(elf_file_path, debug_info_root_paths, env);
567 if (!get_stat(path, &st))
570 if (S_ISDIR(st.st_mode))
573 if (S_ISLNK(st.st_mode))
575 string symlink_target_path;
578 if (!get_stat(path, &st))
581 if (S_ISDIR(st.st_mode))
588static const char* ANONYMOUS_STRUCT_INTERNAL_NAME =
"__anonymous_struct__";
589static const char* ANONYMOUS_UNION_INTERNAL_NAME =
"__anonymous_union__";
590static const char* ANONYMOUS_ENUM_INTERNAL_NAME =
"__anonymous_enum__";
591static const char* ANONYMOUS_SUBRANGE_INTERNAL_NAME =
"__anonymous_range__";
593static int ANONYMOUS_STRUCT_INTERNAL_NAME_LEN =
594 strlen(ANONYMOUS_STRUCT_INTERNAL_NAME);
596static int ANONYMOUS_UNION_INTERNAL_NAME_LEN =
597 strlen(ANONYMOUS_UNION_INTERNAL_NAME);
599static int ANONYMOUS_ENUM_INTERNAL_NAME_LEN =
600 strlen(ANONYMOUS_ENUM_INTERNAL_NAME);
607{
return ANONYMOUS_STRUCT_INTERNAL_NAME;}
614{
return ANONYMOUS_UNION_INTERNAL_NAME;}
616static int ANONYMOUS_SUBRANGE_INTERNAL_NAME_LEN =
617 strlen(ANONYMOUS_SUBRANGE_INTERNAL_NAME);
624{
return ANONYMOUS_ENUM_INTERNAL_NAME;}
631{
return ANONYMOUS_SUBRANGE_INTERNAL_NAME;}
667 string::size_type l_pos1 = 0, r_pos1 = 0;
668 const string::size_type l_length = l.length(), r_length = r.length();
670 while (l_pos1 < l_length && r_pos1 < r_length)
672 string::size_type l_pos2 = l.find(
"::", l_pos1);
673 string::size_type r_pos2 = r.find(
"::", r_pos1);
674 if (l_pos2 == string::npos)
676 if (r_pos2 == string::npos)
679 if (l.compare(l_pos1, l_pos2 - l_pos1, r,
680 r_pos1, r_pos2 - r_pos1)
681 && (l.compare(l_pos1,
682 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
683 ANONYMOUS_STRUCT_INTERNAL_NAME)
685 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
686 ANONYMOUS_STRUCT_INTERNAL_NAME))
687 && (l.compare(l_pos1,
688 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
689 ANONYMOUS_UNION_INTERNAL_NAME)
691 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
692 ANONYMOUS_UNION_INTERNAL_NAME))
693 && (l.compare(l_pos1,
694 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
695 ANONYMOUS_ENUM_INTERNAL_NAME)
697 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
698 ANONYMOUS_ENUM_INTERNAL_NAME)))
701 l_pos1 = l_pos2 == l_length ? l_pos2 : l_pos2 + 2;
702 r_pos1 = r_pos2 == r_length ? r_pos2 : r_pos2 + 2;
705 return (l_pos1 == l_length) == (r_pos1 == r_length);
726 if (!get_stat(file_path, &st))
729 char *link_target_path = realpath(file_path.c_str(), NULL);
730 if (!link_target_path)
733 target_path = link_target_path;
734 free(link_target_path);
754 bool keep_separator_at_end)
762 char *p = strdup(path.c_str());
763 char *r = ::dirname(p);
766 if (keep_separator_at_end
767 && dir_name.length() < path.length())
790 char *p = strdup(path.c_str());
791 char *f = ::basename(p);
814 char *realp = realpath(path.c_str(), NULL);
831 memset(&st, 0,
sizeof (st));
835 stat_result = stat(dir_path.c_str(), &st);
836 if (stat_result == 0)
839 if (!S_ISDIR (st.st_mode))
845 cmd =
"mkdir -p " + dir_path;
847 if (system(cmd.c_str()))
886 if (!prog_name.empty())
887 out << prog_name <<
": ";
899check_file(
const string& path, ostream& out,
const string& prog_name)
903 emit_prefix(prog_name, out) <<
"file " << path <<
" does not exist\n";
909 emit_prefix(prog_name, out) << path <<
" is not a regular file\n";
927check_dir(
const string& path, ostream& out,
const string& prog_name)
931 emit_prefix(prog_name, out) <<
"path " << path <<
" does not exist\n";
937 emit_prefix(prog_name, out) << path <<
" is not a directory\n";
954 string::size_type str_len = str.length(), suffix_len = suffix.length();
956 if (str_len < suffix_len)
958 return str.compare(str_len - suffix_len, suffix_len, suffix) == 0;
977 string::size_type prefix_len = prefix.length();
978 if (prefix_len > str.length())
981 return str.compare(0, prefix.length(), prefix) == 0;
992 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1017 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1019 unsigned char c = *i;
1022 || (c >= 0x7F && c <= 0x9F))
1044 const string& delims,
1045 vector<string>& result)
1047 size_t current = 0, next;
1048 bool did_split =
false;
1053 while (current < input_string.size() && isspace(input_string[current]))
1056 if (current >= input_string.size())
1059 next = input_string.find_first_of(delims, current);
1060 if (next == string::npos)
1062 string s = input_string.substr(current);
1064 result.push_back(input_string.substr(current));
1065 did_split = (current != 0);
1068 string s = input_string.substr(current, next - current);
1071 result.push_back(input_string.substr(current, next - current));
1076 while (next != string::npos);
1094 const string& prefix,
1098 if (prefix.length() >= input_string.length())
1101 if (input_string.compare(0, prefix.length(), prefix) != 0)
1106 suffix = input_string.substr(prefix.length());
1123common_prefix(
const string& s1,
const string& s2,
string &result)
1125 if (s1.length() == 0 || s2.length() == 0)
1129 for (
size_t i = 0; i < s1.length() && i< s2.length(); ++i)
1135 return !result.empty();
1154 string prefix_candidate;
1155 bool found_prefix =
false;
1157 if (input_strings.size() == 1)
1159 if (
dir_name(input_strings.front(), prefix,
1166 for (vector<string>::const_iterator i = input_strings.begin();
1167 i != input_strings.end();
1171 if (prefix_candidate.empty())
1173 prefix_candidate = cur_str;
1178 if (common_prefix(prefix_candidate, cur_str, s))
1181 prefix_candidate = s;
1182 found_prefix =
true;
1188 prefix = prefix_candidate;
1201 string major, minor, revision, version_string, suffix;
1203 version_string = major +
"." + minor +
"." + revision + suffix;
1204 return version_string;
1213 string major, minor, version_string;
1215 version_string = major +
"." + minor;
1216 return version_string;
1245#define TMP_BUF_LEN 1024 + 1
1246 char tmp_buf[TMP_BUF_LEN];
1247 memset(tmp_buf, 0, TMP_BUF_LEN);
1249 while (fgets(tmp_buf, TMP_BUF_LEN, stream))
1251 lines.push_back(tmp_buf);
1252 memset(tmp_buf, 0, TMP_BUF_LEN);
1255 if (pclose(stream) == -1)
1276 const string& option,
1277 vector<string>& arguments)
1279 string s = input_str;
1285 s = s.substr(0, s.size() - 1);
1307 vector<string> query_output;
1313 + rpm_path +
" 2> /dev/null | grep .so",
1316 for (vector<string>::const_iterator line = query_output.begin();
1317 line != query_output.end();
1320 string dso = line->substr(0, line->find(
'('));
1323 provided_dsos.insert(dso);
1340 string::size_type start, end;
1341 for (start = 0; start < str.length(); ++start)
1342 if (!isspace(str[start]))
1345 for (end = str.length() - 1; end > 0; --end)
1346 if (!isspace(str[end]))
1349 result = str.substr(start, end - start + 1);
1386 vector<char**>& char_star_stars)
1388 for (vector<char*>::const_iterator i = char_stars.begin();
1389 i != char_stars.end();
1391 char_star_stars.push_back(
const_cast<char**
>(&*i));
1395struct temp_file::priv
1397 char* path_template_;
1399 shared_ptr<std::fstream> fstream_;
1403 const char* templat =
"/tmp/libabigail-tmp-file-XXXXXX";
1404 int s = strlen(templat);
1405 path_template_ =
new char[s + 1];
1406 memset(path_template_, 0, s + 1);
1407 memcpy(path_template_, templat, s);
1409 fd_ = mkstemp(path_template_);
1413 fstream_.reset(
new std::fstream(path_template_,
1421 if (fd_ && fd_ != -1)
1425 remove(path_template_);
1427 delete [] path_template_;
1434temp_file::temp_file()
1443temp_file::is_good()
const
1444{
return priv_->fstream_->good();}
1451temp_file::get_path()
const
1454 return priv_->path_template_;
1468temp_file::get_stream()
1471 return *priv_->fstream_;
1482 if (result->is_good())
1494 static __thread
bool initialized =
false;
1511 std::ostringstream o;
1525 case FILE_TYPE_UNKNOWN:
1526 repr =
"unknown file type";
1528 case FILE_TYPE_NATIVE_BI:
1529 repr =
"native binary instrumentation file type";
1532 repr =
"ELF file type";
1535 repr =
"archive file type";
1537 case FILE_TYPE_XML_CORPUS:
1538 repr =
"native XML corpus file type";
1540 case FILE_TYPE_XML_CORPUS_GROUP:
1541 repr =
"native XML corpus group file type";
1544 repr =
"RPM file type";
1546 case FILE_TYPE_SRPM:
1547 repr =
"SRPM file type";
1550 repr =
"Debian binary file type";
1553 repr =
"Directory type";
1556 repr =
"GNU tar archive type";
1572 const unsigned BUF_LEN = 264;
1573 const unsigned NB_BYTES_TO_READ = 263;
1576 memset(buf, 0, BUF_LEN);
1578 std::streampos initial_pos = in.tellg();
1579 in.read(buf, NB_BYTES_TO_READ);
1580 in.seekg(initial_pos);
1582 if (in.gcount() < 4 || in.bad())
1599 if (strstr(buf,
"debian-binary"))
1636 return FILE_TYPE_XML_CORPUS_GROUP;
1650 return FILE_TYPE_XML_CORPUS;
1652 if ((
unsigned char) buf[0] == 0xed
1653 && (
unsigned char) buf[1] == 0xab
1654 && (
unsigned char) buf[2] == 0xee
1655 && (
unsigned char) buf[3] == 0xdb)
1659 else if (buf[7] == 0x01)
1703 ifstream in(file_path.c_str(), ifstream::binary);
1721 if (str.empty() || str[0] ==
'_')
1724 string::size_type str_len = str.length(), i = 0 ;
1726 for (; i < str_len; ++i)
1735 name = str.substr(0, i);
1751 if (str.empty() || str[0] ==
'-')
1754 string::size_type str_len = str.length(), i = 0;
1755 string::value_type c;
1757 for (; i < str_len; ++i)
1760 string::size_type next_index = i + 1;
1761 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
1768 name = str.substr(0, i);
1791 string::size_type str_len = str.length(), i = 0;
1792 string::value_type c;
1793 string::size_type last_dot_index = 0, dot_before_last_index = 0;
1795 for (i = str_len - 1; i > 0; --i)
1808 for(--i; i > 0; --i)
1813 dot_before_last_index = i;
1821 arch = str.substr(dot_before_last_index + 1,
1822 last_dot_index - dot_before_last_index - 1);
1838 bool result =
false;
1849 string package_name;
1868 vector<string> query_output;
1874 + rpm_path +
" 2> /dev/null",
1877 for (
auto& line : query_output)
1898 bool result =
false;
1899 string package_name;
1905 result = (package_name ==
"kernel-debuginfo");
1921struct malloced_char_star_deleter
1924 operator()(
char* ptr)
1939std::shared_ptr<char>
1942 using std::shared_ptr;
1944 shared_ptr<char> result;
1946 if (p && p[0] !=
'/')
1948 shared_ptr<char> pwd(get_current_dir_name(),
1949 malloced_char_star_deleter());
1950 string s = string(pwd.get()) +
"/" + p;
1951 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
1954 result.reset(strdup(p), malloced_char_star_deleter());
1975 if (p && p[0] !=
'/')
1977 char* pwd = get_current_dir_name();
1978 string s = string(pwd) +
"/" + p;
1980 result = strdup(s.c_str());
2004handle_file_entry(
const string& file_path,
2015 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2016 suppr->set_is_artificial(
true);
2022 suppr->get_source_locations_to_keep().insert(file_path);
2038handle_fts_entry(
const FTSENT *entry,
2042 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2043 || entry->fts_info == FTS_ERR
2044 || entry->fts_info == FTS_NS)
2047 string fname = entry->fts_name;
2053 handle_file_entry (fname, suppr);
2071gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2074 if (!headers_root_dir.empty())
2076 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2078 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2081 while ((entry = fts_read(file_hierarchy)))
2082 handle_fts_entry(entry, result);
2083 fts_close(file_hierarchy);
2104 const vector<string>& header_files)
2108 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2109 root_dir != headers_root_dirs.end();
2111 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2113 for (vector<string>::const_iterator file = header_files.begin();
2114 file != header_files.end();
2116 handle_file_entry(*file, result);
2136 const vector<string>& header_files)
2139 vector<string> root_dirs;
2141 if (!headers_root_dir.empty())
2142 root_dirs.push_back(headers_root_dir);
2160 vector<string> header_files;
2191 (
const std::vector<std::string>& abi_whitelist_paths)
2194 std::vector<std::string> whitelisted_names;
2195 for (std::vector<std::string>::const_iterator
2196 path_iter = abi_whitelist_paths.begin(),
2197 path_end = abi_whitelist_paths.end();
2198 path_iter != path_end;
2209 for (ini::config::sections_type::const_iterator
2210 section_iter = whitelist_sections.begin(),
2211 section_end = whitelist_sections.end();
2212 section_iter != section_end;
2215 std::string section_name = (*section_iter)->get_name();
2219 for (ini::config::properties_type::const_iterator
2220 prop_iter = (*section_iter)->get_properties().begin(),
2221 prop_end = (*section_iter)->get_properties().end();
2222 prop_iter != prop_end;
2227 if (prop->has_empty_value())
2229 const std::string& name = prop->get_name();
2231 whitelisted_names.push_back(name);
2238 if (!whitelisted_names.empty())
2241 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2242 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2243 whitelisted_names.end()),
2244 whitelisted_names.end());
2256 fn_suppr->set_label(
"whitelist");
2257 fn_suppr->set_symbol_name_not_regex_str(regex);
2258 fn_suppr->set_drops_artifact_from_ir(
true);
2259 result.push_back(fn_suppr);
2267 var_suppr->set_label(
"whitelist");
2268 var_suppr->set_symbol_name_not_regex_str(regex);
2269 var_suppr->set_drops_artifact_from_ir(
true);
2270 result.push_back(var_suppr);
2281 string default_system_suppr_path;
2283 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2285 default_system_suppr_path = s;
2287 if (default_system_suppr_path.empty())
2288 default_system_suppr_path =
2291 return default_system_suppr_path;
2300 string default_user_suppr_path;
2301 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2308 default_user_suppr_path = s;
2309 if (default_user_suppr_path.empty())
2310 default_user_suppr_path =
"~";
2311 default_user_suppr_path +=
"/.abignore";
2314 default_user_suppr_path = s;
2316 return default_user_suppr_path;
2330 string default_system_suppr_path =
2346 string default_user_suppr_path =
2367entry_of_file_with_name(
const FTSENT *entry,
2368 const string& fname,
2369 const string& root_dir)
2372 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2373 || entry->fts_info == FTS_ERR
2374 || entry->fts_info == FTS_NS)
2377 string fpath = ::basename(entry->fts_path);
2381 fpath = trim_leading_string(entry->fts_path, root_dir);
2400 const string& file_path_to_look_for,
2403 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2405 FTS *file_hierarchy = fts_open(paths,
2406 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2407 if (!file_hierarchy)
2410 string r = root_dir;
2415 while ((entry = fts_read(file_hierarchy)))
2417 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2419 result = entry->fts_path;
2423 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2425 fts_set(file_hierarchy, entry, FTS_SKIP);
2430 fts_close(file_hierarchy);
2447 const string& file_path_to_look_for,
2450 if (root_dirs.empty())
2453 for (
const auto& root_dir : root_dirs)
2482 const vector<string>& deps_dirs,
2483 set<string>& dependencies)
2485 const vector<string>& set_of_needed = korpus.
get_needed();
2486 if (set_of_needed.empty())
2489 bool found_at_least_one_dependency =
false;
2490 for (
const auto& n :set_of_needed)
2493 if (dependencies.find(n) == dependencies.end()
2496 dependencies.insert(dependency);
2497 found_at_least_one_dependency =
true;
2501 return found_at_least_one_dependency;
2519 const vector<string>& binaries,
2520 const vector<string>& deps_dirs,
2523 vector<string> bins;
2525 for (
const auto& b : binaries)
2529 bins.push_back(bin);
2532 for (
const auto& b : bins)
2537 reader->initialize(b);
2539 corpus_sptr c = reader->read_corpus(stat);
2560 const vector<string>& deps_dirs,
2568 for (
const auto& dep: deps)
2573 reader->initialize(dep);
2575 corpus_sptr c = reader->read_corpus(stat);
2603 const corpus_sptr& korpus,
2604 const vector<string>& binaries,
2605 const vector<string>& bins_dirs)
2607 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2608 korpus->get_path()));
2609 result->add_corpus(korpus);
2632 const corpus_sptr& korpus,
2633 const vector<string>& deps_dirs)
2635 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2636 korpus->get_path()));
2637 result->add_corpus(korpus);
2665 vector<string>& suppr_paths,
2666 vector<string>& kabi_whitelist_paths,
2671 for (vector<string>::const_iterator i = suppr_paths.begin();
2672 i != suppr_paths.end();
2677 gen_suppr_spec_from_kernel_abi_whitelists(kabi_whitelist_paths);
2679 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2692is_vmlinux(
const FTSENT *entry)
2695 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2696 || entry->fts_info == FTS_ERR
2697 || entry->fts_info == FTS_NS)
2700 string fname = entry->fts_name;
2702 if (fname ==
"vmlinux")
2705 dir_name(entry->fts_path, dirname);
2722is_kernel_module(
const FTSENT *entry)
2725 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2726 || entry->fts_info == FTS_ERR
2727 || entry->fts_info == FTS_NS)
2730 string fname = entry->fts_name;
2752find_vmlinux_and_module_paths(
const string& from,
2753 string &vmlinux_path,
2754 vector<string> &module_paths)
2756 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2758 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2759 if (!file_hierarchy)
2762 bool found_vmlinux = !vmlinux_path.empty();
2764 while ((entry = fts_read(file_hierarchy)))
2767 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2769 fts_set(file_hierarchy, entry, FTS_SKIP);
2773 if (!found_vmlinux && is_vmlinux(entry))
2775 vmlinux_path = entry->fts_path;
2776 found_vmlinux =
true;
2778 else if (is_kernel_module(entry))
2779 module_paths.push_back(entry->fts_path);
2782 fts_close(file_hierarchy);
2784 return found_vmlinux;
2795find_vmlinux_path(
const string& from,
2796 string &vmlinux_path)
2798 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2800 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2801 if (!file_hierarchy)
2804 bool found_vmlinux =
false;
2806 while ((entry = fts_read(file_hierarchy)))
2809 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2811 fts_set(file_hierarchy, entry, FTS_SKIP);
2815 if (!found_vmlinux && is_vmlinux(entry))
2817 vmlinux_path = entry->fts_path;
2818 found_vmlinux =
true;
2823 fts_close(file_hierarchy);
2825 return found_vmlinux;
2846 const string& debug_info_root_path,
2847 string& vmlinux_path,
2848 vector<string>& module_paths)
2861 string kernel_modules_root = dist_root;
2862 string debug_info_root;
2865 kernel_modules_root = dist_root +
"/lib/modules";
2866 debug_info_root = debug_info_root_path.empty()
2867 ? dist_root +
"/usr/lib/debug"
2868 : debug_info_root_path;
2872 debug_info_root.clear();
2880 find_vmlinux_and_module_paths(kernel_modules_root,
2885 || find_vmlinux_and_module_paths(debug_info_root,
2890 std::sort(module_paths.begin(), module_paths.end());
2906 string& vmlinux_path)
2917 string dist_root = from;
2919 dist_root +=
"/lib/modules";
2922 if (find_vmlinux_path(dist_root, vmlinux_path))
2942 string& vmlinux_path,
2943 vector<string>& module_paths)
2945 string debug_info_root_path;
2947 debug_info_root_path,
2990load_vmlinux_corpus(elf_based_reader_sptr rdr,
2991 corpus_group_sptr& group,
2992 const string& vmlinux,
2993 vector<string>& modules,
2995 vector<char**>& di_roots,
2996 vector<string>& suppr_paths,
2997 vector<string>& kabi_wl_paths,
3004 rdr->options().do_log = verbose;
3007 load_generate_apply_suppressions(*rdr, suppr_paths,
3008 kabi_wl_paths, supprs);
3012 std::cerr <<
"loaded white list and generated suppr spec in: "
3018 rdr->corpus_group(group);
3021 std::cerr <<
"reading kernel binary '"
3022 << vmlinux <<
"' ...\n" << std::flush;
3026 rdr->read_and_add_corpus_to_group(*group, status);
3030 std::cerr << vmlinux
3031 <<
" reading DONE in:"
3034 if (group->is_empty())
3038 int total_nb_modules = modules.size();
3039 int cur_module_index = 1;
3040 for (vector<string>::const_iterator m = modules.begin();
3042 ++m, ++cur_module_index)
3045 std::cerr <<
"reading module '"
3048 <<
"/" << total_nb_modules
3049 <<
") ...\n" << std::flush;
3051 rdr->initialize(*m, di_roots,
3055 load_generate_apply_suppressions(*rdr, suppr_paths,
3056 kabi_wl_paths, supprs);
3058 rdr->corpus_group(group);
3061 rdr->read_and_add_corpus_to_group(*group, status);
3064 std::cerr <<
"Module reading DONE in: "
3065 << t <<
" for '" << *m
3066 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3072 std::cerr <<
"Total number of functions: "
3073 << group->get_functions().size() <<
"\n";
3074 std::cerr <<
"Total number of variables: "
3075 << group->get_variables().size() <<
"\n";
3118 const string debug_info_root,
3119 const string& vmlinux_path,
3120 vector<string>& suppr_paths,
3121 vector<string>& kabi_wl_paths,
3127 string vmlinux = vmlinux_path;
3128 corpus_group_sptr group;
3129 vector<string> modules;
3132 std::cerr <<
"Analysing kernel dist root '"
3134 <<
"' with vmlinux path: '"
3136 <<
"' ... \n" << std::flush;
3141 bool got_binary_paths =
3146 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3148 if (got_binary_paths)
3150 shared_ptr<char> di_root =
3152 char *di_root_ptr = di_root.get();
3153 vector<char**> di_roots;
3154 di_roots.push_back(&di_root_ptr);
3157 shared_ptr<char> di_root_ctf;
3158 char *di_root_ctf_ptr;
3159 if (requested_fe_kind & corpus::CTF_ORIGIN)
3162 di_root_ctf_ptr = di_root_ctf.get();
3163 di_roots.push_back(&di_root_ctf_ptr);
3167 abigail::elf_based_reader_sptr reader =
3175 load_vmlinux_corpus(reader, group, vmlinux,
3176 modules, root, di_roots,
3177 suppr_paths, kabi_wl_paths,
3178 supprs, verbose, t, env);
3219elf_based_reader_sptr
3221 const vector<char**>& debug_info_root_paths,
3224 bool show_all_types,
3225 bool linux_kernel_mode)
3227 elf_based_reader_sptr result;
3231 if (requested_fe_kind & corpus::CTF_ORIGIN)
3238 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3243 show_all_types, linux_kernel_mode);
3263 show_all_types, linux_kernel_mode);
3273 debug_info_root_paths,
3302 std::vector<function_decl*>::const_iterator a_end,
3303 std::vector<function_decl*>::const_iterator b_begin,
3304 std::vector<function_decl*>::const_iterator b_end)
3305{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3319 std::vector<function_decl*>::const_iterator a_end,
3320 std::vector<function_decl*>::const_iterator b_begin,
3321 std::vector<function_decl*>::const_iterator b_end)
3323 std::vector<function_decl*>::const_iterator i;
3324 std::ostream& o = std::cerr;
3325 for (i = a_begin; i != a_end; ++i)
3326 o << (*i)->get_pretty_representation() <<
"\n";
3329 for (i = b_begin; i != b_end; ++i)
3330 o << (*i)->get_pretty_representation() <<
"\n";
3343 unsigned f1_index,
unsigned f2_index)
3348 return *fn1 == *fn2;
This file contains the declarations of the front-end to analyze the BTF information contained in an E...
This file contains the declarations of the entry points to de-serialize an instance of abigail::corpu...
This file contains the declarations of the entry points to de-serialize an instance of abigail::corpu...
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Types of the main internal representation of libabigail.
Wrappers around regex types and functions.
This is the interface an ELF reader.
const Dwarf * dwarf_debug_info() const
Getter of the handle used to access DWARF information from the current ELF file.
const Elf_Scn * find_ctf_section() const
Find and return a pointer to the the CTF section.
const Elf_Scn * find_btf_section() const
Find and return a pointer to the BTF section of the current ELF file.
The common interface of readers based on ELF.
status
The status of the fe_iface::read_corpus call.
@ STATUS_OK
This status is for when the call went OK.
@ STATUS_UNKNOWN
The status is in an unknown state.
void add_suppressions(const suppr::suppressions_type &)
Add suppressions specifications to the set of suppressions to be used during the construction of the ...
The abstraction of the structured content of an .ini file. This roughly follows what is explained at ...
vector< section_sptr > sections_type
A convenience typedef for a vector of config::section_sptr.
const sections_type & get_sections() const
Abstraction of a group of corpora.
bool has_corpus(const string &)
Test if a corpus of a given path has been added to the group.
void add_corpus(const corpus_sptr &)
Add a new corpus to the current instance of corpus_group.
This is the abstraction of a set of translation units (themselves seen as bundles of unitary abi arte...
origin
This abstracts where the corpus comes from. That is, either it has been read from the native xml form...
const vector< string > & get_needed() const
Getter of the needed property of the corpus.
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Abstraction for a function declaration.
Abstraction of a function suppression specification.
Abstraction of a type suppression specification.
The abstraction of a variable suppression specification.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &env, bool load_all_types=false, bool linux_kernel_mode=false)
Create and return a BTF reader (or front-end) which is an instance of btf::reader.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &env)
Create and return a new read context to process CTF information from a given ELF file.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &environment, bool load_all_types, bool linux_kernel_mode)
Create a dwarf::reader.
Namespace for handling ini-style files.
bool read_config(istream &input, config &conf)
Parse an ini config file from an input stream.
shared_ptr< simple_property > simple_property_sptr
Convenience typedef for a shared_ptr to an simple_property.
simple_property * is_simple_property(const property *p)
Tests if a property is a simple property.
std::string generate_from_strings(const std::vector< std::string > &strs)
Generate a regex pattern equivalent to testing set membership.
an engine to suppress the parts of the result of comparing two sets of ABI artifacts.
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
const char * get_opaque_types_suppr_spec_label()
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
void read_suppressions(std::istream &input, suppressions_type &suppressions)
Read suppressions specifications from an input stream.
Toplevel namespace for libabigail.
bool compare_functions(vector< function_decl * >::const_iterator base, unsigned f1_index, unsigned f2_index)
Compare two functions that are in a vector of functions.
void abigail_get_library_version(std::string &major, std::string &minor, std::string &revision, std::string &suffix)
Return the relevant version numbers of the library.
void dump_function_names(std::vector< function_decl * >::const_iterator a_begin, std::vector< function_decl * >::const_iterator a_end, std::vector< function_decl * >::const_iterator b_begin, std::vector< function_decl * >::const_iterator b_end)
Dump (to the standard error output stream) a pretty representation of the signatures of two sequences...
void abigail_get_abixml_version(std::string &major, std::string &minor)
Return the version numbers for the ABIXML format.
void dump_functions_as_string(std::vector< function_decl * >::const_iterator a_begin, std::vector< function_decl * >::const_iterator a_end, std::vector< function_decl * >::const_iterator b_begin, std::vector< function_decl * >::const_iterator b_end)
Dump (to the standard error stream) two sequences of strings where each string represent one of the f...