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())
2215 if (p && p[0] !=
'/')
2217 char* pwd = get_current_dir_name();
2218 string s = string(pwd) +
"/" + p;
2220 result = strdup(s.c_str());
2244handle_file_entry(
const string& file_path,
2255 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2256 suppr->set_is_artificial(
true);
2262 suppr->get_source_locations_to_keep().insert(file_path);
2278handle_fts_entry(
const FTSENT *entry,
2282 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2283 || entry->fts_info == FTS_ERR
2284 || entry->fts_info == FTS_NS)
2287 string fname = entry->fts_name;
2293 handle_file_entry (fname, suppr);
2311gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2314 if (!headers_root_dir.empty())
2316 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2318 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2321 while ((entry = fts_read(file_hierarchy)))
2322 handle_fts_entry(entry, result);
2323 fts_close(file_hierarchy);
2344 const vector<string>& header_files)
2348 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2349 root_dir != headers_root_dirs.end();
2351 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2353 for (vector<string>::const_iterator file = header_files.begin();
2354 file != header_files.end();
2356 handle_file_entry(*file, result);
2376 const vector<string>& header_files)
2379 vector<string> root_dirs;
2381 if (!headers_root_dir.empty())
2382 root_dirs.push_back(headers_root_dir);
2400 vector<string> header_files;
2431 (
const std::vector<std::string>& abi_whitelist_paths)
2434 std::vector<std::string> whitelisted_names;
2435 for (std::vector<std::string>::const_iterator
2436 path_iter = abi_whitelist_paths.begin(),
2437 path_end = abi_whitelist_paths.end();
2438 path_iter != path_end;
2449 for (ini::config::sections_type::const_iterator
2450 section_iter = whitelist_sections.begin(),
2451 section_end = whitelist_sections.end();
2452 section_iter != section_end;
2455 std::string section_name = (*section_iter)->get_name();
2459 for (ini::config::properties_type::const_iterator
2460 prop_iter = (*section_iter)->get_properties().begin(),
2461 prop_end = (*section_iter)->get_properties().end();
2462 prop_iter != prop_end;
2467 if (prop->has_empty_value())
2469 const std::string& name = prop->get_name();
2471 whitelisted_names.push_back(name);
2478 if (!whitelisted_names.empty())
2481 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2482 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2483 whitelisted_names.end()),
2484 whitelisted_names.end());
2496 fn_suppr->set_label(
"whitelist");
2497 fn_suppr->set_symbol_name_not_regex_str(regex);
2498 fn_suppr->set_drops_artifact_from_ir(
true);
2499 result.push_back(fn_suppr);
2507 var_suppr->set_label(
"whitelist");
2508 var_suppr->set_symbol_name_not_regex_str(regex);
2509 var_suppr->set_drops_artifact_from_ir(
true);
2510 result.push_back(var_suppr);
2521 string default_system_suppr_path;
2523 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2525 default_system_suppr_path = s;
2527 if (default_system_suppr_path.empty())
2528 default_system_suppr_path =
2531 return default_system_suppr_path;
2540 string default_user_suppr_path;
2541 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2548 default_user_suppr_path = s;
2549 if (default_user_suppr_path.empty())
2550 default_user_suppr_path =
"~";
2551 default_user_suppr_path +=
"/.abignore";
2554 default_user_suppr_path = s;
2556 return default_user_suppr_path;
2570 string default_system_suppr_path =
2586 string default_user_suppr_path =
2607entry_of_file_with_name(
const FTSENT *entry,
2608 const string& fname,
2609 const string& root_dir)
2612 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2613 || entry->fts_info == FTS_ERR
2614 || entry->fts_info == FTS_NS)
2617 string fpath = ::basename(entry->fts_path);
2621 fpath = trim_leading_string(entry->fts_path, root_dir);
2640 const string& file_path_to_look_for,
2643 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2645 FTS *file_hierarchy = fts_open(paths,
2646 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2647 if (!file_hierarchy)
2650 string r = root_dir;
2655 while ((entry = fts_read(file_hierarchy)))
2657 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2659 result = entry->fts_path;
2660 fts_close(file_hierarchy);
2664 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2666 fts_set(file_hierarchy, entry, FTS_SKIP);
2671 fts_close(file_hierarchy);
2688 const string& file_path_to_look_for,
2691 if (root_dirs.empty())
2694 for (
const auto& root_dir : root_dirs)
2723 const vector<string>& deps_dirs,
2724 set<string>& dependencies)
2726 const vector<string>& set_of_needed = korpus.
get_needed();
2727 if (set_of_needed.empty())
2730 bool found_at_least_one_dependency =
false;
2731 for (
const auto& n :set_of_needed)
2734 if (dependencies.find(n) == dependencies.end()
2737 dependencies.insert(dependency);
2738 found_at_least_one_dependency =
true;
2742 return found_at_least_one_dependency;
2760 const vector<string>& binaries,
2761 const vector<string>& deps_dirs,
2764 vector<string> bins;
2766 for (
const auto& b : binaries)
2770 bins.push_back(bin);
2773 for (
const auto& b : bins)
2778 reader->initialize(b);
2780 corpus_sptr c = reader->read_corpus(stat);
2801 const vector<string>& deps_dirs,
2809 for (
const auto& dep: deps)
2814 reader->initialize(dep);
2816 corpus_sptr c = reader->read_corpus(stat);
2844 const corpus_sptr& korpus,
2845 const vector<string>& binaries,
2846 const vector<string>& bins_dirs)
2848 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2849 korpus->get_path()));
2850 result->add_corpus(korpus);
2873 const corpus_sptr& korpus,
2874 const vector<string>& deps_dirs)
2876 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2877 korpus->get_path()));
2878 result->add_corpus(korpus);
2906 vector<string>& suppr_paths,
2907 vector<string>& kabi_whitelist_paths,
2912 for (vector<string>::const_iterator i = suppr_paths.begin();
2913 i != suppr_paths.end();
2918 gen_suppr_spec_from_kernel_abi_whitelists(kabi_whitelist_paths);
2920 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2933is_vmlinux(
const FTSENT *entry)
2936 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2937 || entry->fts_info == FTS_ERR
2938 || entry->fts_info == FTS_NS)
2941 string fname = entry->fts_name;
2943 if (fname ==
"vmlinux")
2946 dir_name(entry->fts_path, dirname);
2963is_kernel_module(
const FTSENT *entry)
2966 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2967 || entry->fts_info == FTS_ERR
2968 || entry->fts_info == FTS_NS)
2971 string fname = entry->fts_name;
2987is_file(
const FTSENT *entry)
2990 && (entry->fts_info == FTS_F
2991 || entry->fts_info == FTS_SL));
3007find_vmlinux_and_module_paths(
const string& from,
3008 string &vmlinux_path,
3009 vector<string> &module_paths)
3011 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3013 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3014 if (!file_hierarchy)
3017 bool found_vmlinux = !vmlinux_path.empty();
3019 while ((entry = fts_read(file_hierarchy)))
3022 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3024 fts_set(file_hierarchy, entry, FTS_SKIP);
3028 if (!found_vmlinux && is_vmlinux(entry))
3030 vmlinux_path = entry->fts_path;
3031 found_vmlinux =
true;
3033 else if (is_kernel_module(entry))
3034 module_paths.push_back(entry->fts_path);
3037 fts_close(file_hierarchy);
3039 return found_vmlinux;
3050find_vmlinux_path(
const string& from,
3051 string &vmlinux_path)
3053 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3055 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3056 if (!file_hierarchy)
3059 bool found_vmlinux =
false;
3061 while ((entry = fts_read(file_hierarchy)))
3064 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3066 fts_set(file_hierarchy, entry, FTS_SKIP);
3070 if (!found_vmlinux && is_vmlinux(entry))
3072 vmlinux_path = entry->fts_path;
3073 found_vmlinux =
true;
3078 fts_close(file_hierarchy);
3080 return found_vmlinux;
3093 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
3094 FTS *file_hierarchy = fts_open(paths,
3095 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3096 if (!file_hierarchy)
3099 string r = root_dir;
3103 bool found_file =
false;
3105 while ((entry = fts_read(file_hierarchy)))
3108 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3110 fts_set(file_hierarchy, entry, FTS_SKIP);
3117 string path = entry->fts_path;
3119 dirs.push_back(path);
3122 fts_close(file_hierarchy);
3145 const string& debug_info_root_path,
3146 string& vmlinux_path,
3147 vector<string>& module_paths)
3160 string kernel_modules_root = dist_root;
3161 string debug_info_root;
3164 kernel_modules_root = dist_root +
"/lib/modules";
3165 debug_info_root = debug_info_root_path.empty()
3166 ? dist_root +
"/usr/lib/debug"
3167 : debug_info_root_path;
3171 debug_info_root.clear();
3179 find_vmlinux_and_module_paths(kernel_modules_root,
3184 || find_vmlinux_and_module_paths(debug_info_root,
3189 std::sort(module_paths.begin(), module_paths.end());
3205 string& vmlinux_path)
3216 string dist_root = from;
3218 dist_root +=
"/lib/modules";
3221 if (find_vmlinux_path(dist_root, vmlinux_path))
3241 string& vmlinux_path,
3242 vector<string>& module_paths)
3244 string debug_info_root_path;
3246 debug_info_root_path,
3289load_vmlinux_corpus(elf_based_reader_sptr rdr,
3290 corpus_group_sptr& group,
3291 const string& vmlinux,
3292 vector<string>& modules,
3294 vector<string>& di_roots,
3295 vector<string>& suppr_paths,
3296 vector<string>& kabi_wl_paths,
3303 rdr->options().do_log = verbose;
3307 std::cerr <<
"Loading stable lists:'";
3308 for (
auto s : kabi_wl_paths)
3309 std::cerr << s <<
",";
3310 std::cerr <<
"'...\n";
3313 load_generate_apply_suppressions(*rdr, suppr_paths,
3314 kabi_wl_paths, supprs);
3318 std::cerr <<
"loaded white list and generated suppr spec in: "
3324 rdr->corpus_group(group);
3327 std::cerr <<
"reading kernel binary '"
3328 << vmlinux <<
"' ...\n" << std::flush;
3332 rdr->read_and_add_corpus_to_group(*group, status);
3336 std::cerr << vmlinux
3337 <<
" reading DONE in:"
3340 if (group->is_empty())
3344 int total_nb_modules = modules.size();
3345 int cur_module_index = 1;
3346 for (vector<string>::const_iterator m = modules.begin();
3348 ++m, ++cur_module_index)
3351 std::cerr <<
"reading module '"
3354 <<
"/" << total_nb_modules
3355 <<
") ...\n" << std::flush;
3357 rdr->initialize(*m, di_roots,
3361 load_generate_apply_suppressions(*rdr, suppr_paths,
3362 kabi_wl_paths, supprs);
3364 rdr->corpus_group(group);
3367 rdr->read_and_add_corpus_to_group(*group, status);
3370 std::cerr <<
"Module reading DONE in: "
3371 << t <<
" for '" << *m
3372 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3378 std::cerr <<
"Total number of functions: "
3379 << group->get_functions().size() <<
"\n";
3380 std::cerr <<
"Total number of variables: "
3381 << group->get_variables().size() <<
"\n";
3424 const string debug_info_root,
3425 const string& vmlinux_path,
3426 vector<string>& suppr_paths,
3427 vector<string>& kabi_wl_paths,
3433 string vmlinux = vmlinux_path;
3434 corpus_group_sptr group;
3435 vector<string> modules;
3438 std::cerr <<
"Analysing kernel dist root '"
3440 <<
"' with vmlinux path: '"
3442 <<
"' ... \n" << std::flush;
3447 bool got_binary_paths =
3452 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3454 if (got_binary_paths)
3458 vector<string> di_roots;
3459 di_roots.push_back(di_root);
3463 if (requested_fe_kind & corpus::CTF_ORIGIN)
3466 di_roots.push_back(di_root_ctf);
3470 abigail::elf_based_reader_sptr reader =
3478 load_vmlinux_corpus(reader, group, vmlinux,
3479 modules, root, di_roots,
3480 suppr_paths, kabi_wl_paths,
3481 supprs, verbose, t, env);
3522elf_based_reader_sptr
3524 const vector<string>& debug_info_root_paths,
3527 bool show_all_types,
3528 bool linux_kernel_mode)
3530 elf_based_reader_sptr result;
3534 if (requested_fe_kind & corpus::CTF_ORIGIN)
3541 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3546 show_all_types, linux_kernel_mode);
3566 show_all_types, linux_kernel_mode);
3576 debug_info_root_paths,
3590struct xz_decompressor_type::priv
3592 std::istream& xz_istream;
3596 char inbuf[1024 * 100] = {};
3599 char outbuf[1024 * 100] = {};
3601 priv(std::istream& i)
3603 lzma(LZMA_STREAM_INIT)
3611xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
3612 : priv_(new priv(xz_istream))
3615 lzma_ret status = lzma_stream_decoder(&priv_->lzma,
3624 lzma_end(&priv_->lzma);
3635std::streambuf::int_type
3638 if (gptr() < egptr())
3642 priv_->xz_istream.read(priv_->inbuf,
sizeof(priv_->inbuf));
3643 size_t nr = priv_->xz_istream.gcount();
3649 priv_->lzma.avail_in = nr;
3650 priv_->lzma.next_in =
reinterpret_cast<uint8_t*
>(priv_->inbuf);
3653 if (priv_->lzma.avail_out || priv_->lzma.avail_in)
3658 priv_->lzma.avail_out =
sizeof(priv_->outbuf);
3659 priv_->lzma.next_out =
reinterpret_cast<uint8_t*
>(priv_->outbuf);
3664 lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
3665 if (result != LZMA_OK && result != LZMA_STREAM_END)
3670 std::ostringstream o;
3671 o <<
"LZMA decompression failed;"
3672 <<
" return code of lzma_code() is : "
3674 throw std::runtime_error(o.str());
3680 size_t nr_decompressed_bytes =
sizeof(priv_->outbuf) - priv_->lzma.avail_out;
3683 setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
3685 if (nr_decompressed_bytes > 0)
3691 result = lzma_code(&priv_->lzma, LZMA_FINISH);
3692 ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
3693 return traits_type::eof();
3720 std::vector<function_decl*>::const_iterator a_end,
3721 std::vector<function_decl*>::const_iterator b_begin,
3722 std::vector<function_decl*>::const_iterator b_end)
3723{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3737 std::vector<function_decl*>::const_iterator a_end,
3738 std::vector<function_decl*>::const_iterator b_begin,
3739 std::vector<function_decl*>::const_iterator b_end)
3741 std::vector<function_decl*>::const_iterator i;
3742 std::ostream& o = std::cerr;
3743 for (i = a_begin; i != a_end; ++i)
3744 o << (*i)->get_pretty_representation() <<
"\n";
3747 for (i = b_begin; i != b_end; ++i)
3748 o << (*i)->get_pretty_representation() <<
"\n";
3761 unsigned f1_index,
unsigned f2_index)
3766 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...