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"
60ABG_BEGIN_EXPORT_DECLARATIONS
66ABG_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<char**>& debug_info_root_paths)
471 debug_info_root_paths,
500 const vector<char**>& 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<char**>& 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));
1860 shared_ptr<std::streambuf> decompressor_streambuf;
1871 shared_ptr<ifstream> input_fstream(
new ifstream(file_path.c_str(),
1873 shared_ptr<istream> input_stream = input_fstream;
1875 if (compr_kind != COMPRESSION_KIND_UNKNOWN)
1876 decompressor_streambuf = get_decompressed_streambuf(*input_stream,
1879 if (decompressor_streambuf)
1880 input_stream.reset(
new istream(decompressor_streambuf.get()));
1884 input_fstream->close();
1886 if (!decompressor_streambuf)
1891 compr_kind = is_compressed_file_type(r);
1907 }
while (!decompressor_streambuf && compr_kind);
1924 if (str.empty() || str[0] ==
'_')
1927 string::size_type str_len = str.length(), i = 0 ;
1929 for (; i < str_len; ++i)
1938 name = str.substr(0, i);
1954 if (str.empty() || str[0] ==
'-')
1957 string::size_type str_len = str.length(), i = 0;
1958 string::value_type c;
1960 for (; i < str_len; ++i)
1963 string::size_type next_index = i + 1;
1964 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
1971 name = str.substr(0, i);
1994 string::size_type str_len = str.length(), i = 0;
1995 string::value_type c;
1996 string::size_type last_dot_index = 0, dot_before_last_index = 0;
1998 for (i = str_len - 1; i > 0; --i)
2011 for(--i; i > 0; --i)
2016 dot_before_last_index = i;
2024 arch = str.substr(dot_before_last_index + 1,
2025 last_dot_index - dot_before_last_index - 1);
2041 bool result =
false;
2052 string package_name;
2071 vector<string> query_output;
2077 + rpm_path +
" 2> /dev/null",
2080 for (
auto& line : query_output)
2101 bool result =
false;
2102 string package_name;
2108 result = (package_name ==
"kernel-debuginfo");
2124struct malloced_char_star_deleter
2127 operator()(
char* ptr)
2142std::shared_ptr<char>
2145 using std::shared_ptr;
2147 shared_ptr<char> result;
2149 if (p && p[0] !=
'/')
2151 shared_ptr<char> pwd(get_current_dir_name(),
2152 malloced_char_star_deleter());
2153 string s = string(pwd.get()) +
"/" + p;
2154 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
2157 result.reset(strdup(p), malloced_char_star_deleter());
2178 if (p && p[0] !=
'/')
2180 char* pwd = get_current_dir_name();
2181 string s = string(pwd) +
"/" + p;
2183 result = strdup(s.c_str());
2207handle_file_entry(
const string& file_path,
2218 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2219 suppr->set_is_artificial(
true);
2225 suppr->get_source_locations_to_keep().insert(file_path);
2241handle_fts_entry(
const FTSENT *entry,
2245 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2246 || entry->fts_info == FTS_ERR
2247 || entry->fts_info == FTS_NS)
2250 string fname = entry->fts_name;
2256 handle_file_entry (fname, suppr);
2274gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2277 if (!headers_root_dir.empty())
2279 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2281 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2284 while ((entry = fts_read(file_hierarchy)))
2285 handle_fts_entry(entry, result);
2286 fts_close(file_hierarchy);
2307 const vector<string>& header_files)
2311 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2312 root_dir != headers_root_dirs.end();
2314 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2316 for (vector<string>::const_iterator file = header_files.begin();
2317 file != header_files.end();
2319 handle_file_entry(*file, result);
2339 const vector<string>& header_files)
2342 vector<string> root_dirs;
2344 if (!headers_root_dir.empty())
2345 root_dirs.push_back(headers_root_dir);
2363 vector<string> header_files;
2394 (
const std::vector<std::string>& abi_whitelist_paths)
2397 std::vector<std::string> whitelisted_names;
2398 for (std::vector<std::string>::const_iterator
2399 path_iter = abi_whitelist_paths.begin(),
2400 path_end = abi_whitelist_paths.end();
2401 path_iter != path_end;
2412 for (ini::config::sections_type::const_iterator
2413 section_iter = whitelist_sections.begin(),
2414 section_end = whitelist_sections.end();
2415 section_iter != section_end;
2418 std::string section_name = (*section_iter)->get_name();
2422 for (ini::config::properties_type::const_iterator
2423 prop_iter = (*section_iter)->get_properties().begin(),
2424 prop_end = (*section_iter)->get_properties().end();
2425 prop_iter != prop_end;
2430 if (prop->has_empty_value())
2432 const std::string& name = prop->get_name();
2434 whitelisted_names.push_back(name);
2441 if (!whitelisted_names.empty())
2444 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2445 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2446 whitelisted_names.end()),
2447 whitelisted_names.end());
2459 fn_suppr->set_label(
"whitelist");
2460 fn_suppr->set_symbol_name_not_regex_str(regex);
2461 fn_suppr->set_drops_artifact_from_ir(
true);
2462 result.push_back(fn_suppr);
2470 var_suppr->set_label(
"whitelist");
2471 var_suppr->set_symbol_name_not_regex_str(regex);
2472 var_suppr->set_drops_artifact_from_ir(
true);
2473 result.push_back(var_suppr);
2484 string default_system_suppr_path;
2486 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2488 default_system_suppr_path = s;
2490 if (default_system_suppr_path.empty())
2491 default_system_suppr_path =
2494 return default_system_suppr_path;
2503 string default_user_suppr_path;
2504 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2511 default_user_suppr_path = s;
2512 if (default_user_suppr_path.empty())
2513 default_user_suppr_path =
"~";
2514 default_user_suppr_path +=
"/.abignore";
2517 default_user_suppr_path = s;
2519 return default_user_suppr_path;
2533 string default_system_suppr_path =
2549 string default_user_suppr_path =
2570entry_of_file_with_name(
const FTSENT *entry,
2571 const string& fname,
2572 const string& root_dir)
2575 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2576 || entry->fts_info == FTS_ERR
2577 || entry->fts_info == FTS_NS)
2580 string fpath = ::basename(entry->fts_path);
2603 const string& file_path_to_look_for,
2606 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2608 FTS *file_hierarchy = fts_open(paths,
2609 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2610 if (!file_hierarchy)
2613 string r = root_dir;
2618 while ((entry = fts_read(file_hierarchy)))
2620 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2622 result = entry->fts_path;
2626 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2628 fts_set(file_hierarchy, entry, FTS_SKIP);
2633 fts_close(file_hierarchy);
2650 const string& file_path_to_look_for,
2653 if (root_dirs.empty())
2656 for (
const auto& root_dir : root_dirs)
2685 const vector<string>& deps_dirs,
2686 set<string>& dependencies)
2688 const vector<string>& set_of_needed = korpus.
get_needed();
2689 if (set_of_needed.empty())
2692 bool found_at_least_one_dependency =
false;
2693 for (
const auto& n :set_of_needed)
2696 if (dependencies.find(n) == dependencies.end()
2699 dependencies.insert(dependency);
2700 found_at_least_one_dependency =
true;
2704 return found_at_least_one_dependency;
2722 const vector<string>& binaries,
2723 const vector<string>& deps_dirs,
2726 vector<string> bins;
2728 for (
const auto& b : binaries)
2732 bins.push_back(bin);
2735 for (
const auto& b : bins)
2740 reader->initialize(b);
2742 corpus_sptr c = reader->read_corpus(stat);
2763 const vector<string>& deps_dirs,
2771 for (
const auto& dep: deps)
2776 reader->initialize(dep);
2778 corpus_sptr c = reader->read_corpus(stat);
2806 const corpus_sptr& korpus,
2807 const vector<string>& binaries,
2808 const vector<string>& bins_dirs)
2810 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2811 korpus->get_path()));
2812 result->add_corpus(korpus);
2835 const corpus_sptr& korpus,
2836 const vector<string>& deps_dirs)
2838 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2839 korpus->get_path()));
2840 result->add_corpus(korpus);
2868 vector<string>& suppr_paths,
2869 vector<string>& kabi_whitelist_paths,
2874 for (vector<string>::const_iterator i = suppr_paths.begin();
2875 i != suppr_paths.end();
2882 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2895is_vmlinux(
const FTSENT *entry)
2898 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2899 || entry->fts_info == FTS_ERR
2900 || entry->fts_info == FTS_NS)
2903 string fname = entry->fts_name;
2905 if (fname ==
"vmlinux")
2908 dir_name(entry->fts_path, dirname);
2925is_kernel_module(
const FTSENT *entry)
2928 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2929 || entry->fts_info == FTS_ERR
2930 || entry->fts_info == FTS_NS)
2933 string fname = entry->fts_name;
2955find_vmlinux_and_module_paths(
const string& from,
2956 string &vmlinux_path,
2957 vector<string> &module_paths)
2959 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2961 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2962 if (!file_hierarchy)
2965 bool found_vmlinux = !vmlinux_path.empty();
2967 while ((entry = fts_read(file_hierarchy)))
2970 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2972 fts_set(file_hierarchy, entry, FTS_SKIP);
2976 if (!found_vmlinux && is_vmlinux(entry))
2978 vmlinux_path = entry->fts_path;
2979 found_vmlinux =
true;
2981 else if (is_kernel_module(entry))
2982 module_paths.push_back(entry->fts_path);
2985 fts_close(file_hierarchy);
2987 return found_vmlinux;
2998find_vmlinux_path(
const string& from,
2999 string &vmlinux_path)
3001 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
3003 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
3004 if (!file_hierarchy)
3007 bool found_vmlinux =
false;
3009 while ((entry = fts_read(file_hierarchy)))
3012 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
3014 fts_set(file_hierarchy, entry, FTS_SKIP);
3018 if (!found_vmlinux && is_vmlinux(entry))
3020 vmlinux_path = entry->fts_path;
3021 found_vmlinux =
true;
3026 fts_close(file_hierarchy);
3028 return found_vmlinux;
3049 const string& debug_info_root_path,
3050 string& vmlinux_path,
3051 vector<string>& module_paths)
3064 string kernel_modules_root = dist_root;
3065 string debug_info_root;
3068 kernel_modules_root = dist_root +
"/lib/modules";
3069 debug_info_root = debug_info_root_path.empty()
3070 ? dist_root +
"/usr/lib/debug"
3071 : debug_info_root_path;
3075 debug_info_root.clear();
3083 find_vmlinux_and_module_paths(kernel_modules_root,
3088 || find_vmlinux_and_module_paths(debug_info_root,
3093 std::sort(module_paths.begin(), module_paths.end());
3109 string& vmlinux_path)
3120 string dist_root = from;
3122 dist_root +=
"/lib/modules";
3125 if (find_vmlinux_path(dist_root, vmlinux_path))
3145 string& vmlinux_path,
3146 vector<string>& module_paths)
3148 string debug_info_root_path;
3150 debug_info_root_path,
3193load_vmlinux_corpus(elf_based_reader_sptr rdr,
3194 corpus_group_sptr& group,
3195 const string& vmlinux,
3196 vector<string>& modules,
3198 vector<char**>& di_roots,
3199 vector<string>& suppr_paths,
3200 vector<string>& kabi_wl_paths,
3207 rdr->options().do_log = verbose;
3211 std::cerr <<
"Loading stable lists:'";
3212 for (
auto s : kabi_wl_paths)
3213 std::cerr << s <<
",";
3214 std::cerr <<
"'...\n";
3217 load_generate_apply_suppressions(*rdr, suppr_paths,
3218 kabi_wl_paths, supprs);
3222 std::cerr <<
"loaded white list and generated suppr spec in: "
3228 rdr->corpus_group(group);
3231 std::cerr <<
"reading kernel binary '"
3232 << vmlinux <<
"' ...\n" << std::flush;
3236 rdr->read_and_add_corpus_to_group(*group, status);
3240 std::cerr << vmlinux
3241 <<
" reading DONE in:"
3244 if (group->is_empty())
3248 int total_nb_modules = modules.size();
3249 int cur_module_index = 1;
3250 for (vector<string>::const_iterator m = modules.begin();
3252 ++m, ++cur_module_index)
3255 std::cerr <<
"reading module '"
3258 <<
"/" << total_nb_modules
3259 <<
") ...\n" << std::flush;
3261 rdr->initialize(*m, di_roots,
3265 load_generate_apply_suppressions(*rdr, suppr_paths,
3266 kabi_wl_paths, supprs);
3268 rdr->corpus_group(group);
3271 rdr->read_and_add_corpus_to_group(*group, status);
3274 std::cerr <<
"Module reading DONE in: "
3275 << t <<
" for '" << *m
3276 <<
"' (" << cur_module_index <<
"/" << total_nb_modules <<
")"
3282 std::cerr <<
"Total number of functions: "
3283 << group->get_functions().size() <<
"\n";
3284 std::cerr <<
"Total number of variables: "
3285 << group->get_variables().size() <<
"\n";
3328 const string debug_info_root,
3329 const string& vmlinux_path,
3330 vector<string>& suppr_paths,
3331 vector<string>& kabi_wl_paths,
3337 string vmlinux = vmlinux_path;
3338 corpus_group_sptr group;
3339 vector<string> modules;
3342 std::cerr <<
"Analysing kernel dist root '"
3344 <<
"' with vmlinux path: '"
3346 <<
"' ... \n" << std::flush;
3351 bool got_binary_paths =
3356 std::cerr <<
"Kernel tree binary paths analysis DONE in: " << t <<
"\n";
3358 if (got_binary_paths)
3360 shared_ptr<char> di_root =
3362 char *di_root_ptr = di_root.get();
3363 vector<char**> di_roots;
3364 di_roots.push_back(&di_root_ptr);
3367 shared_ptr<char> di_root_ctf;
3368 char *di_root_ctf_ptr;
3369 if (requested_fe_kind & corpus::CTF_ORIGIN)
3372 di_root_ctf_ptr = di_root_ctf.get();
3373 di_roots.push_back(&di_root_ctf_ptr);
3377 abigail::elf_based_reader_sptr reader =
3385 load_vmlinux_corpus(reader, group, vmlinux,
3386 modules, root, di_roots,
3387 suppr_paths, kabi_wl_paths,
3388 supprs, verbose, t, env);
3429elf_based_reader_sptr
3431 const vector<char**>& debug_info_root_paths,
3434 bool show_all_types,
3435 bool linux_kernel_mode)
3437 elf_based_reader_sptr result;
3441 if (requested_fe_kind & corpus::CTF_ORIGIN)
3448 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3453 show_all_types, linux_kernel_mode);
3473 show_all_types, linux_kernel_mode);
3483 debug_info_root_paths,
3497struct xz_decompressor_type::priv
3499 std::istream& xz_istream;
3504 char inbuf[1024 * 10] = {};
3507 char outbuf[1024 * 10] = {};
3509 priv(std::istream& i)
3511 lzma(LZMA_STREAM_INIT)
3519xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
3520 : priv_(new priv(xz_istream))
3523 lzma_ret status = lzma_stream_decoder(&priv_->lzma,
3532 lzma_end(&priv_->lzma);
3543std::streambuf::int_type
3546 if (gptr() < egptr())
3550 priv_->xz_istream.read(priv_->inbuf,
sizeof(priv_->inbuf));
3551 size_t nr = priv_->xz_istream.gcount();
3556 lzma_ret result = lzma_code(&priv_->lzma, LZMA_FINISH);
3557 ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
3562 priv_->lzma.avail_in = nr;
3563 priv_->lzma.next_in =
reinterpret_cast<uint8_t*
>(priv_->inbuf);
3565 priv_->lzma.avail_out =
sizeof(priv_->outbuf);
3566 priv_->lzma.next_out =
reinterpret_cast<uint8_t*
>(priv_->outbuf);
3570 lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
3571 if (result != LZMA_OK && result != LZMA_STREAM_END)
3576 std::ostringstream o;
3577 o <<
"LZMA decompression failed;"
3578 <<
" return code of lzma_code() is : "
3580 throw std::runtime_error(o.str());
3586 size_t nr_decompressed_bytes =
sizeof(priv_->outbuf) - priv_->lzma.avail_out;
3589 setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
3591 if (nr_decompressed_bytes > 0)
3621 std::vector<function_decl*>::const_iterator a_end,
3622 std::vector<function_decl*>::const_iterator b_begin,
3623 std::vector<function_decl*>::const_iterator b_end)
3624{abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3638 std::vector<function_decl*>::const_iterator a_end,
3639 std::vector<function_decl*>::const_iterator b_begin,
3640 std::vector<function_decl*>::const_iterator b_end)
3642 std::vector<function_decl*>::const_iterator i;
3643 std::ostream& o = std::cerr;
3644 for (i = a_begin; i != a_end; ++i)
3645 o << (*i)->get_pretty_representation() <<
"\n";
3648 for (i = b_begin; i != b_end; ++i)
3649 o << (*i)->get_pretty_representation() <<
"\n";
3662 unsigned f1_index,
unsigned f2_index)
3667 return *fn1 == *fn2;
This file contains the declarations of the front-end to analyze the BTF information contained in an E...
This file contains the declarations of the entry points to de-serialize an instance of abigail::corpu...
This file contains the declarations of the entry points to de-serialize an instance of abigail::corpu...
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Types of the main internal representation of libabigail.
Wrappers around regex types and functions.
This is the interface an ELF reader.
const Dwarf * dwarf_debug_info() const
Getter of the handle used to access DWARF information from the current ELF file.
const Elf_Scn * find_ctf_section() const
Find and return a pointer to the the CTF section.
const Elf_Scn * find_btf_section() const
Find and return a pointer to the BTF section of the current ELF file.
The common interface of readers based on ELF.
status
The status of the fe_iface::read_corpus call.
@ STATUS_OK
This status is for when the call went OK.
@ STATUS_UNKNOWN
The status is in an unknown state.
void add_suppressions(const suppr::suppressions_type &)
Add suppressions specifications to the set of suppressions to be used during the construction of the ...
The abstraction of the structured content of an .ini file. This roughly follows what is explained at ...
vector< section_sptr > sections_type
A convenience typedef for a vector of config::section_sptr.
const sections_type & get_sections() const
Abstraction of a group of corpora.
bool has_corpus(const string &)
Test if a corpus of a given path has been added to the group.
void add_corpus(const corpus_sptr &)
Add a new corpus to the current instance of corpus_group.
This is the abstraction of a set of translation units (themselves seen as bundles of unitary abi arte...
origin
This abstracts where the corpus comes from. That is, either it has been read from the native xml form...
const vector< string > & get_needed() const
Getter of the needed property of the corpus.
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Abstraction for a function declaration.
Abstraction of a function suppression specification.
Abstraction of a type suppression specification.
The abstraction of a variable suppression specification.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &env, bool load_all_types=false, bool linux_kernel_mode=false)
Create and return a BTF reader (or front-end) which is an instance of btf::reader.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &env)
Create and return a new read context to process CTF information from a given ELF file.
elf_based_reader_sptr create_reader(const std::string &elf_path, const vector< char ** > &debug_info_root_paths, environment &environment, bool load_all_types, bool linux_kernel_mode)
Create a dwarf::reader.
Namespace for handling ini-style files.
bool read_config(istream &input, config &conf)
Parse an ini config file from an input stream.
shared_ptr< simple_property > simple_property_sptr
Convenience typedef for a shared_ptr to an simple_property.
simple_property * is_simple_property(const property *p)
Tests if a property is a simple property.
std::string generate_from_strings(const std::vector< std::string > &strs)
Generate a regex pattern equivalent to testing set membership.
an engine to suppress the parts of the result of comparing two sets of ABI artifacts.
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
const char * get_opaque_types_suppr_spec_label()
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
void read_suppressions(std::istream &input, suppressions_type &suppressions)
Read suppressions specifications from an input stream.
Toplevel namespace for libabigail.
bool compare_functions(vector< function_decl * >::const_iterator base, unsigned f1_index, unsigned f2_index)
Compare two functions that are in a vector of functions.
void abigail_get_library_version(std::string &major, std::string &minor, std::string &revision, std::string &suffix)
Return the relevant version numbers of the library.
void dump_function_names(std::vector< function_decl * >::const_iterator a_begin, std::vector< function_decl * >::const_iterator a_end, std::vector< function_decl * >::const_iterator b_begin, std::vector< function_decl * >::const_iterator b_end)
Dump (to the standard error output stream) a pretty representation of the signatures of two sequences...
void abigail_get_abixml_version(std::string &major, std::string &minor)
Return the version numbers for the ABIXML format.
void dump_functions_as_string(std::vector< function_decl * >::const_iterator a_begin, std::vector< function_decl * >::const_iterator a_end, std::vector< function_decl * >::const_iterator b_begin, std::vector< function_decl * >::const_iterator b_end)
Dump (to the standard error stream) two sequences of strings where each string represent one of the f...
std::ostream & operator<<(std::ostream &o, const interned_string &s)
Streaming operator.