1 /** 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 27 using namespace std; 28 29 namespace 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 38 namespace { 39 40 vector<string> verbose_strings; 41 42 popt::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 55 double 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 80 vector<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 97 options::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; 158 fail: 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 167 options::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 195 int 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 223 demangle_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 236 merge_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 } 293