13 #include <sys/types.h>
23 #include <sys/types.h>
36#include <libxml/parser.h>
37#include <libxml/xmlversion.h>
56#include "abg-internal.h"
61ABG_BEGIN_EXPORT_DECLARATIONS
67ABG_END_EXPORT_DECLARATIONS
105#ifndef ABIGAIL_ROOT_SYSTEM_LIBDIR
106#error the macro ABIGAIL_ROOT_SYSTEM_LIBDIR must be set at compile time
109 static __thread
const char* system_libdir(ABIGAIL_ROOT_SYSTEM_LIBDIR);
110 return system_libdir;
123 |
static_cast<unsigned>(r));}
135 &
static_cast<unsigned>(r));}
148 |
static_cast<unsigned>(r));
193#define DECLARE_STAT(st) \
195 memset(&st, 0, sizeof(st))
203 struct timeval begin_timeval;
204 struct timeval end_timeval;
217 : priv_(new
timer::priv(k))
232 if (gettimeofday(&priv_->begin_timeval, 0))
246 if (gettimeofday(&priv_->end_timeval, 0))
257{
return priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;}
277 time_t& milliseconds)
const
279 time_t elapsed_seconds =
280 priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;
281 suseconds_t elapsed_usecs =
282 ((priv_->end_timeval.tv_sec * 1000000) + priv_->end_timeval.tv_usec)
283 - ((priv_->begin_timeval.tv_sec * 1000000) + priv_->begin_timeval.tv_usec);
287 hours = elapsed_seconds / 3600;
288 minutes = (elapsed_seconds % 3600) / 60;
289 seconds = (elapsed_seconds % 3600) % 60;
290 if (elapsed_seconds == 0)
291 milliseconds = elapsed_usecs / 1000;
302 time_t hours = 0, minutes = 0, seconds = 0;
305 value(hours, minutes, seconds, msecs);
307 std::ostringstream o;
355get_stat(
const string& path,
357{
return (lstat(path.c_str(), s) == 0);}
369 return get_stat(path, &st);
390 DIR* dir = opendir(path.c_str());
395 dirent *result = readdir(dir);
396 if (result == NULL && errno != 0)
401 return result == NULL;
415 if (!get_stat(path, &st))
418 if (S_ISREG(st.st_mode))
421 if (S_ISLNK(st.st_mode))
423 string symlink_target_path;
440 const string& archive_prefix)
442 string ctf_archive = directory +
"/" + archive_prefix +
".ctfa";
464 const vector<string>& debug_info_root_paths)
471 debug_info_root_paths,
500 const vector<string>& debug_info_root_paths)
507 debug_info_root_paths,
517 if (
dir_name(elf_file_path, dirname)
523 for (
const auto& path : debug_info_root_paths)
544 const vector<string>& debug_info_root_paths)
550 elf::reader r(elf_file_path, debug_info_root_paths, env);
569 if (!get_stat(path, &st))
572 if (S_ISDIR(st.st_mode))
575 if (S_ISLNK(st.st_mode))
577 string symlink_target_path;
580 if (!get_stat(path, &st))
583 if (S_ISDIR(st.st_mode))
590static const char* ANONYMOUS_STRUCT_INTERNAL_NAME =
"__anonymous_struct__";
591static const char* ANONYMOUS_UNION_INTERNAL_NAME =
"__anonymous_union__";
592static const char* ANONYMOUS_ENUM_INTERNAL_NAME =
"__anonymous_enum__";
593static const char* ANONYMOUS_SUBRANGE_INTERNAL_NAME =
"__anonymous_range__";
595static int ANONYMOUS_STRUCT_INTERNAL_NAME_LEN =
596 strlen(ANONYMOUS_STRUCT_INTERNAL_NAME);
598static int ANONYMOUS_UNION_INTERNAL_NAME_LEN =
599 strlen(ANONYMOUS_UNION_INTERNAL_NAME);
601static int ANONYMOUS_ENUM_INTERNAL_NAME_LEN =
602 strlen(ANONYMOUS_ENUM_INTERNAL_NAME);
609{
return ANONYMOUS_STRUCT_INTERNAL_NAME;}
616{
return ANONYMOUS_UNION_INTERNAL_NAME;}
623{
return ANONYMOUS_ENUM_INTERNAL_NAME;}
630{
return ANONYMOUS_SUBRANGE_INTERNAL_NAME;}
666 string::size_type l_pos1 = 0, r_pos1 = 0;
667 const string::size_type l_length = l.length(), r_length = r.length();
669 while (l_pos1 < l_length && r_pos1 < r_length)
671 string::size_type l_pos2 = l.find(
"::", l_pos1);
672 string::size_type r_pos2 = r.find(
"::", r_pos1);
673 if (l_pos2 == string::npos)
675 if (r_pos2 == string::npos)
678 if (l.compare(l_pos1, l_pos2 - l_pos1, r,
679 r_pos1, r_pos2 - r_pos1)
680 && (l.compare(l_pos1,
681 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
682 ANONYMOUS_STRUCT_INTERNAL_NAME)
684 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
685 ANONYMOUS_STRUCT_INTERNAL_NAME))
686 && (l.compare(l_pos1,
687 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
688 ANONYMOUS_UNION_INTERNAL_NAME)
690 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
691 ANONYMOUS_UNION_INTERNAL_NAME))
692 && (l.compare(l_pos1,
693 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
694 ANONYMOUS_ENUM_INTERNAL_NAME)
696 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
697 ANONYMOUS_ENUM_INTERNAL_NAME)))
700 l_pos1 = l_pos2 == l_length ? l_pos2 : l_pos2 + 2;
701 r_pos1 = r_pos2 == r_length ? r_pos2 : r_pos2 + 2;
704 return (l_pos1 == l_length) == (r_pos1 == r_length);
725 if (!get_stat(file_path, &st))
728 char *link_target_path = realpath(file_path.c_str(), NULL);
729 if (!link_target_path)
732 target_path = link_target_path;
733 free(link_target_path);
753 bool keep_separator_at_end)
761 char *p = strdup(path.c_str());
762 char *r = ::dirname(p);
765 if (keep_separator_at_end
766 &&
dir_name.length() < path.length())
789 char *p = strdup(path.c_str());
790 char *f = ::basename(p);
813 char *realp = realpath(path.c_str(), NULL);
830 memset(&st, 0,
sizeof (st));
834 stat_result = stat(dir_path.c_str(), &st);
835 if (stat_result == 0)
838 if (!S_ISDIR (st.st_mode))
844 cmd =
"mkdir -p " + dir_path;
846 if (system(cmd.c_str()))
885 if (!prog_name.empty())
886 out << prog_name <<
": ";
898check_file(
const string& path, ostream& out,
const string& prog_name)
902 emit_prefix(prog_name, out) <<
"file " << path <<
" does not exist\n";
908 emit_prefix(prog_name, out) << path <<
" is not a regular file\n";
926check_dir(
const string& path, ostream& out,
const string& prog_name)
930 emit_prefix(prog_name, out) <<
"path " << path <<
" does not exist\n";
936 emit_prefix(prog_name, out) << path <<
" is not a directory\n";
953 string::size_type str_len = str.length(), suffix_len = suffix.length();
955 if (str_len < suffix_len)
957 return str.compare(str_len - suffix_len, suffix_len, suffix) == 0;
976 string::size_type prefix_len = prefix.length();
977 if (prefix_len > str.length())
980 return str.compare(0, prefix.length(), prefix) == 0;
991 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1016 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1018 unsigned char c = *i;
1021 || (c >= 0x7F && c <= 0x9F))
1043 const string& delims,
1044 vector<string>& result)
1046 size_t current = 0, next;
1047 bool did_split =
false;
1052 while (current < input_string.size() && isspace(input_string[current]))
1055 if (current >= input_string.size())
1058 next = input_string.find_first_of(delims, current);
1059 if (next == string::npos)
1061 string s = input_string.substr(current);
1063 result.push_back(input_string.substr(current));
1064 did_split = (current != 0);
1067 string s = input_string.substr(current, next - current);
1070 result.push_back(input_string.substr(current, next - current));
1075 while (next != string::npos);
1093 const string& prefix,
1097 if (prefix.length() >= input_string.length())
1100 if (input_string.compare(0, prefix.length(), prefix) != 0)
1105 suffix = input_string.substr(prefix.length());
1121 const string& suffix,
1124 if (input_string.empty() || suffix.length() > input_string.length())
1129 prefix = input_string;
1133 if (input_string.compare(input_string.length() - suffix.length(),
1134 suffix.length(), suffix) != 0)
1137 prefix = input_string.substr(0, input_string.length() - suffix.length());
1155common_prefix(
const string& s1,
const string& s2,
string &result)
1157 if (s1.length() == 0 || s2.length() == 0)
1161 for (
size_t i = 0; i < s1.length() && i< s2.length(); ++i)
1167 return !result.empty();
1186 string prefix_candidate;
1187 bool found_prefix =
false;
1189 if (input_strings.size() == 1)
1191 if (
dir_name(input_strings.front(), prefix,
1198 for (vector<string>::const_iterator i = input_strings.begin();
1199 i != input_strings.end();
1203 if (prefix_candidate.empty())
1205 prefix_candidate = cur_str;
1210 if (common_prefix(prefix_candidate, cur_str, s))
1213 prefix_candidate = s;
1214 found_prefix =
true;
1220 prefix = prefix_candidate;
1233 string major, minor, revision, version_string, suffix;
1235 version_string = major +
"." + minor +
"." + revision + suffix;
1236 return version_string;
1245 string major, minor, version_string;
1247 version_string = major +
"." + minor;
1248 return version_string;
1277#define TMP_BUF_LEN 1024 + 1
1278 char tmp_buf[TMP_BUF_LEN];
1279 memset(tmp_buf, 0, TMP_BUF_LEN);
1281 while (fgets(tmp_buf, TMP_BUF_LEN, stream))
1283 lines.push_back(tmp_buf);
1284 memset(tmp_buf, 0, TMP_BUF_LEN);
1287 if (pclose(stream) == -1)
1308 const string& option,
1309 vector<string>& arguments)
1311 string s = input_str;
1317 s = s.substr(0, s.size() - 1);
1339 vector<string> query_output;
1345 + rpm_path +
" 2> /dev/null | grep .so",
1348 for (vector<string>::const_iterator line = query_output.begin();
1349 line != query_output.end();
1352 string dso = line->substr(0, line->find(
'('));
1355 provided_dsos.insert(dso);
1372 string::size_type start, end;
1373 for (start = 0; start < str.length(); ++start)
1374 if (!isspace(str[start]))
1377 for (end = str.length() - 1; end > 0; --end)
1378 if (!isspace(str[end]))
1381 result = str.substr(start, end - start + 1);
1393 if (str.erase(std::remove_if(str.begin(), str.end(), isspace),
1394 str.end()) == str.end())
1412 static std::regex re(
"([0-9]+)([uUlL])+");
1427 bool begin_pattern =
false, middle_pattern =
false, found_litteral =
false;
1428 for (string::iterator i = str.begin(); i < str.end(); ++i)
1431 begin_pattern =
true;
1435 && (*i ==
'u' || *i ==
'U' || *i ==
'l' || *i ==
'L'))
1436 middle_pattern =
true;
1441 found_litteral =
true;
1450 std::regex& re = get_litteral_regex();
1451 str = std::regex_replace(str, re,
"$1");
1491 vector<char**>& char_star_stars)
1493 for (vector<char*>::const_iterator i = char_stars.begin();
1494 i != char_stars.end();
1496 char_star_stars.push_back(
const_cast<char**
>(&*i));
1500struct temp_file::priv
1502 char* path_template_;
1504 shared_ptr<std::fstream> fstream_;
1508 const char* templat =
"/tmp/libabigail-tmp-file-XXXXXX";
1509 int s = strlen(templat);
1510 path_template_ =
new char[s + 1];
1511 memset(path_template_, 0, s + 1);
1512 memcpy(path_template_, templat, s);
1514 fd_ = mkstemp(path_template_);
1518 fstream_.reset(
new std::fstream(path_template_,
1526 if (fd_ && fd_ != -1)
1530 remove(path_template_);
1532 delete [] path_template_;
1539temp_file::temp_file()
1548temp_file::is_good()
const
1549{
return priv_->fstream_->good();}
1556temp_file::get_path()
const
1559 return priv_->path_template_;
1573temp_file::get_stream()
1576 return *priv_->fstream_;
1587 if (result->is_good())
1599 static __thread
bool initialized =
false;
1616 std::ostringstream o;
1630 case FILE_TYPE_UNKNOWN:
1631 repr =
"unknown file type";
1633 case FILE_TYPE_NATIVE_BI:
1634 repr =
"native binary instrumentation file type";
1637 repr =
"ELF file type";
1640 repr =
"archive file type";
1642 case FILE_TYPE_XML_CORPUS:
1643 repr =
"native XML corpus file type";
1645 case FILE_TYPE_XML_CORPUS_GROUP:
1646 repr =
"native XML corpus group file type";
1649 repr =
"RPM file type";
1651 case FILE_TYPE_SRPM:
1652 repr =
"SRPM file type";
1655 repr =
"Debian binary file type";
1658 repr =
"Directory type";
1661 repr =
"GNU tar archive type";
1664 repr =
"XZ compressed file";
1679 COMPRESSION_KIND_UNKNOWN,
1691static compression_kind
1692is_compressed_file_type(file_type t)
1694 if (t == FILE_TYPE_XZ)
1695 return COMPRESSION_KIND_XZ;
1697 return COMPRESSION_KIND_UNKNOWN;
1708 const unsigned BUF_LEN = 264;
1709 const unsigned NB_BYTES_TO_READ = 263;
1711 unsigned char buf[BUF_LEN];
1712 memset(buf, 0, BUF_LEN);
1714 std::streampos initial_pos = in.tellg();
1715 in.read(
reinterpret_cast<char*
>(buf), NB_BYTES_TO_READ);
1716 in.seekg(initial_pos);
1718 if (in.gcount() < 4 || in.bad())
1729 if (in.gcount() >= 6
1746 if (strstr(
reinterpret_cast<char*
>(buf),
"debian-binary"))
1783 return FILE_TYPE_XML_CORPUS_GROUP;
1797 return FILE_TYPE_XML_CORPUS;
1801 if ((
unsigned char) buf[0] == 0xed
1802 && (
unsigned char) buf[1] == 0xab
1803 && (
unsigned char) buf[2] == 0xee
1804 && (
unsigned char) buf[3] == 0xdb)
1808 else if (buf[7] == 0x01)
1839static shared_ptr<std::streambuf>
1840get_decompressed_streambuf(std::istream& compressed_input,
1841 compression_kind compr)
1843 shared_ptr<std::streambuf> result;
1847 case COMPRESSION_KIND_UNKNOWN:
1851 case COMPRESSION_KIND_XZ:
1852 shared_ptr<std::streambuf> r(
new xz_decompressor_type(compressed_input));
1894 shared_ptr<std::streambuf> decompressor_streambuf;
1906 if (is_compressed_file_type(r) && !look_through_compression)
1911 shared_ptr<ifstream> input_fstream(
new ifstream(file_path.c_str(),
1913 shared_ptr<istream> input_stream = input_fstream;
1915 if (compr_kind != COMPRESSION_KIND_UNKNOWN)
1916 decompressor_streambuf = get_decompressed_streambuf(*input_stream,
1919 if (decompressor_streambuf)
1920 input_stream.reset(
new istream(decompressor_streambuf.get()));
1924 input_fstream->close();
1926 if (!decompressor_streambuf)
1931 compr_kind = is_compressed_file_type(r);
1934 if (!look_through_compression)
1952 }
while (!decompressor_streambuf && compr_kind);
1969 if (str.empty() || str[0] ==
'_')
1972 string::size_type str_len = str.length(), i = 0 ;
1974 for (; i < str_len; ++i)
1983 name = str.substr(0, i);
1999 if (str.empty() || str[0] ==
'-')
2002 string::size_type str_len = str.length(), i = 0;
2003 string::value_type c;
2005 for (; i < str_len; ++i)
2008 string::size_type next_index = i + 1;
2009 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
2016 name = str.substr(0, i);
2039 string::size_type str_len = str.length(), i = 0;
2040 string::value_type c;
2041 string::size_type last_dot_index = 0, dot_before_last_index = 0;
2043 for (i = str_len - 1; i > 0; --i)
2056 for(--i; i > 0; --i)
2061 dot_before_last_index = i;
2069 arch = str.substr(dot_before_last_index + 1,
2070 last_dot_index - dot_before_last_index - 1);
2086 bool result =
false;
2097 string package_name;
2116 vector<string> query_output;
2122 + rpm_path +
" 2> /dev/null",
2125 for (
auto& line : query_output)
2146 bool result =
false;
2147 string package_name;
2153 result = (package_name ==
"kernel-debuginfo");
2169struct malloced_char_star_deleter
2172 operator()(
char* ptr)
2187std::shared_ptr<char>
2190 using std::shared_ptr;
2192 shared_ptr<char> result;
2194 if (p && p[0] !=
'/')
2196 shared_ptr<char> pwd(get_current_dir_name(),
2197 malloced_char_star_deleter());
2198 string s = string(pwd.get()) +
"/" + p;
2199 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
2202 result.reset(strdup(p), malloced_char_star_deleter());
2220 if (!p.empty() && p[0] !=
'/')
2222 shared_ptr<char> pwd(get_current_dir_name(),
2223 malloced_char_star_deleter());
2224 result = string(pwd.get()) +
"/" + p;
2226 else if (!p.empty())
2248handle_file_entry(
const string& file_path,
2259 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2260 suppr->set_is_artificial(
true);
2266 suppr->get_source_locations_to_keep().insert(file_path);
2282handle_fts_entry(
const FTSENT *entry,
2286 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2287 || entry->fts_info == FTS_ERR
2288 || entry->fts_info == FTS_NS)
2291 string fname = entry->fts_name;
2297 handle_file_entry (fname, suppr);
2315gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2318 if (!headers_root_dir.empty())
2320 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2322 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2325 while ((entry = fts_read(file_hierarchy)))
2326 handle_fts_entry(entry, result);
2327 fts_close(file_hierarchy);
2348 const vector<string>& header_files)
2352 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2353 root_dir != headers_root_dirs.end();
2355 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2357 for (vector<string>::const_iterator file = header_files.begin();
2358 file != header_files.end();
2360 handle_file_entry(*file, result);
2380 const vector<string>& header_files)
2383 vector<string> root_dirs;
2385 if (!headers_root_dir.empty())
2386 root_dirs.push_back(headers_root_dir);
2404 vector<string> header_files;
2435 (
const std::vector<std::string>& abi_whitelist_paths)
2438 std::vector<std::string> whitelisted_names;
2439 for (std::vector<std::string>::const_iterator
2440 path_iter = abi_whitelist_paths.begin(),
2441 path_end = abi_whitelist_paths.end();
2442 path_iter != path_end;
2453 for (ini::config::sections_type::const_iterator
2454 section_iter = whitelist_sections.begin(),
2455 section_end = whitelist_sections.end();
2456 section_iter != section_end;
2459 std::string section_name = (*section_iter)->get_name();
2463 for (ini::config::properties_type::const_iterator
2464 prop_iter = (*section_iter)->get_properties().begin(),
2465 prop_end = (*section_iter)->get_properties().end();
2466 prop_iter != prop_end;
2471 if (prop->has_empty_value())
2473 const std::string& name = prop->get_name();
2475 whitelisted_names.push_back(name);
2482 if (!whitelisted_names.empty())
2485 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2486 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2487 whitelisted_names.end()),
2488 whitelisted_names.end());
2500 fn_suppr->set_label(
"whitelist");
2501 fn_suppr->set_symbol_name_not_regex_str(regex);
2502 fn_suppr->set_drops_artifact_from_ir(
true);
2503 result.push_back(fn_suppr);
2511 var_suppr->set_label(
"whitelist");
2512 var_suppr->set_symbol_name_not_regex_str(regex);
2513 var_suppr->set_drops_artifact_from_ir(
true);
2514 result.push_back(var_suppr);
2525 string default_system_suppr_path;
2527 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2529 default_system_suppr_path = s;
2531 if (default_system_suppr_path.empty())
2532 default_system_suppr_path =
2535 return default_system_suppr_path;
2544 string default_user_suppr_path;
2545 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2552 default_user_suppr_path = s;
2553 if (default_user_suppr_path.empty())
2554 default_user_suppr_path =
"~";
2555 default_user_suppr_path +=
"/.abignore";
2558 default_user_suppr_path = s;
2560 return default_user_suppr_path;
2574 string default_system_suppr_path =
2590 string default_user_suppr_path =
2611entry_of_file_with_name(
const FTSENT *entry,
2612 const string& fname,
2613 const string& root_dir)
2616 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2617 || entry->fts_info == FTS_ERR
2618 || entry->fts_info == FTS_NS)
2621 string fpath = ::basename(entry->fts_path);
2625 fpath = trim_leading_string(entry->fts_path, root_dir);
2644 const string& file_path_to_look_for,
2647 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2649 FTS *file_hierarchy = fts_open(paths,
2650 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2651 if (!file_hierarchy)
2654 string r = root_dir;
2659 while ((entry = fts_read(file_hierarchy)))
2661 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2663 result = entry->fts_path;
2664 fts_close(file_hierarchy);
2668 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2670 fts_set(file_hierarchy, entry, FTS_SKIP);
2675 fts_close(file_hierarchy);
2692 const string& file_path_to_look_for,
2695 if (root_dirs.empty())
2698 for (
const auto& root_dir : root_dirs)
2727 const vector<string>& deps_dirs,
2728 set<string>& dependencies)
2730 const vector<string>& set_of_needed = korpus.
get_needed();
2731 if (set_of_needed.empty())
2734 bool found_at_least_one_dependency =
false;
2735 for (
const auto& n :set_of_needed)
2738 if (dependencies.find(n) == dependencies.end()
2741 dependencies.insert(dependency);
2742 found_at_least_one_dependency =
true;
2746 return found_at_least_one_dependency;
2764 const vector<string>& binaries,
2765 const vector<string>& deps_dirs,
2768 vector<string> bins;
2770 for (
const auto& b : binaries)
2774 bins.push_back(bin);
2777 for (
const auto& b : bins)
2782 reader->initialize(b);
2784 corpus_sptr c = reader->read_corpus(stat);
2805 const vector<string>& deps_dirs,
2813 for (
const auto& dep: deps)
2818 reader->initialize(dep);
2820 corpus_sptr c = reader->read_corpus(stat);
2848 const corpus_sptr& korpus,
2849 const vector<string>& binaries,
2850 const vector<string>& bins_dirs)
2852 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2853 korpus->get_path()));
2854 result->add_corpus(korpus);
2877 const corpus_sptr& korpus,
2878 const vector<string>& deps_dirs)
2880 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2881 korpus->get_path()));
2882 result->add_corpus(korpus);
2910 vector<string>& suppr_paths,
2911 vector<string>& kabi_whitelist_paths,
2916 for (vector<string>::const_iterator i = suppr_paths.begin();
2917 i != suppr_paths.end();
2922 gen_suppr_spec_from_kernel_abi_whitelists(kabi_whitelist_paths);
2924 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2937is_vmlinux(
const FTSENT *entry)
2940 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2941 || entry->fts_info == FTS_ERR
2942 || entry->fts_info == FTS_NS)
2945 string fname = entry->fts_name;
2947 if (fname ==
"vmlinux")
2950 dir_name(entry->fts_path, dirname);
2967is_kernel_module(
const FTSENT *entry)
2970 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2971 || entry->fts_info == FTS_ERR
2972 || entry->fts_info == FTS_NS)
2975 string fname = entry->fts_name;
2991is_file(
const FTSENT *entry)
2994 && (entry->fts_info == FTS_F
2995 || entry->fts_info == FTS_SL));
3011find_vmlinux_and_module_paths(
const string& from,
3012 string &vmlinux_path,
3013 vector<string> &module_paths)
3015 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3017 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3018 if (!file_hierarchy)
3021 bool found_vmlinux = !vmlinux_path.empty();
3023 while ((entry = fts_read(file_hierarchy)))
3026 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3028 fts_set(file_hierarchy, entry, FTS_SKIP);
3032 if (!found_vmlinux && is_vmlinux(entry))
3034 vmlinux_path = entry->fts_path;
3035 found_vmlinux =
true;
3037 else if (is_kernel_module(entry))
3038 module_paths.push_back(entry->fts_path);
3041 fts_close(file_hierarchy);
3043 return found_vmlinux;
3054find_vmlinux_path(
const string& from,
3055 string &vmlinux_path)
3057 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3059 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3060 if (!file_hierarchy)
3063 bool found_vmlinux =
false;
3065 while ((entry = fts_read(file_hierarchy)))
3068 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3070 fts_set(file_hierarchy, entry, FTS_SKIP);
3074 if (!found_vmlinux && is_vmlinux(entry))
3076 vmlinux_path = entry->fts_path;
3077 found_vmlinux =
true;
3082 fts_close(file_hierarchy);
3084 return found_vmlinux;
3097 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
3098 FTS *file_hierarchy = fts_open(paths,
3099 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3100 if (!file_hierarchy)
3103 string r = root_dir;
3107 bool found_file =
false;
3109 while ((entry = fts_read(file_hierarchy)))
3112 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3114 fts_set(file_hierarchy, entry, FTS_SKIP);
3121 string path = entry->fts_path;
3123 dirs.push_back(path);
3126 fts_close(file_hierarchy);
3149 const string& debug_info_root_path,
3150 string& vmlinux_path,
3151 vector<string>& module_paths)
3164 string kernel_modules_root = dist_root;
3165 string debug_info_root;
3168 kernel_modules_root = dist_root +
"/lib/modules";
3169 debug_info_root = debug_info_root_path.empty()
3170 ? dist_root +
"/usr/lib/debug"
3171 : debug_info_root_path;
3175 debug_info_root.clear();
3183 find_vmlinux_and_module_paths(kernel_modules_root,
3188 || find_vmlinux_and_module_paths(debug_info_root,
3193 std::sort(module_paths.begin(), module_paths.end());
3209 string& vmlinux_path)
3220 string dist_root = from;
3222 dist_root +=
"/lib/modules";
3225 if (find_vmlinux_path(dist_root, vmlinux_path))
3245 string& vmlinux_path,
3246 vector<string>& module_paths)
3248 string debug_info_root_path;
3250 debug_info_root_path,
3293load_vmlinux_corpus(elf_based_reader_sptr rdr,
3294 corpus_group_sptr& group,
3295 const string& vmlinux,
3296 vector<string>& modules,
3298 vector<string>& di_roots,
3299 vector<string>& suppr_paths,
3300 vector<string>& kabi_wl_paths,
3307 rdr->options().do_log = verbose;
3311 std::cerr <<
"Loading stable lists:'";
3312 for (
auto s : kabi_wl_paths)
3313 std::cerr << s <<
",";
3314 std::cerr <<
"'...\n";
3317 load_generate_apply_suppressions(*rdr, suppr_paths,
3318 kabi_wl_paths, supprs);
3322 std::cerr <<
"loaded white list and generated suppr spec in: "
3328 rdr->corpus_group(group);
3331 std::cerr <<
"reading kernel binary '"
3332 << vmlinux <<
"' ...\n" << std::flush;
3335 rdr->options().load_in_linux_kernel_mode =
true;
3337 rdr->read_and_add_corpus_to_group(*group, status);
3341 std::cerr << vmlinux
3342 <<
" reading DONE in:"
3345 if (group->is_empty())
3349 int total_nb_modules = modules.size();
3350 int cur_module_index = 1;
3351 for (vector<string>::const_iterator m = modules.begin();
3353 ++m, ++cur_module_index)
3356 std::cerr <<
"reading module '"
3359 <<
"/" << total_nb_modules
3360 <<
") ...\n" << std::flush;
3362 rdr->initialize(*m, di_roots);
3364 load_generate_apply_suppressions(*rdr, suppr_paths,
3365 kabi_wl_paths, supprs);
3367 rdr->corpus_group(group);
3370 rdr->read_and_add_corpus_to_group(*group, status);
3373 std::cerr <<
"Module reading DONE in: "
3374 << t <<
" for '" << *m
3375 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3381 std::cerr <<
"Total number of functions: "
3382 << group->get_functions().size() <<
"\n";
3383 std::cerr <<
"Total number of variables: "
3384 << group->get_variables().size() <<
"\n";
3431 const string debug_info_root,
3432 const string& vmlinux_path,
3433 vector<string>& suppr_paths,
3434 vector<string>& kabi_wl_paths,
3441 string vmlinux = vmlinux_path;
3442 corpus_group_sptr group;
3443 vector<string> modules;
3446 std::cerr <<
"Analysing kernel dist root '"
3448 <<
"' with vmlinux path: '"
3450 <<
"' ... \n" << std::flush;
3455 bool got_binary_paths =
3460 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3462 if (got_binary_paths)
3466 vector<string> di_roots;
3467 di_roots.push_back(di_root);
3471 if (requested_fe_kind & corpus::CTF_ORIGIN)
3474 di_roots.push_back(di_root_ctf);
3478 abigail::elf_based_reader_sptr reader =
3485 load_vmlinux_corpus(reader, group, vmlinux,
3486 modules, root, di_roots,
3487 suppr_paths, kabi_wl_paths,
3488 supprs, verbose, t, env);
3533 const string debug_info_root,
3534 const string& vmlinux_path,
3535 vector<string>& suppr_paths,
3536 vector<string>& kabi_wl_paths,
3544 vmlinux_path, suppr_paths,
3545 kabi_wl_paths, supprs,
3585elf_based_reader_sptr
3587 const vector<string>& debug_info_root_paths,
3592 elf_based_reader_sptr result;
3596 if (requested_fe_kind & corpus::CTF_ORIGIN)
3604 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3608 result = btf::create_reader(elf_file_path, debug_info_root_paths,
3629 result = btf::create_reader(elf_file_path, debug_info_root_paths,
3640 debug_info_root_paths,
3679elf_based_reader_sptr
3681 const vector<string>& debug_info_root_paths,
3687 env, requested_debug_info_kind, o);
3695struct xz_decompressor_type::priv
3697 std::istream& xz_istream;
3701 char inbuf[1024 * 100] = {};
3704 char outbuf[1024 * 100] = {};
3706 priv(std::istream& i)
3708 lzma(LZMA_STREAM_INIT)
3716xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
3717 : priv_(new priv(xz_istream))
3720 lzma_ret status = lzma_stream_decoder(&priv_->lzma,
3729 lzma_end(&priv_->lzma);
3740std::streambuf::int_type
3743 if (gptr() < egptr())
3747 priv_->xz_istream.read(priv_->inbuf,
sizeof(priv_->inbuf));
3748 size_t nr = priv_->xz_istream.gcount();
3754 priv_->lzma.avail_in = nr;
3755 priv_->lzma.next_in =
reinterpret_cast<uint8_t*
>(priv_->inbuf);
3758 if (priv_->lzma.avail_out || priv_->lzma.avail_in)
3763 priv_->lzma.avail_out =
sizeof(priv_->outbuf);
3764 priv_->lzma.next_out =
reinterpret_cast<uint8_t*
>(priv_->outbuf);
3769 lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
3770 if (result != LZMA_OK && result != LZMA_STREAM_END)
3775 std::ostringstream o;
3776 o <<
"LZMA decompression failed;"
3777 <<
" return code of lzma_code() is : "
3779 throw std::runtime_error(o.str());
3785 size_t nr_decompressed_bytes =
sizeof(priv_->outbuf) - priv_->lzma.avail_out;
3788 setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
3790 if (nr_decompressed_bytes > 0)
3796 result = lzma_code(&priv_->lzma, LZMA_FINISH);
3797 ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
3798 return traits_type::eof();
3825 std::vector<function_decl*>::const_iterator a_end,
3826 std::vector<function_decl*>::const_iterator b_begin,
3827 std::vector<function_decl*>::const_iterator b_end)
3828{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3842 std::vector<function_decl*>::const_iterator a_end,
3843 std::vector<function_decl*>::const_iterator b_begin,
3844 std::vector<function_decl*>::const_iterator b_end)
3846 std::vector<function_decl*>::const_iterator i;
3847 std::ostream& o = std::cerr;
3848 for (i = a_begin; i != a_end; ++i)
3849 o << (*i)->get_pretty_representation() <<
"\n";
3852 for (i = b_begin; i != b_end; ++i)
3853 o << (*i)->get_pretty_representation() <<
"\n";
3866 unsigned f1_index,
unsigned f2_index)
3871 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.
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< string > &debug_info_root_paths, environment &env, const fe_iface::options_type &options)
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< string > &debug_info_root_paths, environment &environment, const fe_iface::options_type &options)
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.
void initialize()
The initialization function of libxml2 abstraction layer. This function must be called prior to using...
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...
The generic options that control the behaviour of all Front-End interfaces.