| /** |
| * @file oparchive.cpp |
| * Implement oparchive utility |
| * |
| * @remark Copyright 2003, 2004 OProfile authors |
| * @remark Read the file COPYING |
| * |
| * @author Will Cohen |
| * @author John Levon |
| * @author Philippe Elie |
| */ |
| |
| #include <cstdlib> |
| |
| #include <iostream> |
| #include <fstream> |
| #include <cstdlib> |
| |
| #include <errno.h> |
| #include <string.h> |
| #include <dirent.h> |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include "op_file.h" |
| #include "op_bfd.h" |
| #include "op_config.h" |
| #include "oparchive_options.h" |
| #include "file_manip.h" |
| #include "cverb.h" |
| #include "image_errors.h" |
| #include "string_manip.h" |
| #include "locate_images.h" |
| |
| using namespace std; |
| |
| namespace { |
| |
| |
| void copy_one_file(image_error err, string const & source, string const & dest) |
| { |
| if (!op_file_readable(source)) |
| return; |
| |
| if (options::list_files) { |
| cout << source << endl; |
| return; |
| } |
| |
| if (!copy_file(source, dest) && err == image_ok) { |
| cerr << "can't copy from " << source << " to " << dest |
| << " cause: " << strerror(errno) << endl; |
| } |
| } |
| |
| void copy_stats(string const & session_samples_dir, |
| string const & archive_path) |
| { |
| DIR * dir; |
| struct dirent * dirent; |
| string stats_path; |
| |
| stats_path = session_samples_dir + "stats/"; |
| |
| if (!(dir = opendir(stats_path.c_str()))) { |
| return; |
| } |
| |
| string sample_base_dir = session_samples_dir.substr(archive_path.size()); |
| string archive_stats = options::outdirectory + sample_base_dir + "stats/"; |
| string archive_stats_path = archive_stats + "event_lost_overflow"; |
| if (!options::list_files && |
| create_path(archive_stats_path.c_str())) { |
| cerr << "Unable to create directory for " |
| << archive_stats << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| |
| copy_one_file(image_ok, stats_path + "/event_lost_overflow", archive_stats_path); |
| |
| while ((dirent = readdir(dir))) { |
| int cpu_nr; |
| string path; |
| if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1) |
| continue; |
| path = string(dirent->d_name) + "/" + "sample_lost_overflow"; |
| archive_stats_path = archive_stats + path; |
| if (!options::list_files && |
| create_path(archive_stats_path.c_str())) { |
| cerr << "Unable to create directory for " |
| << archive_stats_path << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| copy_one_file(image_ok, stats_path + path, archive_stats_path); |
| |
| } |
| closedir(dir); |
| |
| } |
| |
| int oparchive(options::spec const & spec) |
| { |
| handle_options(spec); |
| |
| string archive_path = classes.extra_found_images.get_archive_path(); |
| |
| /* Check to see if directory can be created */ |
| if (!options::list_files && create_path(options::outdirectory.c_str())) { |
| cerr << "Unable to create directory for " |
| << options::outdirectory << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| |
| /* copy over each of the executables and the debuginfo files */ |
| list<inverted_profile> iprofiles = invert_profiles(classes); |
| |
| report_image_errors(iprofiles, classes.extra_found_images); |
| |
| list<inverted_profile>::iterator it = iprofiles.begin(); |
| list<inverted_profile>::iterator const end = iprofiles.end(); |
| |
| cverb << vdebug << "(exe_names)" << endl << endl; |
| for (; it != end; ++it) { |
| |
| string exe_name = it->image; |
| image_error error; |
| string real_exe_name = |
| classes.extra_found_images.find_image_path(it->image, |
| error, true); |
| |
| if (error == image_ok) |
| exe_name = classes.extra_found_images.strip_path_prefix(real_exe_name); |
| |
| // output name must be identical to the original name, when |
| // using this archive the used fixup will be identical e.g.: |
| // oparchive -p /lib/modules/2.6.42/kernel -o tmp; |
| // opreport -p /lib/modules/2.6.42/kernel { archive:tmp } |
| string exe_archive_file = options::outdirectory + exe_name; |
| |
| // FIXME: hacky |
| if (it->error == image_not_found && is_prefix(exe_name, "anon ")) |
| continue; |
| |
| cverb << vdebug << real_exe_name << endl; |
| /* Create directory for executable file. */ |
| if (!options::list_files && |
| create_path(exe_archive_file.c_str())) { |
| cerr << "Unable to create directory for " |
| << exe_archive_file << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| |
| /* Copy actual executable files */ |
| copy_one_file(it->error, real_exe_name, exe_archive_file); |
| |
| /* If there are any debuginfo files, copy them over. |
| * Need to copy the debug info file to somewhere we'll |
| * find it - executable location + "/.debug" |
| * to avoid overwriting files with the same name. The |
| * /usr/lib/debug search path is not going to work. |
| */ |
| bfd * ibfd = open_bfd(real_exe_name); |
| if (ibfd) { |
| string dirname = op_dirname(real_exe_name); |
| string debug_filename; |
| if (find_separate_debug_file(ibfd, real_exe_name, |
| debug_filename, classes.extra_found_images)) { |
| /* found something copy it over */ |
| string dest_debug_dir = options::outdirectory + |
| dirname + "/.debug/"; |
| if (!options::list_files && |
| create_dir(dest_debug_dir.c_str())) { |
| cerr << "Unable to create directory: " |
| << dest_debug_dir << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| |
| string dest_debug = dest_debug_dir + |
| op_basename(debug_filename); |
| copy_one_file(image_ok, debug_filename, dest_debug); |
| } |
| bfd_close(ibfd); |
| } |
| } |
| |
| /* copy over each of the sample files */ |
| list<string>::iterator sit = sample_files.begin(); |
| list<string>::iterator const send = sample_files.end(); |
| |
| string a_sample_file = *sit; |
| int offset = a_sample_file.find('{'); |
| string base_samples_dir = a_sample_file.substr(0, offset); |
| copy_stats(base_samples_dir, archive_path); |
| |
| cverb << vdebug << "(sample_names)" << endl << endl; |
| |
| for (; sit != send; ++sit) { |
| string sample_name = *sit; |
| /* Get rid of the the archive_path from the name */ |
| string sample_base = sample_name.substr(archive_path.size()); |
| string sample_archive_file = options::outdirectory + sample_base; |
| |
| cverb << vdebug << sample_name << endl; |
| cverb << vdebug << " destp " << sample_archive_file << endl; |
| if (!options::list_files && |
| create_path(sample_archive_file.c_str())) { |
| cerr << "Unable to create directory for " |
| << sample_archive_file << "." << endl; |
| exit (EXIT_FAILURE); |
| } |
| |
| /* Copy over actual sample file. */ |
| copy_one_file(image_ok, sample_name, sample_archive_file); |
| } |
| |
| /* copy over the <session-dir>/abi file if it exists */ |
| string abi_name = string(op_session_dir) + "/abi"; |
| copy_one_file(image_ok, archive_path + abi_name, |
| options::outdirectory + abi_name); |
| |
| /* copy over the <session-dir>/samples/oprofiled.log file */ |
| string log_name = string(op_samples_dir) + "/oprofiled.log"; |
| copy_one_file(image_ok, archive_path + log_name, |
| options::outdirectory + log_name); |
| |
| return 0; |
| } |
| |
| } // anonymous namespace |
| |
| |
| int main(int argc, char const * argv[]) |
| { |
| return run_pp_tool(argc, argv, oparchive); |
| } |