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()))) { 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 } 237