13 #include <sys/types.h>
23 #include <sys/types.h>
28 #include <sys/types.h>
36 #include <libxml/parser.h>
37 #include <libxml/xmlversion.h>
54 #include "abg-internal.h"
58 ABG_BEGIN_EXPORT_DECLARATIONS
64 ABG_END_EXPORT_DECLARATIONS
103 #ifndef ABIGAIL_ROOT_SYSTEM_LIBDIR
104 #error the macro ABIGAIL_ROOT_SYSTEM_LIBDIR must be set at compile time
107 static __thread
const char* system_libdir(ABIGAIL_ROOT_SYSTEM_LIBDIR);
108 return system_libdir;
121 |
static_cast<unsigned>(r));}
133 &
static_cast<unsigned>(r));}
146 |
static_cast<unsigned>(r));
191 #define DECLARE_STAT(st) \
193 memset(&st, 0, sizeof(st))
200 timer::kind timer_kind;
201 struct timeval begin_timeval;
202 struct timeval end_timeval;
215 : priv_(new
timer::priv(k))
230 if (gettimeofday(&priv_->begin_timeval, 0))
244 if (gettimeofday(&priv_->end_timeval, 0))
255 {
return priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;}
275 time_t& milliseconds)
const
277 time_t elapsed_seconds =
278 priv_->end_timeval.tv_sec - priv_->begin_timeval.tv_sec;
279 suseconds_t elapsed_usecs =
280 ((priv_->end_timeval.tv_sec * 1000000) + priv_->end_timeval.tv_usec)
281 - ((priv_->begin_timeval.tv_sec * 1000000) + priv_->begin_timeval.tv_usec);
285 hours = elapsed_seconds / 3600;
286 minutes = (elapsed_seconds % 3600) / 60;
287 seconds = (elapsed_seconds % 3600) % 60;
288 if (elapsed_seconds == 0)
289 milliseconds = elapsed_usecs / 1000;
300 time_t hours = 0, minutes = 0, seconds = 0;
303 value(hours, minutes, seconds, msecs);
305 std::ostringstream o;
353 get_stat(
const string& path,
355 {
return (lstat(path.c_str(), s) == 0);}
367 return get_stat(path, &st);
388 DIR* dir = opendir(path.c_str());
393 dirent *result = readdir(dir);
394 if (result == NULL && errno != 0)
399 return result == NULL;
413 if (!get_stat(path, &st))
416 if (S_ISREG(st.st_mode))
419 string symlink_target_path;
435 const string& archive_prefix)
437 string ctf_archive = directory +
"/" + archive_prefix +
".ctfa";
459 const vector<char**>& debug_info_root_paths)
466 debug_info_root_paths,
495 const vector<char**>& debug_info_root_paths)
502 debug_info_root_paths,
512 if (
dir_name(elf_file_path, dirname)
518 for (
const auto& path : debug_info_root_paths)
539 const vector<char**>& debug_info_root_paths)
545 elf::reader r(elf_file_path, debug_info_root_paths, env);
564 if (!get_stat(path, &st))
567 if (S_ISDIR(st.st_mode))
570 if (S_ISLNK(st.st_mode))
572 string symlink_target_path;
575 if (!get_stat(path, &st))
578 if (S_ISDIR(st.st_mode))
585 static const char* ANONYMOUS_STRUCT_INTERNAL_NAME =
"__anonymous_struct__";
586 static const char* ANONYMOUS_UNION_INTERNAL_NAME =
"__anonymous_union__";
587 static const char* ANONYMOUS_ENUM_INTERNAL_NAME =
"__anonymous_enum__";
588 static const char* ANONYMOUS_SUBRANGE_INTERNAL_NAME =
"__anonymous_range__";
590 static int ANONYMOUS_STRUCT_INTERNAL_NAME_LEN =
591 strlen(ANONYMOUS_STRUCT_INTERNAL_NAME);
593 static int ANONYMOUS_UNION_INTERNAL_NAME_LEN =
594 strlen(ANONYMOUS_UNION_INTERNAL_NAME);
596 static int ANONYMOUS_ENUM_INTERNAL_NAME_LEN =
597 strlen(ANONYMOUS_ENUM_INTERNAL_NAME);
604 {
return ANONYMOUS_STRUCT_INTERNAL_NAME;}
611 {
return ANONYMOUS_UNION_INTERNAL_NAME;}
613 static int ANONYMOUS_SUBRANGE_INTERNAL_NAME_LEN =
614 strlen(ANONYMOUS_SUBRANGE_INTERNAL_NAME);
621 {
return ANONYMOUS_ENUM_INTERNAL_NAME;}
628 {
return ANONYMOUS_SUBRANGE_INTERNAL_NAME;}
664 string::size_type l_pos1 = 0, r_pos1 = 0;
665 const string::size_type l_length = l.length(), r_length = r.length();
667 while (l_pos1 < l_length && r_pos1 < r_length)
669 string::size_type l_pos2 = l.find(
"::", l_pos1);
670 string::size_type r_pos2 = r.find(
"::", r_pos1);
671 if (l_pos2 == string::npos)
673 if (r_pos2 == string::npos)
676 if (l.compare(l_pos1, l_pos2 - l_pos1, r,
677 r_pos1, r_pos2 - r_pos1)
678 && (l.compare(l_pos1,
679 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
680 ANONYMOUS_STRUCT_INTERNAL_NAME)
682 ANONYMOUS_STRUCT_INTERNAL_NAME_LEN,
683 ANONYMOUS_STRUCT_INTERNAL_NAME))
684 && (l.compare(l_pos1,
685 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
686 ANONYMOUS_UNION_INTERNAL_NAME)
688 ANONYMOUS_UNION_INTERNAL_NAME_LEN,
689 ANONYMOUS_UNION_INTERNAL_NAME))
690 && (l.compare(l_pos1,
691 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
692 ANONYMOUS_ENUM_INTERNAL_NAME)
694 ANONYMOUS_ENUM_INTERNAL_NAME_LEN,
695 ANONYMOUS_ENUM_INTERNAL_NAME)))
698 l_pos1 = l_pos2 == l_length ? l_pos2 : l_pos2 + 2;
699 r_pos1 = r_pos2 == r_length ? r_pos2 : r_pos2 + 2;
702 return (l_pos1 == l_length) == (r_pos1 == r_length);
723 if (!get_stat(file_path, &st))
726 char *link_target_path = realpath(file_path.c_str(), NULL);
727 if (!link_target_path)
730 target_path = link_target_path;
731 free(link_target_path);
751 bool keep_separator_at_end)
759 char *p = strdup(path.c_str());
760 char *r = ::dirname(p);
763 if (keep_separator_at_end
764 &&
dir_name.length() < path.length())
787 char *p = strdup(path.c_str());
788 char *f = ::basename(p);
811 char *realp = realpath(path.c_str(), NULL);
828 memset(&st, 0,
sizeof (st));
832 stat_result = stat(dir_path.c_str(), &st);
833 if (stat_result == 0)
836 if (!S_ISDIR (st.st_mode))
842 cmd =
"mkdir -p " + dir_path;
844 if (system(cmd.c_str()))
883 if (!prog_name.empty())
884 out << prog_name <<
": ";
896 check_file(
const string& path, ostream& out,
const string& prog_name)
900 emit_prefix(prog_name, out) <<
"file " << path <<
" does not exist\n";
906 emit_prefix(prog_name, out) << path <<
" is not a regular file\n";
924 check_dir(
const string& path, ostream& out,
const string& prog_name)
928 emit_prefix(prog_name, out) <<
"path " << path <<
" does not exist\n";
934 emit_prefix(prog_name, out) << path <<
" is not a directory\n";
951 string::size_type str_len = str.length(), suffix_len = suffix.length();
953 if (str_len < suffix_len)
955 return str.compare(str_len - suffix_len, suffix_len, suffix) == 0;
974 string::size_type prefix_len = prefix.length();
975 if (prefix_len > str.length())
978 return str.compare(0, prefix.length(), prefix) == 0;
989 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1014 for (string::const_iterator i = str.begin(); i != str.end(); ++i)
1016 unsigned char c = *i;
1019 || (c >= 0x7F && c <= 0x9F))
1041 const string& delims,
1042 vector<string>& result)
1044 size_t current = 0, next;
1045 bool did_split =
false;
1050 while (current < input_string.size() && isspace(input_string[current]))
1053 if (current >= input_string.size())
1056 next = input_string.find_first_of(delims, current);
1057 if (next == string::npos)
1059 string s = input_string.substr(current);
1061 result.push_back(input_string.substr(current));
1062 did_split = (current != 0);
1065 string s = input_string.substr(current, next - current);
1068 result.push_back(input_string.substr(current, next - current));
1073 while (next != string::npos);
1091 const string& prefix,
1095 if (prefix.length() >= input_string.length())
1098 if (input_string.compare(0, prefix.length(), prefix) != 0)
1103 suffix = input_string.substr(prefix.length());
1120 common_prefix(
const string& s1,
const string& s2,
string &result)
1122 if (s1.length() == 0 || s2.length() == 0)
1126 for (
size_t i = 0; i < s1.length() && i< s2.length(); ++i)
1132 return !result.empty();
1151 string prefix_candidate;
1152 bool found_prefix =
false;
1154 if (input_strings.size() == 1)
1156 if (
dir_name(input_strings.front(), prefix,
1163 for (vector<string>::const_iterator i = input_strings.begin();
1164 i != input_strings.end();
1168 if (prefix_candidate.empty())
1170 prefix_candidate = cur_str;
1175 if (common_prefix(prefix_candidate, cur_str, s))
1178 prefix_candidate = s;
1179 found_prefix =
true;
1185 prefix = prefix_candidate;
1198 string major, minor, revision, version_string, suffix;
1200 version_string = major +
"." + minor +
"." + revision + suffix;
1201 return version_string;
1210 string major, minor, version_string;
1212 version_string = major +
"." + minor;
1213 return version_string;
1242 #define TMP_BUF_LEN 1024 + 1
1243 char tmp_buf[TMP_BUF_LEN];
1244 memset(tmp_buf, 0, TMP_BUF_LEN);
1246 while (fgets(tmp_buf, TMP_BUF_LEN, stream))
1248 lines.push_back(tmp_buf);
1249 memset(tmp_buf, 0, TMP_BUF_LEN);
1252 if (pclose(stream) == -1)
1273 const string& option,
1274 vector<string>& arguments)
1276 string s = input_str;
1282 s = s.substr(0, s.size() - 1);
1304 vector<string> query_output;
1310 + rpm_path +
" 2> /dev/null | grep .so",
1313 for (vector<string>::const_iterator line = query_output.begin();
1314 line != query_output.end();
1317 string dso = line->substr(0, line->find(
'('));
1320 provided_dsos.insert(dso);
1337 string::size_type start, end;
1338 for (start = 0; start < str.length(); ++start)
1339 if (!isspace(str[start]))
1342 for (end = str.length() - 1; end > 0; --end)
1343 if (!isspace(str[end]))
1346 result = str.substr(start, end - start + 1);
1383 vector<char**>& char_star_stars)
1385 for (vector<char*>::const_iterator i = char_stars.begin();
1386 i != char_stars.end();
1388 char_star_stars.push_back(
const_cast<char**
>(&*i));
1392 struct temp_file::priv
1394 char* path_template_;
1396 shared_ptr<std::fstream> fstream_;
1400 const char* templat =
"/tmp/libabigail-tmp-file-XXXXXX";
1401 int s = strlen(templat);
1402 path_template_ =
new char[s + 1];
1403 memset(path_template_, 0, s + 1);
1404 memcpy(path_template_, templat, s);
1406 fd_ = mkstemp(path_template_);
1410 fstream_.reset(
new std::fstream(path_template_,
1418 if (fd_ && fd_ != -1)
1422 remove(path_template_);
1424 delete [] path_template_;
1431 temp_file::temp_file()
1440 temp_file::is_good()
const
1441 {
return priv_->fstream_->good();}
1448 temp_file::get_path()
const
1451 return priv_->path_template_;
1465 temp_file::get_stream()
1468 return *priv_->fstream_;
1479 if (result->is_good())
1491 static __thread
bool initialized =
false;
1508 std::ostringstream o;
1523 repr =
"unknown file type";
1526 repr =
"native binary instrumentation file type";
1529 repr =
"ELF file type";
1532 repr =
"archive file type";
1534 case FILE_TYPE_XML_CORPUS:
1535 repr =
"native XML corpus file type";
1537 case FILE_TYPE_XML_CORPUS_GROUP:
1538 repr =
"native XML corpus group file type";
1541 repr =
"RPM file type";
1544 repr =
"SRPM file type";
1547 repr =
"Debian binary file type";
1550 repr =
"Directory type";
1553 repr =
"GNU tar archive type";
1569 const unsigned BUF_LEN = 264;
1570 const unsigned NB_BYTES_TO_READ = 263;
1573 memset(buf, 0, BUF_LEN);
1575 std::streampos initial_pos = in.tellg();
1576 in.read(buf, NB_BYTES_TO_READ);
1577 in.seekg(initial_pos);
1579 if (in.gcount() < 4 || in.bad())
1596 if (strstr(buf,
"debian-binary"))
1633 return FILE_TYPE_XML_CORPUS_GROUP;
1647 return FILE_TYPE_XML_CORPUS;
1649 if ((
unsigned char) buf[0] == 0xed
1650 && (
unsigned char) buf[1] == 0xab
1651 && (
unsigned char) buf[2] == 0xee
1652 && (
unsigned char) buf[3] == 0xdb)
1656 else if (buf[7] == 0x01)
1700 ifstream in(file_path.c_str(), ifstream::binary);
1718 if (str.empty() || str[0] ==
'_')
1721 string::size_type str_len = str.length(), i = 0 ;
1723 for (; i < str_len; ++i)
1732 name = str.substr(0, i);
1748 if (str.empty() || str[0] ==
'-')
1751 string::size_type str_len = str.length(), i = 0;
1752 string::value_type c;
1754 for (; i < str_len; ++i)
1757 string::size_type next_index = i + 1;
1758 if ((next_index < str_len) && c ==
'-' && isdigit(str[next_index]))
1765 name = str.substr(0, i);
1788 string::size_type str_len = str.length(), i = 0;
1789 string::value_type c;
1790 string::size_type last_dot_index = 0, dot_before_last_index = 0;
1792 for (i = str_len - 1; i > 0; --i)
1805 for(--i; i > 0; --i)
1810 dot_before_last_index = i;
1818 arch = str.substr(dot_before_last_index + 1,
1819 last_dot_index - dot_before_last_index - 1);
1835 bool result =
false;
1846 string package_name;
1865 vector<string> query_output;
1871 + rpm_path +
" 2> /dev/null",
1874 for (
auto& line : query_output)
1895 bool result =
false;
1896 string package_name;
1902 result = (package_name ==
"kernel-debuginfo");
1918 struct malloced_char_star_deleter
1921 operator()(
char* ptr)
1936 std::shared_ptr<char>
1939 using std::shared_ptr;
1941 shared_ptr<char> result;
1943 if (p && p[0] !=
'/')
1945 shared_ptr<char> pwd(get_current_dir_name(),
1946 malloced_char_star_deleter());
1947 string s = string(pwd.get()) +
"/" + p;
1948 result.reset(strdup(s.c_str()), malloced_char_star_deleter());
1951 result.reset(strdup(p), malloced_char_star_deleter());
1972 if (p && p[0] !=
'/')
1974 char* pwd = get_current_dir_name();
1975 string s = string(pwd) +
"/" + p;
1977 result = strdup(s.c_str());
2001 handle_file_entry(
const string& file_path,
2012 suppr->set_source_location_to_keep_regex_str(
"^/usr/include/");
2013 suppr->set_is_artificial(
true);
2019 suppr->get_source_locations_to_keep().insert(file_path);
2035 handle_fts_entry(
const FTSENT *entry,
2039 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2040 || entry->fts_info == FTS_ERR
2041 || entry->fts_info == FTS_NS)
2044 string fname = entry->fts_name;
2050 handle_file_entry (fname, suppr);
2068 gen_suppr_spec_from_headers_root_dir(
const string& headers_root_dir,
2071 if (!headers_root_dir.empty())
2073 char* paths[] = {
const_cast<char*
>(headers_root_dir.c_str()), 0};
2075 if (FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL))
2078 while ((entry = fts_read(file_hierarchy)))
2079 handle_fts_entry(entry, result);
2080 fts_close(file_hierarchy);
2101 const vector<string>& header_files)
2105 for (vector<string>::const_iterator root_dir = headers_root_dirs.begin();
2106 root_dir != headers_root_dirs.end();
2108 gen_suppr_spec_from_headers_root_dir(*root_dir, result);
2110 for (vector<string>::const_iterator file = header_files.begin();
2111 file != header_files.end();
2113 handle_file_entry(*file, result);
2133 const vector<string>& header_files)
2136 vector<string> root_dirs;
2138 if (!headers_root_dir.empty())
2139 root_dirs.push_back(headers_root_dir);
2157 vector<string> header_files;
2188 (
const std::vector<std::string>& abi_whitelist_paths)
2191 std::vector<std::string> whitelisted_names;
2192 for (std::vector<std::string>::const_iterator
2193 path_iter = abi_whitelist_paths.begin(),
2194 path_end = abi_whitelist_paths.end();
2195 path_iter != path_end;
2206 for (ini::config::sections_type::const_iterator
2207 section_iter = whitelist_sections.begin(),
2208 section_end = whitelist_sections.end();
2209 section_iter != section_end;
2212 std::string section_name = (*section_iter)->get_name();
2216 for (ini::config::properties_type::const_iterator
2217 prop_iter = (*section_iter)->get_properties().begin(),
2218 prop_end = (*section_iter)->get_properties().end();
2219 prop_iter != prop_end;
2224 if (prop->has_empty_value())
2226 const std::string& name = prop->get_name();
2228 whitelisted_names.push_back(name);
2235 if (!whitelisted_names.empty())
2238 std::sort(whitelisted_names.begin(), whitelisted_names.end());
2239 whitelisted_names.erase(std::unique(whitelisted_names.begin(),
2240 whitelisted_names.end()),
2241 whitelisted_names.end());
2253 fn_suppr->set_label(
"whitelist");
2254 fn_suppr->set_symbol_name_not_regex_str(regex);
2255 fn_suppr->set_drops_artifact_from_ir(
true);
2256 result.push_back(fn_suppr);
2264 var_suppr->set_label(
"whitelist");
2265 var_suppr->set_symbol_name_not_regex_str(regex);
2266 var_suppr->set_drops_artifact_from_ir(
true);
2267 result.push_back(var_suppr);
2278 string default_system_suppr_path;
2280 const char *s = getenv(
"LIBABIGAIL_DEFAULT_SYSTEM_SUPPRESSION_FILE");
2282 default_system_suppr_path = s;
2284 if (default_system_suppr_path.empty())
2285 default_system_suppr_path =
2288 return default_system_suppr_path;
2297 string default_user_suppr_path;
2298 const char *s = getenv(
"LIBABIGAIL_DEFAULT_USER_SUPPRESSION_FILE");
2305 default_user_suppr_path = s;
2306 if (default_user_suppr_path.empty())
2307 default_user_suppr_path =
"~";
2308 default_user_suppr_path +=
"/.abignore";
2311 default_user_suppr_path = s;
2313 return default_user_suppr_path;
2327 string default_system_suppr_path =
2343 string default_user_suppr_path =
2364 entry_of_file_with_name(
const FTSENT *entry,
2365 const string& fname,
2366 const string& root_dir)
2369 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2370 || entry->fts_info == FTS_ERR
2371 || entry->fts_info == FTS_NS)
2374 string fpath = ::basename(entry->fts_path);
2397 const string& file_path_to_look_for,
2400 char* paths[] = {
const_cast<char*
>(root_dir.c_str()), 0};
2402 FTS *file_hierarchy = fts_open(paths,
2403 FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2404 if (!file_hierarchy)
2407 string r = root_dir;
2412 while ((entry = fts_read(file_hierarchy)))
2414 if (entry_of_file_with_name(entry, file_path_to_look_for, r))
2416 result = entry->fts_path;
2420 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2422 fts_set(file_hierarchy, entry, FTS_SKIP);
2427 fts_close(file_hierarchy);
2444 const string& file_path_to_look_for,
2447 if (root_dirs.empty())
2450 for (
const auto& root_dir : root_dirs)
2479 const vector<string>& deps_dirs,
2480 set<string>& dependencies)
2482 const vector<string>& set_of_needed = korpus.
get_needed();
2483 if (set_of_needed.empty())
2486 bool found_at_least_one_dependency =
false;
2487 for (
const auto& n :set_of_needed)
2490 if (dependencies.find(n) == dependencies.end()
2493 dependencies.insert(dependency);
2494 found_at_least_one_dependency =
true;
2498 return found_at_least_one_dependency;
2516 const vector<string>& binaries,
2517 const vector<string>& deps_dirs,
2520 vector<string> bins;
2522 for (
const auto& b : binaries)
2526 bins.push_back(bin);
2529 for (
const auto& b : bins)
2534 reader->initialize(b);
2536 corpus_sptr c = reader->read_corpus(stat);
2557 const vector<string>& deps_dirs,
2565 for (
const auto& dep: deps)
2570 reader->initialize(dep);
2572 corpus_sptr c = reader->read_corpus(stat);
2600 const corpus_sptr& korpus,
2601 const vector<string>& binaries,
2602 const vector<string>& bins_dirs)
2604 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2605 korpus->get_path()));
2606 result->add_corpus(korpus);
2629 const corpus_sptr& korpus,
2630 const vector<string>& deps_dirs)
2632 corpus_group_sptr result (
new corpus_group(korpus->get_environment(),
2633 korpus->get_path()));
2634 result->add_corpus(korpus);
2662 vector<string>& suppr_paths,
2663 vector<string>& kabi_whitelist_paths,
2668 for (vector<string>::const_iterator i = suppr_paths.begin();
2669 i != suppr_paths.end();
2676 supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
2689 is_vmlinux(
const FTSENT *entry)
2692 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2693 || entry->fts_info == FTS_ERR
2694 || entry->fts_info == FTS_NS)
2697 string fname = entry->fts_name;
2699 if (fname ==
"vmlinux")
2702 dir_name(entry->fts_path, dirname);
2719 is_kernel_module(
const FTSENT *entry)
2722 || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2723 || entry->fts_info == FTS_ERR
2724 || entry->fts_info == FTS_NS)
2727 string fname = entry->fts_name;
2749 find_vmlinux_and_module_paths(
const string& from,
2750 string &vmlinux_path,
2751 vector<string> &module_paths)
2753 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2755 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2756 if (!file_hierarchy)
2759 bool found_vmlinux = !vmlinux_path.empty();
2761 while ((entry = fts_read(file_hierarchy)))
2764 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2766 fts_set(file_hierarchy, entry, FTS_SKIP);
2770 if (!found_vmlinux && is_vmlinux(entry))
2772 vmlinux_path = entry->fts_path;
2773 found_vmlinux =
true;
2775 else if (is_kernel_module(entry))
2776 module_paths.push_back(entry->fts_path);
2779 fts_close(file_hierarchy);
2781 return found_vmlinux;
2792 find_vmlinux_path(
const string& from,
2793 string &vmlinux_path)
2795 char* path[] = {
const_cast<char*
>(from.c_str()), 0};
2797 FTS *file_hierarchy = fts_open(path, FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
2798 if (!file_hierarchy)
2801 bool found_vmlinux =
false;
2803 while ((entry = fts_read(file_hierarchy)))
2806 if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
2808 fts_set(file_hierarchy, entry, FTS_SKIP);
2812 if (!found_vmlinux && is_vmlinux(entry))
2814 vmlinux_path = entry->fts_path;
2815 found_vmlinux =
true;
2820 fts_close(file_hierarchy);
2822 return found_vmlinux;
2843 const string& debug_info_root_path,
2844 string& vmlinux_path,
2845 vector<string>& module_paths)
2858 string kernel_modules_root;
2859 string debug_info_root;
2862 kernel_modules_root = dist_root +
"/lib/modules";
2863 debug_info_root = debug_info_root_path.empty()
2864 ? dist_root +
"/usr/lib/debug"
2865 : debug_info_root_path;
2869 debug_info_root.clear();
2877 find_vmlinux_and_module_paths(kernel_modules_root,
2882 || find_vmlinux_and_module_paths(debug_info_root,
2887 std::sort(module_paths.begin(), module_paths.end());
2903 string& vmlinux_path)
2914 string dist_root = from;
2916 dist_root +=
"/lib/modules";
2919 if (find_vmlinux_path(dist_root, vmlinux_path))
2939 string& vmlinux_path,
2940 vector<string>& module_paths)
2942 string debug_info_root_path;
2944 debug_info_root_path,
2987 load_vmlinux_corpus(elf_based_reader_sptr rdr,
2988 corpus_group_sptr& group,
2989 const string& vmlinux,
2990 vector<string>& modules,
2992 vector<char**>& di_roots,
2993 vector<string>& suppr_paths,
2994 vector<string>& kabi_wl_paths,
3001 rdr->options().do_log = verbose;
3004 load_generate_apply_suppressions(*rdr, suppr_paths,
3005 kabi_wl_paths, supprs);
3009 std::cerr <<
"loaded white list and generated suppr spec in: "
3015 rdr->corpus_group(group);
3018 std::cerr <<
"reading kernel binary '"
3019 << vmlinux <<
"' ...\n" << std::flush;
3023 rdr->read_and_add_corpus_to_group(*group, status);
3027 std::cerr << vmlinux
3031 if (group->is_empty())
3035 int total_nb_modules = modules.size();
3036 int cur_module_index = 1;
3037 for (vector<string>::const_iterator m = modules.begin();
3039 ++m, ++cur_module_index)
3042 std::cerr <<
"reading module '"
3045 <<
"/" << total_nb_modules
3046 <<
") ... " << std::flush;
3048 rdr->initialize(*m, di_roots,
3052 load_generate_apply_suppressions(*rdr, suppr_paths,
3053 kabi_wl_paths, supprs);
3055 rdr->corpus_group(group);
3058 rdr->read_and_add_corpus_to_group(*group, status);
3061 std::cerr <<
"module '"
3063 <<
"' reading DONE: "
3107 const string debug_info_root,
3108 const string& vmlinux_path,
3109 vector<string>& suppr_paths,
3110 vector<string>& kabi_wl_paths,
3116 string vmlinux = vmlinux_path;
3117 corpus_group_sptr group;
3118 vector<string> modules;
3121 std::cerr <<
"Analysing kernel dist root '"
3123 <<
"' with vmlinux path: '"
3125 <<
"' ... " << std::flush;
3130 bool got_binary_paths =
3135 std::cerr <<
"DONE: " << t <<
"\n";
3137 if (got_binary_paths)
3139 shared_ptr<char> di_root =
3141 char *di_root_ptr = di_root.get();
3142 vector<char**> di_roots;
3143 di_roots.push_back(&di_root_ptr);
3146 shared_ptr<char> di_root_ctf;
3147 if (requested_fe_kind & corpus::CTF_ORIGIN)
3150 char *di_root_ctf_ptr = di_root_ctf.get();
3151 di_roots.push_back(&di_root_ctf_ptr);
3155 abigail::elf_based_reader_sptr reader =
3163 load_vmlinux_corpus(reader, group, vmlinux,
3164 modules, root, di_roots,
3165 suppr_paths, kabi_wl_paths,
3166 supprs, verbose, t, env);
3207 elf_based_reader_sptr
3209 const vector<char**>& debug_info_root_paths,
3212 bool show_all_types,
3213 bool linux_kernel_mode)
3215 elf_based_reader_sptr result;
3219 if (requested_fe_kind & corpus::CTF_ORIGIN)
3226 else if (requested_fe_kind & corpus::BTF_ORIGIN)
3259 debug_info_root_paths,
3288 std::vector<function_decl*>::const_iterator a_end,
3289 std::vector<function_decl*>::const_iterator b_begin,
3290 std::vector<function_decl*>::const_iterator b_end)
3291 {abigail::fns_to_str(a_begin, a_end, b_begin, b_end, std::cerr);}
3305 std::vector<function_decl*>::const_iterator a_end,
3306 std::vector<function_decl*>::const_iterator b_begin,
3307 std::vector<function_decl*>::const_iterator b_end)
3309 std::vector<function_decl*>::const_iterator i;
3310 std::ostream& o = std::cerr;
3311 for (i = a_begin; i != a_end; ++i)
3312 o << (*i)->get_pretty_representation() <<
"\n";
3315 for (i = b_begin; i != b_end; ++i)
3316 o << (*i)->get_pretty_representation() <<
"\n";
3329 unsigned f1_index,
unsigned f2_index)
3334 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.
function_suppression::change_kind operator|(function_suppression::change_kind l, function_suppression::change_kind r)
The bitwise 'or' operator for the enum function_suppression::change_kind.
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.
function_suppression::change_kind operator&(function_suppression::change_kind l, function_suppression::change_kind r)
The bitwise 'and' operator for the enum function_suppression::change_kind.
void read_suppressions(std::istream &input, suppressions_type &suppressions)
Read suppressions specifications from an input stream.
Toplevel namespace for libabigail.
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 abigail_get_abixml_version(std::string &major, std::string &minor)
Return the version numbers for the ABIXML format.
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.
fe_iface::status & operator|=(fe_iface::status &l, fe_iface::status r)
The bitwise |= operator for the fe_iface::status type.
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...
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...
std::ostream & operator<<(std::ostream &o, const interned_string &s)
Streaming operator.