blob: 99e0e96eefa13c5bc450fb92dce9ecfbed0566cf [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
2 * @file common_option.cpp
3 * Contains common options and implementation of entry point of pp tools
4 * and some miscelleaneous functions
5 *
6 * @remark Copyright 2003 OProfile authors
7 * @remark Read the file COPYING
8 *
9 * @author Philippe Elie
10 */
11
12#include <cstdlib>
13
14#include <iostream>
15#include <sstream>
16#include <iterator>
17#include <cstdlib>
18
19#include "op_config.h"
20#include "locate_images.h"
21#include "op_exception.h"
22#include "popt_options.h"
23#include "cverb.h"
24#include "common_option.h"
25#include "file_manip.h"
26
27using namespace std;
28
29namespace options {
30 double threshold = 0.0;
31 string threshold_opt;
32 string session_dir = OP_SESSION_DIR_DEFAULT;
33 string command_options;
34 vector<string> image_path;
35 string root_path;
36}
37
38namespace {
39
40vector<string> verbose_strings;
41
42popt::option common_options_array[] = {
43 popt::option(verbose_strings, "verbose", 'V',
44 // FIXME help string for verbose level
45 "verbose output", "all,debug,bfd,level1,sfile,stats,xml"),
46 popt::option(options::session_dir, "session-dir", '\0',
47 "specify session path to hold samples database and session data (" OP_SESSION_DIR_DEFAULT ")", "path"),
48 popt::option(options::image_path, "image-path", 'p',
49 "comma-separated path to search missing binaries", "path"),
50 popt::option(options::root_path, "root", 'R',
51 "path to filesystem to search for missing binaries", "path"),
52};
53
54
55double handle_threshold(string threshold)
56{
57 double value = 0.0;
58
59 if (threshold.length()) {
60 istringstream ss(threshold);
61 if (!(ss >> value)) {
62 cerr << "illegal threshold value: " << threshold
63 << " allowed range: [0-100]" << endl;
64 exit(EXIT_FAILURE);
65 }
66
67 if (value < 0.0 || value > 100.0) {
68 cerr << "illegal threshold value: " << threshold
69 << " allowed range: [0-100]" << endl;
70 exit(EXIT_FAILURE);
71 }
72 }
73
74 cverb << vdebug << "threshold: " << value << endl;;
75
76 return value;
77}
78
79
80vector<string> pre_parse_spec(vector<string> const & non_options)
81{
82 vector<string> result;
83
84 for (size_t i = 0; i < non_options.size(); ++i) {
85 if (non_options[i] == "{}") {
86 result.push_back("{");
87 result.push_back("}");
88 } else {
89 result.push_back(non_options[i]);
90 }
91 }
92
93 return result;
94}
95
96
97options::spec const parse_spec(vector<string> non_options)
98{
99 bool in_first = false;
100 bool in_second = false;
101 bool first = false;
102 bool second = false;
103 options::spec pspec;
104
105 non_options = pre_parse_spec(non_options);
106
107 vector<string>::const_iterator it = non_options.begin();
108 vector<string>::const_iterator end = non_options.end();
109
110 for (; it != end; ++it) {
111 if (*it == "{") {
112 if (in_first || in_second || second)
113 goto fail;
114 if (first) {
115 in_second = true;
116 second = true;
117 } else {
118 in_first = true;
119 first = true;
120 }
121 continue;
122 }
123
124 if (*it == "}") {
125 if (in_first) {
126 in_first = false;
127 } else if (in_second) {
128 in_second = false;
129 } else {
130 goto fail;
131 }
132 continue;
133 }
134
135 if (in_first) {
136 pspec.first.push_back(*it);
137 } else if (in_second) {
138 pspec.second.push_back(*it);
139 } else {
140 pspec.common.push_back(*it);
141 }
142 }
143
144 if (in_first || in_second || (first && !second))
145 goto fail;
146
147 if (pspec.first.empty() && pspec.second.size())
148 goto fail;
149
150 if (first && second) {
151 pspec.first.insert(pspec.first.begin(), pspec.common.begin(),
152 pspec.common.end());
153 pspec.second.insert(pspec.second.begin(), pspec.common.begin(),
154 pspec.common.end());
155 }
156
157 return pspec;
158fail:
159 cerr << "invalid profile specification ";
160 copy(non_options.begin(), non_options.end(),
161 ostream_iterator<string>(cerr, " "));
162 cerr << endl;
163 exit(EXIT_FAILURE);
164}
165
166
167options::spec get_options(int argc, char const * argv[])
168{
169 vector<string> non_options;
170 popt::parse_options(argc, argv, non_options);
171
172 // initialize paths in op_config.h
173 init_op_config_dirs(options::session_dir.c_str());
174
175 if (!options::threshold_opt.empty())
176 options::threshold = handle_threshold(options::threshold_opt);
177
178 if (!verbose::setup(verbose_strings)) {
179 cerr << "unknown --verbose= options\n";
180 exit(EXIT_FAILURE);
181 }
182
183 // XML generator needs command line options for its header
184 ostringstream str;
185 for (int i = 1; i < argc; ++i)
186 str << argv[i] << " ";
187 options::command_options = str.str();
188
189 return parse_spec(non_options);
190}
191
192} // anon namespace
193
194
195int run_pp_tool(int argc, char const * argv[], pp_fct_run_t fct)
196{
197 try {
198 return fct(get_options(argc, argv));
199 }
200 catch (op_runtime_error const & e) {
201 cerr << argv[0] << " error: " << e.what() << endl;
202 }
203 catch (op_fatal_error const & e) {
204 cerr << argv[0] << " error: " << e.what() << endl;
205 }
206 catch (op_exception const & e) {
207 cerr << argv[0] << " error: " << e.what() << endl;
208 }
209 catch (invalid_argument const & e) {
210 cerr << argv[0] << " error: " << e.what() << endl;
211 }
212 catch (exception const & e) {
213 cerr << argv[0] << " error: " << e.what() << endl;
214 }
215 catch (...) {
216 cerr << argv[0] << " unknown exception" << endl;
217 }
218
219 return EXIT_FAILURE;
220}
221
222
223demangle_type handle_demangle_option(string const & option)
224{
225 if (option == "none")
226 return dmt_none;
227 if (option == "smart")
228 return dmt_smart;
229 if (option == "normal")
230 return dmt_normal;
231
232 throw op_runtime_error("invalid option --demangle=" + option);
233}
234
235
236merge_option handle_merge_option(vector<string> const & mergespec,
237 bool allow_lib, bool exclude_dependent)
238{
239 using namespace options;
240 merge_option merge_by;
241
242 merge_by.cpu = false;
243 merge_by.lib = false;
244 merge_by.tid = false;
245 merge_by.tgid = false;
246 merge_by.unitmask = false;
247
248 if (!allow_lib)
249 merge_by.lib = true;
250
251 bool is_all = false;
252
253 vector<string>::const_iterator cit = mergespec.begin();
254 vector<string>::const_iterator end = mergespec.end();
255
256 for (; cit != end; ++cit) {
257 if (*cit == "cpu") {
258 merge_by.cpu = true;
259 } else if (*cit == "tid") {
260 merge_by.tid = true;
261 } else if (*cit == "tgid") {
262 // PP:5.21 tgid merge imply tid merging.
263 merge_by.tgid = true;
264 merge_by.tid = true;
265 } else if ((*cit == "lib" || *cit == "library") && allow_lib) {
266 merge_by.lib = true;
267 } else if (*cit == "unitmask") {
268 merge_by.unitmask = true;
269 } else if (*cit == "all") {
270 merge_by.cpu = true;
271 merge_by.lib = true;
272 merge_by.tid = true;
273 merge_by.tgid = true;
274 merge_by.unitmask = true;
275 is_all = true;
276 } else {
277 cerr << "unknown merge option: " << *cit << endl;
278 exit(EXIT_FAILURE);
279 }
280 }
281
282 // if --merge all, don't warn about lib merging,
283 // it's not user friendly. Behaviour should still
284 // be correct.
285 if (exclude_dependent && merge_by.lib && allow_lib && !is_all) {
286 cerr << "--merge=lib is meaningless "
287 << "with --exclude-dependent" << endl;
288 exit(EXIT_FAILURE);
289 }
290
291 return merge_by;
292}