• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
copy_one_file(image_error err,string const & source,string const & dest)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 
copy_stats(string const & session_samples_dir,string const & archive_path)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 
oparchive(options::spec const & spec)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 
main(int argc,char const * argv[])233 int main(int argc, char const * argv[])
234 {
235 	return run_pp_tool(argc, argv, oparchive);
236 }
237