blob: 448766a4a516ea3a9697bd9bab7b5cf46e10dc25 [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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
36using namespace std;
37
38namespace {
39
40
41void 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
57void 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 Dodd8cfa7022010-11-17 11:12:26 -080067 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
102int 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
233int main(int argc, char const * argv[])
234{
235 return run_pp_tool(argc, argv, oparchive);
236}