Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame] | 1 | /** |
| 2 | * @file oparchive.cpp |
| 3 | * Implement oparchive utility |
| 4 | * |
| 5 | * @remark Copyright 2003, 2004 OProfile authors |
| 6 | * @remark Read the file COPYING |
| 7 | * |
| 8 | * @author Will Cohen |
| 9 | * @author John Levon |
| 10 | * @author Philippe Elie |
| 11 | */ |
| 12 | |
| 13 | #include <cstdlib> |
| 14 | |
| 15 | #include <iostream> |
| 16 | #include <fstream> |
| 17 | #include <cstdlib> |
| 18 | |
| 19 | #include <errno.h> |
| 20 | #include <string.h> |
| 21 | #include <dirent.h> |
| 22 | |
| 23 | #include <sys/types.h> |
| 24 | #include <sys/stat.h> |
| 25 | #include <unistd.h> |
| 26 | #include "op_file.h" |
| 27 | #include "op_bfd.h" |
| 28 | #include "op_config.h" |
| 29 | #include "oparchive_options.h" |
| 30 | #include "file_manip.h" |
| 31 | #include "cverb.h" |
| 32 | #include "image_errors.h" |
| 33 | #include "string_manip.h" |
| 34 | #include "locate_images.h" |
| 35 | |
| 36 | using namespace std; |
| 37 | |
| 38 | namespace { |
| 39 | |
| 40 | |
| 41 | void copy_one_file(image_error err, string const & source, string const & dest) |
| 42 | { |
| 43 | if (!op_file_readable(source)) |
| 44 | return; |
| 45 | |
| 46 | if (options::list_files) { |
| 47 | cout << source << endl; |
| 48 | return; |
| 49 | } |
| 50 | |
| 51 | if (!copy_file(source, dest) && err == image_ok) { |
| 52 | cerr << "can't copy from " << source << " to " << dest |
| 53 | << " cause: " << strerror(errno) << endl; |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | void copy_stats(string const & session_samples_dir, |
| 58 | string const & archive_path) |
| 59 | { |
| 60 | DIR * dir; |
| 61 | struct dirent * dirent; |
| 62 | string stats_path; |
| 63 | |
| 64 | stats_path = session_samples_dir + "stats/"; |
| 65 | |
| 66 | if (!(dir = opendir(stats_path.c_str()))) { |
Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame] | 67 | return; |
| 68 | } |
| 69 | |
| 70 | string sample_base_dir = session_samples_dir.substr(archive_path.size()); |
| 71 | string archive_stats = options::outdirectory + sample_base_dir + "stats/"; |
| 72 | string archive_stats_path = archive_stats + "event_lost_overflow"; |
| 73 | if (!options::list_files && |
| 74 | create_path(archive_stats_path.c_str())) { |
| 75 | cerr << "Unable to create directory for " |
| 76 | << archive_stats << "." << endl; |
| 77 | exit (EXIT_FAILURE); |
| 78 | } |
| 79 | |
| 80 | copy_one_file(image_ok, stats_path + "/event_lost_overflow", archive_stats_path); |
| 81 | |
| 82 | while ((dirent = readdir(dir))) { |
| 83 | int cpu_nr; |
| 84 | string path; |
| 85 | if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1) |
| 86 | continue; |
| 87 | path = string(dirent->d_name) + "/" + "sample_lost_overflow"; |
| 88 | archive_stats_path = archive_stats + path; |
| 89 | if (!options::list_files && |
| 90 | create_path(archive_stats_path.c_str())) { |
| 91 | cerr << "Unable to create directory for " |
| 92 | << archive_stats_path << "." << endl; |
| 93 | exit (EXIT_FAILURE); |
| 94 | } |
| 95 | copy_one_file(image_ok, stats_path + path, archive_stats_path); |
| 96 | |
| 97 | } |
| 98 | closedir(dir); |
| 99 | |
| 100 | } |
| 101 | |
| 102 | int oparchive(options::spec const & spec) |
| 103 | { |
| 104 | handle_options(spec); |
| 105 | |
| 106 | string archive_path = classes.extra_found_images.get_archive_path(); |
| 107 | |
| 108 | /* Check to see if directory can be created */ |
| 109 | if (!options::list_files && create_path(options::outdirectory.c_str())) { |
| 110 | cerr << "Unable to create directory for " |
| 111 | << options::outdirectory << "." << endl; |
| 112 | exit (EXIT_FAILURE); |
| 113 | } |
| 114 | |
| 115 | /* copy over each of the executables and the debuginfo files */ |
| 116 | list<inverted_profile> iprofiles = invert_profiles(classes); |
| 117 | |
| 118 | report_image_errors(iprofiles, classes.extra_found_images); |
| 119 | |
| 120 | list<inverted_profile>::iterator it = iprofiles.begin(); |
| 121 | list<inverted_profile>::iterator const end = iprofiles.end(); |
| 122 | |
| 123 | cverb << vdebug << "(exe_names)" << endl << endl; |
| 124 | for (; it != end; ++it) { |
| 125 | |
| 126 | string exe_name = it->image; |
| 127 | image_error error; |
| 128 | string real_exe_name = |
| 129 | classes.extra_found_images.find_image_path(it->image, |
| 130 | error, true); |
| 131 | |
| 132 | if (error == image_ok) |
| 133 | exe_name = classes.extra_found_images.strip_path_prefix(real_exe_name); |
| 134 | |
| 135 | // output name must be identical to the original name, when |
| 136 | // using this archive the used fixup will be identical e.g.: |
| 137 | // oparchive -p /lib/modules/2.6.42/kernel -o tmp; |
| 138 | // opreport -p /lib/modules/2.6.42/kernel { archive:tmp } |
| 139 | string exe_archive_file = options::outdirectory + exe_name; |
| 140 | |
| 141 | // FIXME: hacky |
| 142 | if (it->error == image_not_found && is_prefix(exe_name, "anon ")) |
| 143 | continue; |
| 144 | |
| 145 | cverb << vdebug << real_exe_name << endl; |
| 146 | /* Create directory for executable file. */ |
| 147 | if (!options::list_files && |
| 148 | create_path(exe_archive_file.c_str())) { |
| 149 | cerr << "Unable to create directory for " |
| 150 | << exe_archive_file << "." << endl; |
| 151 | exit (EXIT_FAILURE); |
| 152 | } |
| 153 | |
| 154 | /* Copy actual executable files */ |
| 155 | copy_one_file(it->error, real_exe_name, exe_archive_file); |
| 156 | |
| 157 | /* If there are any debuginfo files, copy them over. |
| 158 | * Need to copy the debug info file to somewhere we'll |
| 159 | * find it - executable location + "/.debug" |
| 160 | * to avoid overwriting files with the same name. The |
| 161 | * /usr/lib/debug search path is not going to work. |
| 162 | */ |
| 163 | bfd * ibfd = open_bfd(real_exe_name); |
| 164 | if (ibfd) { |
| 165 | string dirname = op_dirname(real_exe_name); |
| 166 | string debug_filename; |
| 167 | if (find_separate_debug_file(ibfd, real_exe_name, |
| 168 | debug_filename, classes.extra_found_images)) { |
| 169 | /* found something copy it over */ |
| 170 | string dest_debug_dir = options::outdirectory + |
| 171 | dirname + "/.debug/"; |
| 172 | if (!options::list_files && |
| 173 | create_dir(dest_debug_dir.c_str())) { |
| 174 | cerr << "Unable to create directory: " |
| 175 | << dest_debug_dir << "." << endl; |
| 176 | exit (EXIT_FAILURE); |
| 177 | } |
| 178 | |
| 179 | string dest_debug = dest_debug_dir + |
| 180 | op_basename(debug_filename); |
| 181 | copy_one_file(image_ok, debug_filename, dest_debug); |
| 182 | } |
| 183 | bfd_close(ibfd); |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | /* copy over each of the sample files */ |
| 188 | list<string>::iterator sit = sample_files.begin(); |
| 189 | list<string>::iterator const send = sample_files.end(); |
| 190 | |
| 191 | string a_sample_file = *sit; |
| 192 | int offset = a_sample_file.find('{'); |
| 193 | string base_samples_dir = a_sample_file.substr(0, offset); |
| 194 | copy_stats(base_samples_dir, archive_path); |
| 195 | |
| 196 | cverb << vdebug << "(sample_names)" << endl << endl; |
| 197 | |
| 198 | for (; sit != send; ++sit) { |
| 199 | string sample_name = *sit; |
| 200 | /* Get rid of the the archive_path from the name */ |
| 201 | string sample_base = sample_name.substr(archive_path.size()); |
| 202 | string sample_archive_file = options::outdirectory + sample_base; |
| 203 | |
| 204 | cverb << vdebug << sample_name << endl; |
| 205 | cverb << vdebug << " destp " << sample_archive_file << endl; |
| 206 | if (!options::list_files && |
| 207 | create_path(sample_archive_file.c_str())) { |
| 208 | cerr << "Unable to create directory for " |
| 209 | << sample_archive_file << "." << endl; |
| 210 | exit (EXIT_FAILURE); |
| 211 | } |
| 212 | |
| 213 | /* Copy over actual sample file. */ |
| 214 | copy_one_file(image_ok, sample_name, sample_archive_file); |
| 215 | } |
| 216 | |
| 217 | /* copy over the <session-dir>/abi file if it exists */ |
| 218 | string abi_name = string(op_session_dir) + "/abi"; |
| 219 | copy_one_file(image_ok, archive_path + abi_name, |
| 220 | options::outdirectory + abi_name); |
| 221 | |
| 222 | /* copy over the <session-dir>/samples/oprofiled.log file */ |
| 223 | string log_name = string(op_samples_dir) + "/oprofiled.log"; |
| 224 | copy_one_file(image_ok, archive_path + log_name, |
| 225 | options::outdirectory + log_name); |
| 226 | |
| 227 | return 0; |
| 228 | } |
| 229 | |
| 230 | } // anonymous namespace |
| 231 | |
| 232 | |
| 233 | int main(int argc, char const * argv[]) |
| 234 | { |
| 235 | return run_pp_tool(argc, argv, oparchive); |
| 236 | } |