Home | History | Annotate | Download | only in pp
      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