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());
1122common_prefix(
const string& s1,
const string& s2,
string &result)
1124 if (s1.length() == 0 || s2.length() == 0)
1128 for (
size_t i = 0; i < s1.length() && i< s2.length(); ++i)
1134 return !result.empty();
1153 string prefix_candidate;
1154 bool found_prefix =
false;
1156 if (input_strings.size() == 1)
1158 if (
dir_name(input_strings.front(), prefix,
1165 for (vector<string>::const_iterator i = input_strings.begin();
1166 i != input_strings.end();
1170 if (prefix_candidate.empty())
1172 prefix_candidate = cur_str;
1177 if (common_prefix(prefix_candidate, cur_str, s))
1180 prefix_candidate = s;
1181 found_prefix =
true;
1187 prefix = prefix_candidate;
1200 string major, minor, revision, version_string, suffix;
1202 version_string = major +
"." + minor +
"." + revision + suffix;
1203 return version_string;
1212 string major, minor, version_string;
1214 version_string = major +
"." + minor;
1215 return version_string;
1244#define TMP_BUF_LEN 1024 + 1
1245 char tmp_buf[TMP_BUF_LEN];
1246 memset(tmp_buf, 0, TMP_BUF_LEN);
1248 while (fgets(tmp_buf, TMP_BUF_LEN, stream))
1250 lines.push_back(tmp_buf);
1251 memset(tmp_buf, 0, TMP_BUF_LEN);
1254 if (pclose(stream) == -1)
1275 const string& option,
1276 vector<string>& arguments)
1278 string s = input_str;
1284 s = s.substr(0, s.size() - 1);
1306 vector<string> query_output;
1312 + rpm_path +
" 2> /dev/null | grep .so",
1315 for (vector<string>::const_iterator line = query_output.begin();
1316 line != query_output.end();
1319 string dso = line->substr(0, line->find(
'('));
1322 provided_dsos.insert(dso);
1339 string::size_type start, end;
1340 for (start = 0; start < str.length(); ++start)
1341 if (!isspace(str[start]))
1344 for (end = str.length() - 1; end > 0; --end)
1345 if (!isspace(str[end]))
1348 result = str.substr(start, end - start + 1);
1360 if (str.erase(std::remove_if(str.begin(), str.end(), isspace),
1361 str.end()) == str.end())
1379 static std::regex re(
"([0-9]+)([uUlL])+");
1394 bool begin_pattern =
false, middle_pattern =
false, found_litteral =
false;
1395 for (string::iterator i = str.begin(); i < str.end(); ++i)
1398 begin_pattern =
true;
1402 && (*i ==
'u' || *i ==
'U' || *i ==
'l' || *i ==
'L'))
1403 middle_pattern =
true;
1408 found_litteral =
true;
1417 std::regex& re = get_litteral_regex();
1418 str = std::regex_replace(str, re,
"$1");
1458 vector<char**>& char_star_stars)
1460 for (vector<char*>::const_iterator i = char_stars.begin();
1461 i != char_stars.end();
1463 char_star_stars.push_back(
const_cast<char**
>(&*i));
1467struct temp_file::priv
1469 char* path_template_;
1471 shared_ptr<std::fstream> fstream_;
1475 const char* templat =
"/tmp/libabigail-tmp-file-XXXXXX";
1476 int s = strlen(templat);
1477 path_template_ =
new char[s + 1];
1478 memset(path_template_, 0, s + 1);
1479 memcpy(path_template_, templat, s);
1481 fd_ = mkstemp(path_template_);
1485 fstream_.reset(
new std::fstream(path_template_,
1493 if (fd_ && fd_ != -1)
1497 remove(path_template_);
1499 delete [] path_template_;
1506temp_file::temp_file()
1515temp_file::is_good()
const
1516{
return priv_->fstream_->good();}
1523temp_file::get_path()
const
1526 return priv_->path_template_;
1540temp_file::get_stream()
1543 return *priv_->fstream_;
1554 if (result->is_good())
1566 static __thread
bool initialized =
false;
1583 std::ostringstream o;
1597 case FILE_TYPE_UNKNOWN:
1598 repr =
"unknown file type";
1600 case FILE_TYPE_NATIVE_BI:
1601 repr =
"native binary instrumentation file type";
1604 repr =
"ELF file type";
1607 repr =
"archive file type";
1609 case FILE_TYPE_XML_CORPUS:
1610 repr =
"native XML corpus file type";
1612 case FILE_TYPE_XML_CORPUS_GROUP:
1613 repr =
"native XML corpus group file type";
1616 repr =
"RPM file type";
1618 case FILE_TYPE_SRPM:
1619 repr =
"SRPM file type";
1622 repr =
"Debian binary file type";
1625 repr =
"Directory type";
1628 repr =
"GNU tar archive type";
1631 repr =
"XZ compressed file";
1646 COMPRESSION_KIND_UNKNOWN,
1658static compression_kind
1659is_compressed_file_type(file_type t)
1661 if (t == FILE_TYPE_XZ)
1662 return COMPRESSION_KIND_XZ;
1664 return COMPRESSION_KIND_UNKNOWN;
1675 const unsigned BUF_LEN = 264;
1676 const unsigned NB_BYTES_TO_READ = 263;
1678 unsigned char buf[BUF_LEN];
1679 memset(buf, 0, BUF_LEN);
1681 std::streampos initial_pos = in.tellg();
1682 in.read(
reinterpret_cast<char*
>(buf), NB_BYTES_TO_READ);
1683 in.seekg(initial_pos);
1685 if (in.gcount() < 4 || in.bad())
1696 if (in.gcount() >= 6
1713 if (strstr(
reinterpret_cast<char*
>(buf),
"debian-binary"))
1750 return FILE_TYPE_XML_CORPUS_GROUP;
1764 return FILE_TYPE_XML_CORPUS;
1768 if ((
unsigned char) buf[0] == 0xed
1769 && (
unsigned char) buf[1] == 0xab
1770 && (
unsigned char) buf[2] == 0xee
1771 && (
unsigned char) buf[3] == 0xdb)
1775 else if (buf[7] == 0x01)
1806static shared_ptr<std::streambuf>
1807get_decompressed_streambuf(std::istream& compressed_input,
1808 compression_kind compr)
1810 shared_ptr<std::streambuf> result;
1814 case COMPRESSION_KIND_UNKNOWN:
1818 case COMPRESSION_KIND_XZ:
1819 shared_ptr<std::streambuf> r(
new xz_decompressor_type(compressed_input));
1861 shared_ptr<std::streambuf> decompressor_streambuf;
1873 if (is_compressed_file_type(r) && !look_through_compression)
1878 shared_ptr<ifstream> input_fstream(
new ifstream(file_path.c_str(),
1880 shared_ptr<istream> input_stream = input_fstream;
1882 if (compr_kind != COMPRESSION_KIND_UNKNOWN)
1883 decompressor_streambuf = get_decompressed_streambuf(*input_stream,
1886 if (decompressor_streambuf)
1887 input_stream.reset(
new istream(decompressor_streambuf.get()));
1891 input_fstream->close();
1893 if (!decompressor_streambuf)
1898 compr_kind = is_compressed_file_type(r);
1901 if (!look_through_compression)
1919 }
while (!decompressor_streambuf && compr_kind);
1936 if (str.empty() || str[0] ==
'_')
1939 string::size_type str_len = str.length(), i = 0 ;
1941 for (; i < str_len; ++i)
1950 name = str.substr(0, i);
1966 if (str.empty() || str[0] ==
'-')
1969 string::size_type str_len = str.length(), i = 0;
1970 string::value_type c;
1972 for (; i < str_len; ++i)
1975 string::size_type next_index = i + 1;
1976 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
1983 name = str.substr(0, i);
2006 string::size_type str_len = str.length(), i = 0;
2007 string::value_type c;
2008 string::size_type last_dot_index = 0, dot_before_last_index = 0;
2010 for (i = str_len - 1; i > 0; --i)
2023 for(--i; i > 0; --i)
2028 dot_before_last_index = i;
2036 arch = str.substr(dot_before_last_index + 1,
2037 last_dot_index - dot_before_last_index - 1);
2053 bool result =
false;
2064 string package_name;
2083 vector<string> query_output;
2089 + rpm_path +
" 2> /dev/null",
2092 for (
auto& line : query_output)
2113 bool result =
false;
2114 string package_name;
2120 result = (package_name ==
"kernel-debuginfo");
2136struct malloced_char_star_deleter
2139 operator()(
char* ptr)
2154std::shared_ptr<char>
2157 using std::shared_ptr;
2159 shared_ptr<char> result;
2161 if (p && p[0] !=
'/')
2163 shared_ptr<char> pwd(get_current_dir_name(),
2164 malloced_char_star_deleter());
2165 string s = string(pwd.get()) +
"/" + p;
2166 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
2169 result.reset(strdup(p), malloced_char_star_deleter());
2187 if (!p.empty() && p[0] !=
'/')
2189 shared_ptr<char> pwd(get_current_dir_name(),
2190 malloced_char_star_deleter());
2191 result = string(pwd.get()) +
"/" + p;
2193 else if (!p.empty())
2215handle_file_entry(
const string& file_path,
2226 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2227 suppr->set_is_artificial(
true);
2233 suppr->get_source_locations_to_keep().insert(file_path);
2249handle_fts_entry(
const FTSENT *entry,
2253 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2254 || entry->fts_info == FTS_ERR
2255 || entry->fts_info == FTS_NS)
2258 string fname = entry->fts_name;
2264 handle_file_entry (fname, suppr);
2282gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2285 if (!headers_root_dir.empty())
2287 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2289 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2292 while ((entry = fts_read(file_hierarchy)))
2293 handle_fts_entry(entry, result);
2294 fts_close(file_hierarchy);
2315 const vector<string>& header_files)
2319 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2320 root_dir != headers_root_dirs.end();
2322 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2324 for (vector<string>::const_iterator file = header_files.begin();
2325 file != header_files.end();
2327 handle_file_entry(*file, result);
2347 const vector<string>& header_files)
2350 vector<string> root_dirs;
2352 if (!headers_root_dir.empty())
2353 root_dirs.push_back(headers_root_dir);
2371 vector<string> header_files;
2402 (
const std::vector<std::string>& abi_whitelist_paths)
2405 std::vector<std::string> whitelisted_names;
2406 for (std::vector<std::string>::const_iterator
2407 path_iter = abi_whitelist_paths.begin(),
2408 path_end = abi_whitelist_paths.end();
2409 path_iter != path_end;
2420 for (ini::config::sections_type::const_iterator
2421 section_iter = whitelist_sections.begin(),
2422 section_end = whitelist_sections.end();
2423 section_iter != section_end;
2426 std::string section_name = (*section_iter)->get_name();
2430 for (ini::config::properties_type::const_iterator
2431 prop_iter = (*section_iter)->get_properties().begin(),
2432 prop_end = (*section_iter)->get_properties().end();
2433 prop_iter != prop_end;
2438 if (prop->has_empty_value())
2440 const std::string& name = prop->get_name();
2442 whitelisted_names.push_back(name);
2449 if (!whitelisted_names.empty())
2452 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2453 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2454 whitelisted_names.end()),
2455 whitelisted_names.end());
2467 fn_suppr->set_label(
"whitelist");
2468 fn_suppr->set_symbol_name_not_regex_str(regex);
2469 fn_suppr->set_drops_artifact_from_ir(
true);
2470 result.push_back(fn_suppr);
2478 var_suppr->set_label(
"whitelist");
2479 var_suppr->set_symbol_name_not_regex_str(regex);
2480 var_suppr->set_drops_artifact_from_ir(
true);
2481 result.push_back(var_suppr);
2492 string default_system_suppr_path;
2494 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2496 default_system_suppr_path = s;
2498 if (default_system_suppr_path.empty())
2499 default_system_suppr_path =
2502 return default_system_suppr_path;
2511 string default_user_suppr_path;
2512 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2519 default_user_suppr_path = s;
2520 if (default_user_suppr_path.empty())
2521 default_user_suppr_path =
"~";
2522 default_user_suppr_path +=
"/.abignore";
2525 default_user_suppr_path = s;
2527 return default_user_suppr_path;
2541 string default_system_suppr_path =
2557 string default_user_suppr_path =
2578entry_of_file_with_name(
const FTSENT *entry,
2579 const string& fname,
2580 const string& root_dir)
2583 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2584 || entry->fts_info == FTS_ERR
2585 || entry->fts_info == FTS_NS)
2588 string fpath = ::basename(entry->fts_path);
2592 fpath = trim_leading_string(entry->fts_path, root_dir);
2611 const string& file_path_to_look_for,
2614 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2616 FTS *file_hierarchy = fts_open(paths,
2617 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2618 if (!file_hierarchy)
2621 string r = root_dir;
2626 while ((entry = fts_read(file_hierarchy)))
2628 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2630 result = entry->fts_path;
2631 fts_close(file_hierarchy);
2635 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2637 fts_set(file_hierarchy, entry, FTS_SKIP);
2642 fts_close(file_hierarchy);
2659 const string& file_path_to_look_for,
2662 if (root_dirs.empty())
2665 for (
const auto& root_dir : root_dirs)
2694 const vector<string>& deps_dirs,
2695 set<string>& dependencies)
2697 const vector<string>& set_of_needed = korpus.
get_needed();
2698 if (set_of_needed.empty())
2701 bool found_at_least_one_dependency =
false;
2702 for (
const auto& n :set_of_needed)
2705 if (dependencies.find(n) == dependencies.end()
2708 dependencies.insert(dependency);
2709 found_at_least_one_dependency =
true;
2713 return found_at_least_one_dependency;
2731 const vector<string>& binaries,
2732 const vector<string>& deps_dirs,
2735 vector<string> bins;
2737 for (
const auto& b : binaries)
2741 bins.push_back(bin);
2744 for (
const auto& b : bins)
2749 reader->initialize(b);
2751 corpus_sptr c = reader->read_corpus(stat);
2772 const vector<string>& deps_dirs,
2780 for (
const auto& dep: deps)
2785 reader->initialize(dep);
2787 corpus_sptr c = reader->read_corpus(stat);
2815 const corpus_sptr& korpus,
2816 const vector<string>& binaries,
2817 const vector<string>& bins_dirs)
2819 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2820 korpus->get_path()));
2821 result->add_corpus(korpus);
2844 const corpus_sptr& korpus,
2845 const vector<string>& deps_dirs)
2847 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2848 korpus->get_path()));
2849 result->add_corpus(korpus);
2877 vector<string>& suppr_paths,
2878 vector<string>& kabi_whitelist_paths,
2883 for (vector<string>::const_iterator i = suppr_paths.begin();
2884 i != suppr_paths.end();
2889 gen_suppr_spec_from_kernel_abi_whitelists(kabi_whitelist_paths);
2891 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2904is_vmlinux(
const FTSENT *entry)
2907 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2908 || entry->fts_info == FTS_ERR
2909 || entry->fts_info == FTS_NS)
2912 string fname = entry->fts_name;
2914 if (fname ==
"vmlinux")
2917 dir_name(entry->fts_path, dirname);
2934is_kernel_module(
const FTSENT *entry)
2937 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2938 || entry->fts_info == FTS_ERR
2939 || entry->fts_info == FTS_NS)
2942 string fname = entry->fts_name;
2958is_file(
const FTSENT *entry)
2961 && (entry->fts_info == FTS_F
2962 || entry->fts_info == FTS_SL));
2978find_vmlinux_and_module_paths(
const string& from,
2979 string &vmlinux_path,
2980 vector<string> &module_paths)
2982 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2984 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2985 if (!file_hierarchy)
2988 bool found_vmlinux = !vmlinux_path.empty();
2990 while ((entry = fts_read(file_hierarchy)))
2993 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2995 fts_set(file_hierarchy, entry, FTS_SKIP);
2999 if (!found_vmlinux && is_vmlinux(entry))
3001 vmlinux_path = entry->fts_path;
3002 found_vmlinux =
true;
3004 else if (is_kernel_module(entry))
3005 module_paths.push_back(entry->fts_path);
3008 fts_close(file_hierarchy);
3010 return found_vmlinux;
3021find_vmlinux_path(
const string& from,
3022 string &vmlinux_path)
3024 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3026 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3027 if (!file_hierarchy)
3030 bool found_vmlinux =
false;
3032 while ((entry = fts_read(file_hierarchy)))
3035 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3037 fts_set(file_hierarchy, entry, FTS_SKIP);
3041 if (!found_vmlinux && is_vmlinux(entry))
3043 vmlinux_path = entry->fts_path;
3044 found_vmlinux =
true;
3049 fts_close(file_hierarchy);
3051 return found_vmlinux;
3064 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
3065 FTS *file_hierarchy = fts_open(paths,
3066 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3067 if (!file_hierarchy)
3070 string r = root_dir;
3074 bool found_file =
false;
3076 while ((entry = fts_read(file_hierarchy)))
3079 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3081 fts_set(file_hierarchy, entry, FTS_SKIP);
3088 string path = entry->fts_path;
3090 dirs.push_back(path);
3093 fts_close(file_hierarchy);
3116 const string& debug_info_root_path,
3117 string& vmlinux_path,
3118 vector<string>& module_paths)
3131 string kernel_modules_root = dist_root;
3132 string debug_info_root;
3135 kernel_modules_root = dist_root +
"/lib/modules";
3136 debug_info_root = debug_info_root_path.empty()
3137 ? dist_root +
"/usr/lib/debug"
3138 : debug_info_root_path;
3142 debug_info_root.clear();
3150 find_vmlinux_and_module_paths(kernel_modules_root,
3155 || find_vmlinux_and_module_paths(debug_info_root,
3160 std::sort(module_paths.begin(), module_paths.end());
3176 string& vmlinux_path)
3187 string dist_root = from;
3189 dist_root +=
"/lib/modules";
3192 if (find_vmlinux_path(dist_root, vmlinux_path))
3212 string& vmlinux_path,
3213 vector<string>& module_paths)
3215 string debug_info_root_path;
3217 debug_info_root_path,
3260load_vmlinux_corpus(elf_based_reader_sptr rdr,
3261 corpus_group_sptr& group,
3262 const string& vmlinux,
3263 vector<string>& modules,
3265 vector<string>& di_roots,
3266 vector<string>& suppr_paths,
3267 vector<string>& kabi_wl_paths,
3274 rdr->options().do_log = verbose;
3278 std::cerr <<
"Loading stable lists:'";
3279 for (
auto s : kabi_wl_paths)
3280 std::cerr << s <<
",";
3281 std::cerr <<
"'...\n";
3284 load_generate_apply_suppressions(*rdr, suppr_paths,
3285 kabi_wl_paths, supprs);
3289 std::cerr <<
"loaded white list and generated suppr spec in: "
3295 rdr->corpus_group(group);
3298 std::cerr <<
"reading kernel binary '"
3299 << vmlinux <<
"' ...\n" << std::flush;
3303 rdr->read_and_add_corpus_to_group(*group, status);
3307 std::cerr << vmlinux
3308 <<
" reading DONE in:"
3311 if (group->is_empty())
3315 int total_nb_modules = modules.size();
3316 int cur_module_index = 1;
3317 for (vector<string>::const_iterator m = modules.begin();
3319 ++m, ++cur_module_index)
3322 std::cerr <<
"reading module '"
3325 <<
"/" << total_nb_modules
3326 <<
") ...\n" << std::flush;
3328 rdr->initialize(*m, di_roots,
3332 load_generate_apply_suppressions(*rdr, suppr_paths,
3333 kabi_wl_paths, supprs);
3335 rdr->corpus_group(group);
3338 rdr->read_and_add_corpus_to_group(*group, status);
3341 std::cerr <<
"Module reading DONE in: "
3342 << t <<
" for '" << *m
3343 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3349 std::cerr <<
"Total number of functions: "
3350 << group->get_functions().size() <<
"\n";
3351 std::cerr <<
"Total number of variables: "
3352 << group->get_variables().size() <<
"\n";
3395 const string debug_info_root,
3396 const string& vmlinux_path,
3397 vector<string>& suppr_paths,
3398 vector<string>& kabi_wl_paths,
3404 string vmlinux = vmlinux_path;
3405 corpus_group_sptr group;
3406 vector<string> modules;
3409 std::cerr <<
"Analysing kernel dist root '"
3411 <<
"' with vmlinux path: '"
3413 <<
"' ... \n" << std::flush;
3418 bool got_binary_paths =
3423 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3425 if (got_binary_paths)
3429 vector<string> di_roots;
3430 di_roots.push_back(di_root);
3434 if (requested_fe_kind & corpus::CTF_ORIGIN)
3437 di_roots.push_back(di_root_ctf);
3441 abigail::elf_based_reader_sptr reader =
3449 load_vmlinux_corpus(reader, group, vmlinux,
3450 modules, root, di_roots,
3451 suppr_paths, kabi_wl_paths,
3452 supprs, verbose, t, env);
3493elf_based_reader_sptr
3495 const vector<string>& debug_info_root_paths,
3498 bool show_all_types,
3499 bool linux_kernel_mode)
3501 elf_based_reader_sptr result;
3505 if (requested_fe_kind & corpus::CTF_ORIGIN)
3512 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3517 show_all_types, linux_kernel_mode);
3537 show_all_types, linux_kernel_mode);
3547 debug_info_root_paths,
3561struct xz_decompressor_type::priv
3563 std::istream& xz_istream;
3567 char inbuf[1024 * 100] = {};
3570 char outbuf[1024 * 100] = {};
3572 priv(std::istream& i)
3574 lzma(LZMA_STREAM_INIT)
3582xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
3583 : priv_(new priv(xz_istream))
3586 lzma_ret status = lzma_stream_decoder(&priv_->lzma,
3595 lzma_end(&priv_->lzma);
3606std::streambuf::int_type
3609 if (gptr() < egptr())
3613 priv_->xz_istream.read(priv_->inbuf,
sizeof(priv_->inbuf));
3614 size_t nr = priv_->xz_istream.gcount();
3620 priv_->lzma.avail_in = nr;
3621 priv_->lzma.next_in =
reinterpret_cast<uint8_t*
>(priv_->inbuf);
3624 if (priv_->lzma.avail_out || priv_->lzma.avail_in)
3629 priv_->lzma.avail_out =
sizeof(priv_->outbuf);
3630 priv_->lzma.next_out =
reinterpret_cast<uint8_t*
>(priv_->outbuf);
3635 lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
3636 if (result != LZMA_OK && result != LZMA_STREAM_END)
3641 std::ostringstream o;
3642 o <<
"LZMA decompression failed;"
3643 <<
" return code of lzma_code() is : "
3645 throw std::runtime_error(o.str());
3651 size_t nr_decompressed_bytes =
sizeof(priv_->outbuf) - priv_->lzma.avail_out;
3654 setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
3656 if (nr_decompressed_bytes > 0)
3662 result = lzma_code(&priv_->lzma, LZMA_FINISH);
3663 ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
3664 return traits_type::eof();
3691 std::vector<function_decl*>::const_iterator a_end,
3692 std::vector<function_decl*>::const_iterator b_begin,
3693 std::vector<function_decl*>::const_iterator b_end)
3694{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3708 std::vector<function_decl*>::const_iterator a_end,
3709 std::vector<function_decl*>::const_iterator b_begin,
3710 std::vector<function_decl*>::const_iterator b_end)
3712 std::vector<function_decl*>::const_iterator i;
3713 std::ostream& o = std::cerr;
3714 for (i = a_begin; i != a_end; ++i)
3715 o << (*i)->get_pretty_representation() <<
"\n";
3718 for (i = b_begin; i != b_end; ++i)
3719 o << (*i)->get_pretty_representation() <<
"\n";
3732 unsigned f1_index,
unsigned f2_index)
3737 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< string > &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< string > &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< string > &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.
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...