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