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;}
618static int ANONYMOUS_SUBRANGE_INTERNAL_NAME_LEN =
619 strlen(ANONYMOUS_SUBRANGE_INTERNAL_NAME);
626{
return ANONYMOUS_ENUM_INTERNAL_NAME;}
633{
return ANONYMOUS_SUBRANGE_INTERNAL_NAME;}
669 string::size_type l_pos1 = 0, r_pos1 = 0;
670 const string::size_type l_length = l.length(), r_length = r.length();
672 while (l_pos1 < l_length && r_pos1 < r_length)
674 string::size_type l_pos2 = l.find(
"::", l_pos1);
675 string::size_type r_pos2 = r.find(
"::", r_pos1);
676 if (l_pos2 == string::npos)
678 if (r_pos2 == string::npos)
681 if (l.compare(l_pos1, l_pos2 - l_pos1, r,
682 r_pos1, r_pos2 - r_pos1)
683 && (l.compare(l_pos1,
684 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
685 ANONYMOUS_STRUCT_INTERNAL_NAME)
687 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
688 ANONYMOUS_STRUCT_INTERNAL_NAME))
689 && (l.compare(l_pos1,
690 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
691 ANONYMOUS_UNION_INTERNAL_NAME)
693 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
694 ANONYMOUS_UNION_INTERNAL_NAME))
695 && (l.compare(l_pos1,
696 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
697 ANONYMOUS_ENUM_INTERNAL_NAME)
699 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
700 ANONYMOUS_ENUM_INTERNAL_NAME)))
703 l_pos1 = l_pos2 == l_length ? l_pos2 : l_pos2 + 2;
704 r_pos1 = r_pos2 == r_length ? r_pos2 : r_pos2 + 2;
707 return (l_pos1 == l_length) == (r_pos1 == r_length);
728 if (!get_stat(file_path, &st))
731 char *link_target_path = realpath(file_path.c_str(), NULL);
732 if (!link_target_path)
735 target_path = link_target_path;
736 free(link_target_path);
756 bool keep_separator_at_end)
764 char *p = strdup(path.c_str());
765 char *r = ::dirname(p);
768 if (keep_separator_at_end
769 &&
dir_name.length() < path.length())
792 char *p = strdup(path.c_str());
793 char *f = ::basename(p);
816 char *realp = realpath(path.c_str(), NULL);
833 memset(&st, 0,
sizeof (st));
837 stat_result = stat(dir_path.c_str(), &st);
838 if (stat_result == 0)
841 if (!S_ISDIR (st.st_mode))
847 cmd =
"mkdir -p " + dir_path;
849 if (system(cmd.c_str()))
888 if (!prog_name.empty())
889 out << prog_name <<
": ";
901check_file(
const string& path, ostream& out,
const string& prog_name)
905 emit_prefix(prog_name, out) <<
"file " << path <<
" does not exist\n";
911 emit_prefix(prog_name, out) << path <<
" is not a regular file\n";
929check_dir(
const string& path, ostream& out,
const string& prog_name)
933 emit_prefix(prog_name, out) <<
"path " << path <<
" does not exist\n";
939 emit_prefix(prog_name, out) << path <<
" is not a directory\n";
956 string::size_type str_len = str.length(), suffix_len = suffix.length();
958 if (str_len < suffix_len)
960 return str.compare(str_len - suffix_len, suffix_len, suffix) == 0;
979 string::size_type prefix_len = prefix.length();
980 if (prefix_len > str.length())
983 return str.compare(0, prefix.length(), prefix) == 0;
994 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1019 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1021 unsigned char c = *i;
1024 || (c >= 0x7F && c <= 0x9F))
1046 const string& delims,
1047 vector<string>& result)
1049 size_t current = 0, next;
1050 bool did_split =
false;
1055 while (current < input_string.size() && isspace(input_string[current]))
1058 if (current >= input_string.size())
1061 next = input_string.find_first_of(delims, current);
1062 if (next == string::npos)
1064 string s = input_string.substr(current);
1066 result.push_back(input_string.substr(current));
1067 did_split = (current != 0);
1070 string s = input_string.substr(current, next - current);
1073 result.push_back(input_string.substr(current, next - current));
1078 while (next != string::npos);
1096 const string& prefix,
1100 if (prefix.length() >= input_string.length())
1103 if (input_string.compare(0, prefix.length(), prefix) != 0)
1108 suffix = input_string.substr(prefix.length());
1125common_prefix(
const string& s1,
const string& s2,
string &result)
1127 if (s1.length() == 0 || s2.length() == 0)
1131 for (
size_t i = 0; i < s1.length() && i< s2.length(); ++i)
1137 return !result.empty();
1156 string prefix_candidate;
1157 bool found_prefix =
false;
1159 if (input_strings.size() == 1)
1161 if (
dir_name(input_strings.front(), prefix,
1168 for (vector<string>::const_iterator i = input_strings.begin();
1169 i != input_strings.end();
1173 if (prefix_candidate.empty())
1175 prefix_candidate = cur_str;
1180 if (common_prefix(prefix_candidate, cur_str, s))
1183 prefix_candidate = s;
1184 found_prefix =
true;
1190 prefix = prefix_candidate;
1203 string major, minor, revision, version_string, suffix;
1205 version_string = major +
"." + minor +
"." + revision + suffix;
1206 return version_string;
1215 string major, minor, version_string;
1217 version_string = major +
"." + minor;
1218 return version_string;
1247#define TMP_BUF_LEN 1024 + 1
1248 char tmp_buf[TMP_BUF_LEN];
1249 memset(tmp_buf, 0, TMP_BUF_LEN);
1251 while (fgets(tmp_buf, TMP_BUF_LEN, stream))
1253 lines.push_back(tmp_buf);
1254 memset(tmp_buf, 0, TMP_BUF_LEN);
1257 if (pclose(stream) == -1)
1278 const string& option,
1279 vector<string>& arguments)
1281 string s = input_str;
1287 s = s.substr(0, s.size() - 1);
1309 vector<string> query_output;
1315 + rpm_path +
" 2> /dev/null | grep .so",
1318 for (vector<string>::const_iterator line = query_output.begin();
1319 line != query_output.end();
1322 string dso = line->substr(0, line->find(
'('));
1325 provided_dsos.insert(dso);
1342 string::size_type start, end;
1343 for (start = 0; start < str.length(); ++start)
1344 if (!isspace(str[start]))
1347 for (end = str.length() - 1; end > 0; --end)
1348 if (!isspace(str[end]))
1351 result = str.substr(start, end - start + 1);
1363 if (str.erase(std::remove_if(str.begin(), str.end(), isspace),
1364 str.end()) == str.end())
1382 static std::regex re(
"([0-9]+)([uUlL])+");
1397 bool begin_pattern =
false, middle_pattern =
false, found_litteral =
false;
1398 for (string::iterator i = str.begin(); i < str.end(); ++i)
1401 begin_pattern =
true;
1405 && (*i ==
'u' || *i ==
'U' || *i ==
'l' || *i ==
'L'))
1406 middle_pattern =
true;
1411 found_litteral =
true;
1420 std::regex& re = get_litteral_regex();
1421 str = std::regex_replace(str, re,
"$1");
1461 vector<char**>& char_star_stars)
1463 for (vector<char*>::const_iterator i = char_stars.begin();
1464 i != char_stars.end();
1466 char_star_stars.push_back(
const_cast<char**
>(&*i));
1470struct temp_file::priv
1472 char* path_template_;
1474 shared_ptr<std::fstream> fstream_;
1478 const char* templat =
"/tmp/libabigail-tmp-file-XXXXXX";
1479 int s = strlen(templat);
1480 path_template_ =
new char[s + 1];
1481 memset(path_template_, 0, s + 1);
1482 memcpy(path_template_, templat, s);
1484 fd_ = mkstemp(path_template_);
1488 fstream_.reset(
new std::fstream(path_template_,
1496 if (fd_ && fd_ != -1)
1500 remove(path_template_);
1502 delete [] path_template_;
1509temp_file::temp_file()
1518temp_file::is_good()
const
1519{
return priv_->fstream_->good();}
1526temp_file::get_path()
const
1529 return priv_->path_template_;
1543temp_file::get_stream()
1546 return *priv_->fstream_;
1557 if (result->is_good())
1569 static __thread
bool initialized =
false;
1586 std::ostringstream o;
1601 repr =
"unknown file type";
1604 repr =
"native binary instrumentation file type";
1607 repr =
"ELF file type";
1610 repr =
"archive file type";
1612 case FILE_TYPE_XML_CORPUS:
1613 repr =
"native XML corpus file type";
1615 case FILE_TYPE_XML_CORPUS_GROUP:
1616 repr =
"native XML corpus group file type";
1619 repr =
"RPM file type";
1622 repr =
"SRPM file type";
1625 repr =
"Debian binary file type";
1628 repr =
"Directory type";
1631 repr =
"GNU tar archive type";
1634 repr =
"XZ compressed file";
1649 COMPRESSION_KIND_UNKNOWN,
1667 return COMPRESSION_KIND_UNKNOWN;
1678 const unsigned BUF_LEN = 264;
1679 const unsigned NB_BYTES_TO_READ = 263;
1681 unsigned char buf[BUF_LEN];
1682 memset(buf, 0, BUF_LEN);
1684 std::streampos initial_pos = in.tellg();
1685 in.read(
reinterpret_cast<char*
>(buf), NB_BYTES_TO_READ);
1686 in.seekg(initial_pos);
1688 if (in.gcount() < 4 || in.bad())
1699 if (in.gcount() >= 6
1716 if (strstr(
reinterpret_cast<char*
>(buf),
"debian-binary"))
1753 return FILE_TYPE_XML_CORPUS_GROUP;
1767 return FILE_TYPE_XML_CORPUS;
1771 if ((
unsigned char) buf[0] == 0xed
1772 && (
unsigned char) buf[1] == 0xab
1773 && (
unsigned char) buf[2] == 0xee
1774 && (
unsigned char) buf[3] == 0xdb)
1778 else if (buf[7] == 0x01)
1809static shared_ptr<std::streambuf>
1810get_decompressed_streambuf(std::istream& compressed_input,
1813 shared_ptr<std::streambuf> result;
1817 case COMPRESSION_KIND_UNKNOWN:
1822 shared_ptr<std::streambuf> r(
new xz_decompressor_type(compressed_input));
1864 shared_ptr<std::streambuf> decompressor_streambuf;
1876 if (is_compressed_file_type(r) && !look_through_compression)
1881 shared_ptr<ifstream> input_fstream(
new ifstream(file_path.c_str(),
1883 shared_ptr<istream> input_stream = input_fstream;
1885 if (compr_kind != COMPRESSION_KIND_UNKNOWN)
1886 decompressor_streambuf = get_decompressed_streambuf(*input_stream,
1889 if (decompressor_streambuf)
1890 input_stream.reset(
new istream(decompressor_streambuf.get()));
1894 input_fstream->close();
1896 if (!decompressor_streambuf)
1901 compr_kind = is_compressed_file_type(r);
1904 if (!look_through_compression)
1922 }
while (!decompressor_streambuf && compr_kind);
1939 if (str.empty() || str[0] ==
'_')
1942 string::size_type str_len = str.length(), i = 0 ;
1944 for (; i < str_len; ++i)
1953 name = str.substr(0, i);
1969 if (str.empty() || str[0] ==
'-')
1972 string::size_type str_len = str.length(), i = 0;
1973 string::value_type c;
1975 for (; i < str_len; ++i)
1978 string::size_type next_index = i + 1;
1979 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
1986 name = str.substr(0, i);
2009 string::size_type str_len = str.length(), i = 0;
2010 string::value_type c;
2011 string::size_type last_dot_index = 0, dot_before_last_index = 0;
2013 for (i = str_len - 1; i > 0; --i)
2026 for(--i; i > 0; --i)
2031 dot_before_last_index = i;
2039 arch = str.substr(dot_before_last_index + 1,
2040 last_dot_index - dot_before_last_index - 1);
2056 bool result =
false;
2067 string package_name;
2086 vector<string> query_output;
2092 + rpm_path +
" 2> /dev/null",
2095 for (
auto& line : query_output)
2116 bool result =
false;
2117 string package_name;
2123 result = (package_name ==
"kernel-debuginfo");
2139struct malloced_char_star_deleter
2142 operator()(
char* ptr)
2157std::shared_ptr<char>
2160 using std::shared_ptr;
2162 shared_ptr<char> result;
2164 if (p && p[0] !=
'/')
2166 shared_ptr<char> pwd(get_current_dir_name(),
2167 malloced_char_star_deleter());
2168 string s = string(pwd.get()) +
"/" + p;
2169 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
2172 result.reset(strdup(p), malloced_char_star_deleter());
2190 if (!p.empty() && p[0] !=
'/')
2192 shared_ptr<char> pwd(get_current_dir_name(),
2193 malloced_char_star_deleter());
2194 result = string(pwd.get()) +
"/" + p;
2196 else if (!p.empty())
2218 if (p && p[0] !=
'/')
2220 char* pwd = get_current_dir_name();
2221 string s = string(pwd) +
"/" + p;
2223 result = strdup(s.c_str());
2247handle_file_entry(
const string& file_path,
2258 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2259 suppr->set_is_artificial(
true);
2265 suppr->get_source_locations_to_keep().insert(file_path);
2281handle_fts_entry(
const FTSENT *entry,
2285 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2286 || entry->fts_info == FTS_ERR
2287 || entry->fts_info == FTS_NS)
2290 string fname = entry->fts_name;
2296 handle_file_entry (fname, suppr);
2314gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2317 if (!headers_root_dir.empty())
2319 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2321 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2324 while ((entry = fts_read(file_hierarchy)))
2325 handle_fts_entry(entry, result);
2326 fts_close(file_hierarchy);
2347 const vector<string>& header_files)
2351 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2352 root_dir != headers_root_dirs.end();
2354 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2356 for (vector<string>::const_iterator file = header_files.begin();
2357 file != header_files.end();
2359 handle_file_entry(*file, result);
2379 const vector<string>& header_files)
2382 vector<string> root_dirs;
2384 if (!headers_root_dir.empty())
2385 root_dirs.push_back(headers_root_dir);
2403 vector<string> header_files;
2434 (
const std::vector<std::string>& abi_whitelist_paths)
2437 std::vector<std::string> whitelisted_names;
2438 for (std::vector<std::string>::const_iterator
2439 path_iter = abi_whitelist_paths.begin(),
2440 path_end = abi_whitelist_paths.end();
2441 path_iter != path_end;
2452 for (ini::config::sections_type::const_iterator
2453 section_iter = whitelist_sections.begin(),
2454 section_end = whitelist_sections.end();
2455 section_iter != section_end;
2458 std::string section_name = (*section_iter)->get_name();
2462 for (ini::config::properties_type::const_iterator
2463 prop_iter = (*section_iter)->get_properties().begin(),
2464 prop_end = (*section_iter)->get_properties().end();
2465 prop_iter != prop_end;
2470 if (prop->has_empty_value())
2472 const std::string& name = prop->get_name();
2474 whitelisted_names.push_back(name);
2481 if (!whitelisted_names.empty())
2484 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2485 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2486 whitelisted_names.end()),
2487 whitelisted_names.end());
2499 fn_suppr->set_label(
"whitelist");
2500 fn_suppr->set_symbol_name_not_regex_str(regex);
2501 fn_suppr->set_drops_artifact_from_ir(
true);
2502 result.push_back(fn_suppr);
2510 var_suppr->set_label(
"whitelist");
2511 var_suppr->set_symbol_name_not_regex_str(regex);
2512 var_suppr->set_drops_artifact_from_ir(
true);
2513 result.push_back(var_suppr);
2524 string default_system_suppr_path;
2526 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2528 default_system_suppr_path = s;
2530 if (default_system_suppr_path.empty())
2531 default_system_suppr_path =
2534 return default_system_suppr_path;
2543 string default_user_suppr_path;
2544 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2551 default_user_suppr_path = s;
2552 if (default_user_suppr_path.empty())
2553 default_user_suppr_path =
"~";
2554 default_user_suppr_path +=
"/.abignore";
2557 default_user_suppr_path = s;
2559 return default_user_suppr_path;
2573 string default_system_suppr_path =
2589 string default_user_suppr_path =
2610entry_of_file_with_name(
const FTSENT *entry,
2611 const string& fname,
2612 const string& root_dir)
2615 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2616 || entry->fts_info == FTS_ERR
2617 || entry->fts_info == FTS_NS)
2620 string fpath = ::basename(entry->fts_path);
2643 const string& file_path_to_look_for,
2646 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2648 FTS *file_hierarchy = fts_open(paths,
2649 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2650 if (!file_hierarchy)
2653 string r = root_dir;
2658 while ((entry = fts_read(file_hierarchy)))
2660 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2662 result = entry->fts_path;
2666 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2668 fts_set(file_hierarchy, entry, FTS_SKIP);
2673 fts_close(file_hierarchy);
2690 const string& file_path_to_look_for,
2693 if (root_dirs.empty())
2696 for (
const auto& root_dir : root_dirs)
2725 const vector<string>& deps_dirs,
2726 set<string>& dependencies)
2728 const vector<string>& set_of_needed = korpus.
get_needed();
2729 if (set_of_needed.empty())
2732 bool found_at_least_one_dependency =
false;
2733 for (
const auto& n :set_of_needed)
2736 if (dependencies.find(n) == dependencies.end()
2739 dependencies.insert(dependency);
2740 found_at_least_one_dependency =
true;
2744 return found_at_least_one_dependency;
2762 const vector<string>& binaries,
2763 const vector<string>& deps_dirs,
2766 vector<string> bins;
2768 for (
const auto& b : binaries)
2772 bins.push_back(bin);
2775 for (
const auto& b : bins)
2780 reader->initialize(b);
2782 corpus_sptr c = reader->read_corpus(stat);
2803 const vector<string>& deps_dirs,
2811 for (
const auto& dep: deps)
2816 reader->initialize(dep);
2818 corpus_sptr c = reader->read_corpus(stat);
2846 const corpus_sptr& korpus,
2847 const vector<string>& binaries,
2848 const vector<string>& bins_dirs)
2850 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2851 korpus->get_path()));
2852 result->add_corpus(korpus);
2875 const corpus_sptr& korpus,
2876 const vector<string>& deps_dirs)
2878 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2879 korpus->get_path()));
2880 result->add_corpus(korpus);
2908 vector<string>& suppr_paths,
2909 vector<string>& kabi_whitelist_paths,
2914 for (vector<string>::const_iterator i = suppr_paths.begin();
2915 i != suppr_paths.end();
2922 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2935is_vmlinux(
const FTSENT *entry)
2938 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2939 || entry->fts_info == FTS_ERR
2940 || entry->fts_info == FTS_NS)
2943 string fname = entry->fts_name;
2945 if (fname ==
"vmlinux")
2948 dir_name(entry->fts_path, dirname);
2965is_kernel_module(
const FTSENT *entry)
2968 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2969 || entry->fts_info == FTS_ERR
2970 || entry->fts_info == FTS_NS)
2973 string fname = entry->fts_name;
2989is_file(
const FTSENT *entry)
2992 && (entry->fts_info == FTS_F
2993 || entry->fts_info == FTS_SL));
3009find_vmlinux_and_module_paths(
const string& from,
3010 string &vmlinux_path,
3011 vector<string> &module_paths)
3013 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3015 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3016 if (!file_hierarchy)
3019 bool found_vmlinux = !vmlinux_path.empty();
3021 while ((entry = fts_read(file_hierarchy)))
3024 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3026 fts_set(file_hierarchy, entry, FTS_SKIP);
3030 if (!found_vmlinux && is_vmlinux(entry))
3032 vmlinux_path = entry->fts_path;
3033 found_vmlinux =
true;
3035 else if (is_kernel_module(entry))
3036 module_paths.push_back(entry->fts_path);
3039 fts_close(file_hierarchy);
3041 return found_vmlinux;
3052find_vmlinux_path(
const string& from,
3053 string &vmlinux_path)
3055 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3057 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3058 if (!file_hierarchy)
3061 bool found_vmlinux =
false;
3063 while ((entry = fts_read(file_hierarchy)))
3066 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3068 fts_set(file_hierarchy, entry, FTS_SKIP);
3072 if (!found_vmlinux && is_vmlinux(entry))
3074 vmlinux_path = entry->fts_path;
3075 found_vmlinux =
true;
3080 fts_close(file_hierarchy);
3082 return found_vmlinux;
3095 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
3096 FTS *file_hierarchy = fts_open(paths,
3097 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3098 if (!file_hierarchy)
3101 string r = root_dir;
3105 bool found_file =
false;
3107 while ((entry = fts_read(file_hierarchy)))
3110 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3112 fts_set(file_hierarchy, entry, FTS_SKIP);
3119 string path = entry->fts_path;
3121 dirs.push_back(path);
3124 fts_close(file_hierarchy);
3147 const string& debug_info_root_path,
3148 string& vmlinux_path,
3149 vector<string>& module_paths)
3162 string kernel_modules_root = dist_root;
3163 string debug_info_root;
3166 kernel_modules_root = dist_root +
"/lib/modules";
3167 debug_info_root = debug_info_root_path.empty()
3168 ? dist_root +
"/usr/lib/debug"
3169 : debug_info_root_path;
3173 debug_info_root.clear();
3181 find_vmlinux_and_module_paths(kernel_modules_root,
3186 || find_vmlinux_and_module_paths(debug_info_root,
3191 std::sort(module_paths.begin(), module_paths.end());
3207 string& vmlinux_path)
3218 string dist_root = from;
3220 dist_root +=
"/lib/modules";
3223 if (find_vmlinux_path(dist_root, vmlinux_path))
3243 string& vmlinux_path,
3244 vector<string>& module_paths)
3246 string debug_info_root_path;
3248 debug_info_root_path,
3291load_vmlinux_corpus(elf_based_reader_sptr rdr,
3292 corpus_group_sptr& group,
3293 const string& vmlinux,
3294 vector<string>& modules,
3296 vector<string>& di_roots,
3297 vector<string>& suppr_paths,
3298 vector<string>& kabi_wl_paths,
3305 rdr->options().do_log = verbose;
3309 std::cerr <<
"Loading stable lists:'";
3310 for (
auto s : kabi_wl_paths)
3311 std::cerr << s <<
",";
3312 std::cerr <<
"'...\n";
3315 load_generate_apply_suppressions(*rdr, suppr_paths,
3316 kabi_wl_paths, supprs);
3320 std::cerr <<
"loaded white list and generated suppr spec in: "
3326 rdr->corpus_group(group);
3329 std::cerr <<
"reading kernel binary '"
3330 << vmlinux <<
"' ...\n" << std::flush;
3334 rdr->read_and_add_corpus_to_group(*group, status);
3338 std::cerr << vmlinux
3339 <<
" reading DONE in:"
3342 if (group->is_empty())
3346 int total_nb_modules = modules.size();
3347 int cur_module_index = 1;
3348 for (vector<string>::const_iterator m = modules.begin();
3350 ++m, ++cur_module_index)
3353 std::cerr <<
"reading module '"
3356 <<
"/" << total_nb_modules
3357 <<
") ...\n" << std::flush;
3359 rdr->initialize(*m, di_roots,
3363 load_generate_apply_suppressions(*rdr, suppr_paths,
3364 kabi_wl_paths, supprs);
3366 rdr->corpus_group(group);
3369 rdr->read_and_add_corpus_to_group(*group, status);
3372 std::cerr <<
"Module reading DONE in: "
3373 << t <<
" for '" << *m
3374 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3380 std::cerr <<
"Total number of functions: "
3381 << group->get_functions().size() <<
"\n";
3382 std::cerr <<
"Total number of variables: "
3383 << group->get_variables().size() <<
"\n";
3426 const string debug_info_root,
3427 const string& vmlinux_path,
3428 vector<string>& suppr_paths,
3429 vector<string>& kabi_wl_paths,
3435 string vmlinux = vmlinux_path;
3436 corpus_group_sptr group;
3437 vector<string> modules;
3440 std::cerr <<
"Analysing kernel dist root '"
3442 <<
"' with vmlinux path: '"
3444 <<
"' ... \n" << std::flush;
3449 bool got_binary_paths =
3454 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3456 if (got_binary_paths)
3460 vector<string> di_roots;
3461 di_roots.push_back(di_root);
3465 if (requested_fe_kind & corpus::CTF_ORIGIN)
3468 di_roots.push_back(di_root_ctf);
3472 abigail::elf_based_reader_sptr reader =
3480 load_vmlinux_corpus(reader, group, vmlinux,
3481 modules, root, di_roots,
3482 suppr_paths, kabi_wl_paths,
3483 supprs, verbose, t, env);
3524elf_based_reader_sptr
3526 const vector<string>& debug_info_root_paths,
3529 bool show_all_types,
3530 bool linux_kernel_mode)
3532 elf_based_reader_sptr result;
3536 if (requested_fe_kind & corpus::CTF_ORIGIN)
3543 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3548 show_all_types, linux_kernel_mode);
3568 show_all_types, linux_kernel_mode);
3578 debug_info_root_paths,
3592struct xz_decompressor_type::priv
3594 std::istream& xz_istream;
3598 char inbuf[1024 * 100] = {};
3601 char outbuf[1024 * 100] = {};
3603 priv(std::istream& i)
3605 lzma(LZMA_STREAM_INIT)
3613xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
3614 : priv_(new priv(xz_istream))
3617 lzma_ret status = lzma_stream_decoder(&priv_->lzma,
3626 lzma_end(&priv_->lzma);
3637std::streambuf::int_type
3640 if (gptr() < egptr())
3644 priv_->xz_istream.read(priv_->inbuf,
sizeof(priv_->inbuf));
3645 size_t nr = priv_->xz_istream.gcount();
3651 priv_->lzma.avail_in = nr;
3652 priv_->lzma.next_in =
reinterpret_cast<uint8_t*
>(priv_->inbuf);
3655 if (priv_->lzma.avail_out || priv_->lzma.avail_in)
3660 priv_->lzma.avail_out =
sizeof(priv_->outbuf);
3661 priv_->lzma.next_out =
reinterpret_cast<uint8_t*
>(priv_->outbuf);
3666 lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
3667 if (result != LZMA_OK && result != LZMA_STREAM_END)
3672 std::ostringstream o;
3673 o <<
"LZMA decompression failed;"
3674 <<
" return code of lzma_code() is : "
3676 throw std::runtime_error(o.str());
3682 size_t nr_decompressed_bytes =
sizeof(priv_->outbuf) - priv_->lzma.avail_out;
3685 setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
3687 if (nr_decompressed_bytes > 0)
3693 result = lzma_code(&priv_->lzma, LZMA_FINISH);
3694 ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
3695 return traits_type::eof();
3722 std::vector<function_decl*>::const_iterator a_end,
3723 std::vector<function_decl*>::const_iterator b_begin,
3724 std::vector<function_decl*>::const_iterator b_end)
3725{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3739 std::vector<function_decl*>::const_iterator a_end,
3740 std::vector<function_decl*>::const_iterator b_begin,
3741 std::vector<function_decl*>::const_iterator b_end)
3743 std::vector<function_decl*>::const_iterator i;
3744 std::ostream& o = std::cerr;
3745 for (i = a_begin; i != a_end; ++i)
3746 o << (*i)->get_pretty_representation() <<
"\n";
3749 for (i = b_begin; i != b_end; ++i)
3750 o << (*i)->get_pretty_representation() <<
"\n";
3763 unsigned f1_index,
unsigned f2_index)
3768 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.
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...
std::ostream & operator<<(std::ostream &o, const interned_string &s)
Streaming operator.