svf-lib 1.0.1341 → 1.0.1343
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
#ifndef COMMANDLINE_H_
|
|
2
|
+
#define COMMANDLINE_H_
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <cassert>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <tuple>
|
|
8
|
+
#include <type_traits>
|
|
9
|
+
#include <unordered_map>
|
|
10
|
+
#include <unordered_set>
|
|
11
|
+
#include <limits>
|
|
12
|
+
#include <map>
|
|
13
|
+
#include <vector>
|
|
14
|
+
#include <cstdlib>
|
|
15
|
+
#include <iostream>
|
|
16
|
+
#include <sstream>
|
|
17
|
+
|
|
18
|
+
typedef unsigned u32_t;
|
|
19
|
+
|
|
20
|
+
class OptionBase
|
|
21
|
+
{
|
|
22
|
+
protected:
|
|
23
|
+
/// Name/description pairs.
|
|
24
|
+
typedef std::pair<std::string, std::string> PossibilityDescription;
|
|
25
|
+
typedef std::vector<std::pair<std::string, std::string>> PossibilityDescriptions;
|
|
26
|
+
|
|
27
|
+
/// Value/name/description tuples. If [1] is the value on the commandline for an option, we'd
|
|
28
|
+
/// set the value for the associated Option to [0].
|
|
29
|
+
template <typename T>
|
|
30
|
+
using OptionPossibility = std::tuple<T, std::string, std::string>;
|
|
31
|
+
|
|
32
|
+
protected:
|
|
33
|
+
OptionBase(std::string name, std::string description)
|
|
34
|
+
: OptionBase(name, description, {})
|
|
35
|
+
{
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
OptionBase(std::string name, std::string description, PossibilityDescriptions possibilityDescriptions)
|
|
39
|
+
: name(name), description(description), possibilityDescriptions(possibilityDescriptions)
|
|
40
|
+
{
|
|
41
|
+
assert(name[0] != '-' && "OptionBase: name starts with '-'");
|
|
42
|
+
assert(!isHelpName(name) && "OptionBase: reserved help name");
|
|
43
|
+
assert(getOptionsMap().find(name) == getOptionsMap().end() && "OptionBase: duplicate option");
|
|
44
|
+
|
|
45
|
+
// Types with empty names (i.e., OptionMultiple) can handle things themselves.
|
|
46
|
+
if (!name.empty())
|
|
47
|
+
{
|
|
48
|
+
// Standard name=value option.
|
|
49
|
+
getOptionsMap()[name] = this;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// From a given string, set the value of this option.
|
|
54
|
+
virtual bool parseAndSetValue(const std::string value) = 0;
|
|
55
|
+
|
|
56
|
+
/// Whether this option represents a boolean. Important as such
|
|
57
|
+
/// arguments don't require a value.
|
|
58
|
+
virtual bool isBool(void) const
|
|
59
|
+
{
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Whether this option is an OptionMultiple.
|
|
64
|
+
virtual bool isMultiple(void) const
|
|
65
|
+
{
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Can this option be set?
|
|
70
|
+
virtual bool canSet(void) const = 0;
|
|
71
|
+
|
|
72
|
+
public:
|
|
73
|
+
/// Parse all constructed OptionBase children, returning positional arguments
|
|
74
|
+
/// in the order they appeared.
|
|
75
|
+
static std::vector<std::string> parseOptions(int argc, char *argv[], std::string description, std::string callFormat)
|
|
76
|
+
{
|
|
77
|
+
const std::string usage = buildUsage(description, std::string(argv[0]), callFormat);
|
|
78
|
+
|
|
79
|
+
std::vector<std::string> positionalArguments;
|
|
80
|
+
|
|
81
|
+
for (int i = 1; i < argc; ++i)
|
|
82
|
+
{
|
|
83
|
+
std::string arg(argv[i]);
|
|
84
|
+
if (arg.empty()) continue;
|
|
85
|
+
if (arg[0] != '-')
|
|
86
|
+
{
|
|
87
|
+
// Positional argument. NOT a value to another argument because we
|
|
88
|
+
// "skip" over evaluating those without the corresponding argument.
|
|
89
|
+
positionalArguments.push_back(arg);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Chop off '-'.
|
|
94
|
+
arg = arg.substr(1);
|
|
95
|
+
|
|
96
|
+
std::string argName;
|
|
97
|
+
std::string argValue;
|
|
98
|
+
OptionBase *opt = nullptr;
|
|
99
|
+
|
|
100
|
+
size_t equalsSign = arg.find('=');
|
|
101
|
+
if (equalsSign != std::string::npos)
|
|
102
|
+
{
|
|
103
|
+
// Argument has an equal sign, i.e. argName=argValue
|
|
104
|
+
argName = arg.substr(0, equalsSign);
|
|
105
|
+
if (isHelpName(argName)) usageAndExit(usage, false);
|
|
106
|
+
|
|
107
|
+
opt = getOption(argName);
|
|
108
|
+
if (opt == nullptr)
|
|
109
|
+
{
|
|
110
|
+
std::cerr << "Unknown option: " << argName << std::endl;
|
|
111
|
+
usageAndExit(usage, true);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
argValue = arg.substr(equalsSign + 1);
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
{
|
|
118
|
+
argName = arg;
|
|
119
|
+
if (isHelpName(argName)) usageAndExit(usage, false);
|
|
120
|
+
|
|
121
|
+
opt = getOption(argName);
|
|
122
|
+
if (opt == nullptr)
|
|
123
|
+
{
|
|
124
|
+
std::cerr << "Unknown option: " << argName << std::endl;
|
|
125
|
+
usageAndExit(usage, true);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// No equals sign means we may need next argument.
|
|
129
|
+
if (opt->isBool())
|
|
130
|
+
{
|
|
131
|
+
// Booleans do not accept -arg true/-arg false.
|
|
132
|
+
// They must be -arg=true/-arg=false.
|
|
133
|
+
argValue = "true";
|
|
134
|
+
}
|
|
135
|
+
else if (opt->isMultiple())
|
|
136
|
+
{
|
|
137
|
+
// Name is the value and will be converted to an enum.
|
|
138
|
+
argValue = argName;
|
|
139
|
+
}
|
|
140
|
+
else if (i + 1 < argc)
|
|
141
|
+
{
|
|
142
|
+
// On iteration, we'll skip the value.
|
|
143
|
+
++i;
|
|
144
|
+
argValue = std::string(argv[i]);
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
{
|
|
148
|
+
std::cerr << "Expected value for: " << argName << std::endl;
|
|
149
|
+
usageAndExit(usage, true);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!opt->canSet())
|
|
154
|
+
{
|
|
155
|
+
std::cerr << "Unable to set: " << argName << "; check for duplicates" << std::endl;
|
|
156
|
+
usageAndExit(usage, true);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
bool valueSet = opt->parseAndSetValue(argValue);
|
|
160
|
+
if (!valueSet)
|
|
161
|
+
{
|
|
162
|
+
std::cerr << "Bad value for: " << argName << std::endl;
|
|
163
|
+
usageAndExit(usage, true);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return positionalArguments;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private:
|
|
171
|
+
/// Sets the usage member to a usage string, built from the static list of options.
|
|
172
|
+
/// argv0 is argv[0] and callFormat is how the command should be used, minus the command
|
|
173
|
+
/// name (e.g. "[options] <input-bitcode...>".
|
|
174
|
+
static std::string buildUsage(
|
|
175
|
+
const std::string description, const std::string argv0, const std::string callFormat
|
|
176
|
+
)
|
|
177
|
+
{
|
|
178
|
+
// Determine longest option to split into two columns: options and descriptions.
|
|
179
|
+
unsigned longest = 0;
|
|
180
|
+
for (const std::pair<std::string, OptionBase *> nopt : getOptionsMap())
|
|
181
|
+
{
|
|
182
|
+
const std::string name = std::get<0>(nopt);
|
|
183
|
+
const OptionBase *option = std::get<1>(nopt);
|
|
184
|
+
if (option->isMultiple())
|
|
185
|
+
{
|
|
186
|
+
// For Multiple, description goes in left column.
|
|
187
|
+
if (option->description.length() > longest) longest = option->description.length();
|
|
188
|
+
}
|
|
189
|
+
else
|
|
190
|
+
{
|
|
191
|
+
if (name.length() > longest) longest = name.length();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
for (const PossibilityDescription &pd : option->possibilityDescriptions)
|
|
195
|
+
{
|
|
196
|
+
const std::string possibility = std::get<0>(pd);
|
|
197
|
+
if (possibility.length() + 3 > longest) longest = possibility.length() + 3;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
std::stringstream ss;
|
|
202
|
+
|
|
203
|
+
ss << description << std::endl << std::endl;
|
|
204
|
+
|
|
205
|
+
ss << "USAGE:" << std::endl;
|
|
206
|
+
ss << " " << argv0 << " " << callFormat << std::endl;
|
|
207
|
+
ss << std::endl;
|
|
208
|
+
|
|
209
|
+
ss << "OPTIONS:" << std::endl;
|
|
210
|
+
|
|
211
|
+
// Required as we have OptionMultiples doing a many-to-one in options.
|
|
212
|
+
std::unordered_set<const OptionBase *> handled;
|
|
213
|
+
for (const std::pair<std::string, OptionBase *> nopt : getOptionsMap())
|
|
214
|
+
{
|
|
215
|
+
const std::string name = std::get<0>(nopt);
|
|
216
|
+
const OptionBase *option = std::get<1>(nopt);
|
|
217
|
+
if (handled.find(option) != handled.end()) continue;
|
|
218
|
+
handled.insert(option);
|
|
219
|
+
|
|
220
|
+
if (option->isMultiple())
|
|
221
|
+
{
|
|
222
|
+
// description
|
|
223
|
+
// -name1 - description
|
|
224
|
+
// -name2 - description
|
|
225
|
+
// ...
|
|
226
|
+
ss << " " << option->description << std::endl;
|
|
227
|
+
for (const PossibilityDescription &pd : option->possibilityDescriptions)
|
|
228
|
+
{
|
|
229
|
+
const std::string possibility = std::get<0>(pd);
|
|
230
|
+
const std::string description = std::get<1>(pd);
|
|
231
|
+
ss << " -" << possibility << std::string(longest - possibility.length() + 2, ' ');
|
|
232
|
+
ss << "- " << description << std::endl;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else
|
|
236
|
+
{
|
|
237
|
+
// name - description
|
|
238
|
+
// or
|
|
239
|
+
// name - description
|
|
240
|
+
// =opt1 - description
|
|
241
|
+
// =opt2 - description
|
|
242
|
+
// ...
|
|
243
|
+
ss << " -" << name << std::string(longest - name.length() + 2, ' ');
|
|
244
|
+
ss << "- " << option->description << std::endl;
|
|
245
|
+
for (const PossibilityDescription &pd : option->possibilityDescriptions)
|
|
246
|
+
{
|
|
247
|
+
const std::string possibility = std::get<0>(pd);
|
|
248
|
+
const std::string description = std::get<1>(pd);
|
|
249
|
+
ss << " =" << possibility << std::string(longest - possibility.length() + 2, ' ');
|
|
250
|
+
ss << "- " << description << std::endl;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Help message.
|
|
256
|
+
ss << std::endl;
|
|
257
|
+
ss << " -help" << std::string(longest - 4 + 2, ' ') << "- show usage and exit" << std::endl;
|
|
258
|
+
ss << " -h" << std::string(longest - 1 + 2, ' ') << "- show usage and exit" << std::endl;
|
|
259
|
+
|
|
260
|
+
// How to set boolean options.
|
|
261
|
+
ss << std::endl;
|
|
262
|
+
ss << "Note: for boolean options, -name true and -name false are invalid." << std::endl;
|
|
263
|
+
ss << " Use -name, -name=true, or -name=false." << std::endl;
|
|
264
|
+
|
|
265
|
+
return ss.str();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/// Find option based on name in options map. Returns nullptr if not found.
|
|
269
|
+
static OptionBase *getOption(const std::string optName)
|
|
270
|
+
{
|
|
271
|
+
auto optIt = getOptionsMap().find(optName);
|
|
272
|
+
if (optIt == getOptionsMap().end()) return nullptr;
|
|
273
|
+
else return optIt->second;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/// Print usage and exit. If error is set, print to stderr and exits with code 1.
|
|
277
|
+
static void usageAndExit(const std::string usage, bool error)
|
|
278
|
+
{
|
|
279
|
+
if (error) std::cerr << usage;
|
|
280
|
+
else std::cout << usage;
|
|
281
|
+
std::exit(error ? 1 : 0);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/// Returns whether name is one of the reserved help options.
|
|
285
|
+
static bool isHelpName(const std::string name)
|
|
286
|
+
{
|
|
287
|
+
static std::vector<std::string> helpNames = {"help", "h", "-help"};
|
|
288
|
+
return std::find(helpNames.begin(), helpNames.end(), name) != helpNames.end();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
protected:
|
|
292
|
+
// Return the name/description part of OptionsPossibilities (second and third fields).
|
|
293
|
+
template<typename T>
|
|
294
|
+
static PossibilityDescriptions extractPossibilityDescriptions(const std::vector<OptionPossibility<T>> possibilities)
|
|
295
|
+
{
|
|
296
|
+
PossibilityDescriptions possibilityDescriptions;
|
|
297
|
+
for (const OptionPossibility<T> &op : possibilities)
|
|
298
|
+
{
|
|
299
|
+
possibilityDescriptions.push_back(std::make_pair(std::get<1>(op), std::get<2>(op)));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return possibilityDescriptions;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/// Not unordered map so we can have sorted names when building the usage string.
|
|
306
|
+
/// Map of option names to their object.
|
|
307
|
+
static std::map<std::string, OptionBase *> &getOptionsMap(void)
|
|
308
|
+
{
|
|
309
|
+
// Not static member to avoid initialisation order problems.
|
|
310
|
+
static std::map<std::string, OptionBase *> options;
|
|
311
|
+
return options;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
protected:
|
|
316
|
+
std::string name;
|
|
317
|
+
std::string description;
|
|
318
|
+
/// For when we have possibilities like in an OptionMap.
|
|
319
|
+
PossibilityDescriptions possibilityDescriptions;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
/// General -name=value options.
|
|
323
|
+
/// Retrieve value by Opt().
|
|
324
|
+
template <typename T>
|
|
325
|
+
class Option : public OptionBase
|
|
326
|
+
{
|
|
327
|
+
public:
|
|
328
|
+
Option(std::string name, std::string description, T init)
|
|
329
|
+
: OptionBase(name, description), isExplicitlySet(false), value(init)
|
|
330
|
+
{
|
|
331
|
+
assert(!name.empty() && "Option: empty option name given");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
virtual bool canSet(void) const override
|
|
335
|
+
{
|
|
336
|
+
// Don't allow duplicates.
|
|
337
|
+
return !isExplicitlySet;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
virtual bool parseAndSetValue(const std::string s) override
|
|
341
|
+
{
|
|
342
|
+
isExplicitlySet = fromString(s, value);
|
|
343
|
+
return isExplicitlySet;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
virtual bool isBool(void) const override
|
|
347
|
+
{
|
|
348
|
+
return std::is_same<T, bool>::value;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
void setValue(T v)
|
|
352
|
+
{
|
|
353
|
+
value = v;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
T operator()(void) const
|
|
357
|
+
{
|
|
358
|
+
return value;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private:
|
|
362
|
+
// Convert string to boolean, returning whether we succeeded.
|
|
363
|
+
static bool fromString(const std::string s, bool &value)
|
|
364
|
+
{
|
|
365
|
+
if (s == "true") value = true;
|
|
366
|
+
else if (s == "false") value = false;
|
|
367
|
+
else return false;
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Convert string to string, always succeeds.
|
|
372
|
+
static bool fromString(const std::string s, std::string &value)
|
|
373
|
+
{
|
|
374
|
+
value = s;
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Convert string to u32_t, returning whether we succeeded.
|
|
379
|
+
static bool fromString(const std::string s, u32_t &value)
|
|
380
|
+
{
|
|
381
|
+
// We won't allow anything except [0-9]+.
|
|
382
|
+
if (s.empty()) return false;
|
|
383
|
+
for (char c : s)
|
|
384
|
+
{
|
|
385
|
+
if (!(c >= '0' && c <= '9')) return false;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Use strtoul because we're not using exceptions.
|
|
389
|
+
assert(sizeof(unsigned long) >= sizeof(u32_t));
|
|
390
|
+
const unsigned long sv = std::strtoul(s.c_str(), nullptr, 10);
|
|
391
|
+
|
|
392
|
+
// Out of range according to strtoul, or according to us compared to u32_t.
|
|
393
|
+
if (errno == ERANGE || sv > std::numeric_limits<u32_t>::max()) return false;
|
|
394
|
+
value = sv;
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private:
|
|
399
|
+
bool isExplicitlySet;
|
|
400
|
+
T value;
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/// Option allowing a limited range of values, probably corresponding to an enum.
|
|
404
|
+
/// Opt() gives the value.
|
|
405
|
+
template <typename T>
|
|
406
|
+
class OptionMap : public OptionBase
|
|
407
|
+
{
|
|
408
|
+
public:
|
|
409
|
+
typedef std::vector<OptionPossibility<T>> OptionPossibilities;
|
|
410
|
+
|
|
411
|
+
OptionMap(std::string name, std::string description, T init, OptionPossibilities possibilities)
|
|
412
|
+
: OptionBase(name, description, extractPossibilityDescriptions(possibilities)),
|
|
413
|
+
isExplicitlySet(false), value(init), possibilities(possibilities)
|
|
414
|
+
{
|
|
415
|
+
assert(!name.empty() && "OptionMap: empty option name given");
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
virtual bool canSet(void) const override
|
|
419
|
+
{
|
|
420
|
+
return !isExplicitlySet;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
virtual bool parseAndSetValue(const std::string s) override
|
|
424
|
+
{
|
|
425
|
+
for (const OptionPossibility<T> &op : possibilities)
|
|
426
|
+
{
|
|
427
|
+
// Check if the given string is a valid one.
|
|
428
|
+
if (s == std::get<1>(op))
|
|
429
|
+
{
|
|
430
|
+
// What that string maps to.
|
|
431
|
+
value = std::get<0>(op);
|
|
432
|
+
isExplicitlySet = true;
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return isExplicitlySet;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
T operator()(void) const
|
|
441
|
+
{
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private:
|
|
446
|
+
bool isExplicitlySet;
|
|
447
|
+
T value;
|
|
448
|
+
OptionPossibilities possibilities;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/// Options which form a kind of bit set. There are multiple names and n of them can be set.
|
|
452
|
+
/// Opt(v) tests whether v had been set, aborting if v is invalid.
|
|
453
|
+
template <typename T>
|
|
454
|
+
class OptionMultiple : public OptionBase
|
|
455
|
+
{
|
|
456
|
+
public:
|
|
457
|
+
typedef std::vector<OptionPossibility<T>> OptionPossibilities;
|
|
458
|
+
|
|
459
|
+
OptionMultiple(std::string description, OptionPossibilities possibilities)
|
|
460
|
+
: OptionBase("", description, extractPossibilityDescriptions(possibilities)), possibilities(possibilities)
|
|
461
|
+
{
|
|
462
|
+
for (const OptionPossibility<T> &op : possibilities)
|
|
463
|
+
{
|
|
464
|
+
optionValues[std::get<0>(op)] = false;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
for (const OptionPossibility<T> &op : possibilities)
|
|
468
|
+
{
|
|
469
|
+
std::string possibilityName = std::get<1>(op);
|
|
470
|
+
getOptionsMap()[possibilityName] = this;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
virtual bool canSet(void) const override
|
|
475
|
+
{
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
virtual bool parseAndSetValue(const std::string s) override
|
|
480
|
+
{
|
|
481
|
+
// Like in OptionMap basically, except we can have many values.
|
|
482
|
+
for (const OptionPossibility<T> &op : possibilities)
|
|
483
|
+
{
|
|
484
|
+
if (s == std::get<1>(op))
|
|
485
|
+
{
|
|
486
|
+
optionValues[std::get<0>(op)] = true;
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
virtual bool isMultiple(void) const override
|
|
495
|
+
{
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/// If the bitset is empty.
|
|
500
|
+
bool nothingSet(void) const
|
|
501
|
+
{
|
|
502
|
+
for (const std::pair<T, bool> tb : optionValues)
|
|
503
|
+
{
|
|
504
|
+
if (tb.second) return false;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// Returns whether the value v had been set as an option.
|
|
511
|
+
bool operator()(const T v) const
|
|
512
|
+
{
|
|
513
|
+
typename std::unordered_map<T, bool>::const_iterator ovIt = optionValues.find(v);
|
|
514
|
+
// TODO: disabled as we check for "invalid" values in some places.
|
|
515
|
+
// assert(ovIt != optionValues.end() && "OptionMultiple: bad value checked");
|
|
516
|
+
if (ovIt == optionValues.end()) return false;
|
|
517
|
+
return ovIt->second;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private:
|
|
521
|
+
/// Is the option set? Use a map rather than a set because it's now easier in one
|
|
522
|
+
/// DS to determine whether something is 1) valid, and 2) set.
|
|
523
|
+
std::unordered_map<T, bool> optionValues;
|
|
524
|
+
OptionPossibilities possibilities;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
#endif /* COMMANDLINE_H_ */
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
#include <sstream>
|
|
7
7
|
#include "FastCluster/fastcluster.h"
|
|
8
|
+
#include "Util/CommandLine.h"
|
|
8
9
|
#include "Util/PTAStat.h"
|
|
9
10
|
#include "MemoryModel/PointerAnalysisImpl.h"
|
|
10
11
|
#include "Util/NodeIDAllocator.h"
|
|
11
12
|
#include "MSSA/MemSSA.h"
|
|
12
13
|
#include "WPA/WPAPass.h"
|
|
13
|
-
#include <llvm/Support/CommandLine.h> // for command line options
|
|
14
14
|
|
|
15
15
|
namespace SVF
|
|
16
16
|
{
|
|
@@ -21,244 +21,244 @@ class Options
|
|
|
21
21
|
public:
|
|
22
22
|
Options(void) = delete;
|
|
23
23
|
|
|
24
|
-
static const
|
|
24
|
+
static const OptionMap<enum PTAStat::ClockType> ClockType;
|
|
25
25
|
|
|
26
26
|
/// If set, only return the clock when getClk is called as getClk(true).
|
|
27
27
|
/// Retrieving the clock is slow but it should be fine for a few calls.
|
|
28
28
|
/// This is good for benchmarking when we don't need to know how long processLoad
|
|
29
29
|
/// takes, for example (many calls), but want to know things like total solve time.
|
|
30
30
|
/// Should be used only to affect getClk, not CLOCK_IN_MS.
|
|
31
|
-
static const
|
|
31
|
+
static const Option<bool> MarkedClocksOnly;
|
|
32
32
|
|
|
33
33
|
/// Allocation strategy to be used by the node ID allocator.
|
|
34
34
|
/// Currently dense, seq, or debug.
|
|
35
|
-
static const
|
|
35
|
+
static const OptionMap<SVF::NodeIDAllocator::Strategy> NodeAllocStrat;
|
|
36
36
|
|
|
37
37
|
/// Maximum number of field derivations for an object.
|
|
38
|
-
static const
|
|
38
|
+
static const Option<u32_t> MaxFieldLimit;
|
|
39
39
|
|
|
40
40
|
/// Whether to stage Andersen's with Steensgaard and cluster based on that data.
|
|
41
|
-
static const
|
|
41
|
+
static const Option<bool> ClusterAnder;
|
|
42
42
|
|
|
43
43
|
/// Whether to cluster FS or VFS with the auxiliary Andersen's.
|
|
44
|
-
static const
|
|
44
|
+
static const Option<bool> ClusterFs;
|
|
45
45
|
|
|
46
46
|
/// Use an explicitly plain mapping with flow-sensitive (not null).
|
|
47
|
-
static const
|
|
47
|
+
static const Option<bool> PlainMappingFs;
|
|
48
48
|
|
|
49
49
|
/// Type of points-to set to use for all analyses.
|
|
50
|
-
static const
|
|
50
|
+
static const OptionMap<PointsTo::Type> PtType;
|
|
51
51
|
|
|
52
52
|
/// Clustering method for ClusterFs/ClusterAnder.
|
|
53
53
|
/// TODO: we can separate it into two options, and make Clusterer::cluster take in a method
|
|
54
54
|
/// argument rather than plugging Options::ClusterMethod *inside* Clusterer::cluster
|
|
55
55
|
/// directly, but it seems we will always want single anyway, and this is for testing.
|
|
56
|
-
static const
|
|
56
|
+
static const OptionMap<enum hclust_fast_methods> ClusterMethod;
|
|
57
57
|
|
|
58
58
|
/// Cluster partitions separately.
|
|
59
|
-
static const
|
|
59
|
+
static const Option<bool> RegionedClustering;
|
|
60
60
|
|
|
61
61
|
/// Align identifiers in each region to a word.
|
|
62
|
-
static const
|
|
62
|
+
static const Option<bool> RegionAlign;
|
|
63
63
|
|
|
64
64
|
/// Predict occurences of points-to sets in the staged points-to set to
|
|
65
65
|
/// weigh more common points-to sets as more important.
|
|
66
|
-
static const
|
|
66
|
+
static const Option<bool> PredictPtOcc;
|
|
67
67
|
|
|
68
68
|
/// PTData type.
|
|
69
|
-
static const
|
|
69
|
+
static const OptionMap<BVDataPTAImpl::PTBackingType> ptDataBacking;
|
|
70
70
|
|
|
71
71
|
/// Time limit for the main phase (i.e., the actual solving) of FS analyses.
|
|
72
|
-
static const
|
|
72
|
+
static const Option<u32_t> FsTimeLimit;
|
|
73
73
|
|
|
74
74
|
/// Time limit for the Andersen's analyses.
|
|
75
|
-
static const
|
|
75
|
+
static const Option<u32_t> AnderTimeLimit;
|
|
76
76
|
|
|
77
77
|
/// Number of threads for the versioning phase.
|
|
78
|
-
static const
|
|
78
|
+
static const Option<u32_t> VersioningThreads;
|
|
79
79
|
|
|
80
80
|
// ContextDDA.cpp
|
|
81
|
-
static const
|
|
81
|
+
static const Option<u32_t> CxtBudget;
|
|
82
82
|
|
|
83
83
|
// DDAClient.cpp
|
|
84
|
-
static const
|
|
85
|
-
static const
|
|
86
|
-
static const
|
|
87
|
-
static const
|
|
88
|
-
static const
|
|
89
|
-
static const
|
|
90
|
-
static const
|
|
91
|
-
static const
|
|
92
|
-
static const
|
|
84
|
+
static const Option<bool> SingleLoad;
|
|
85
|
+
static const Option<bool> DumpFree;
|
|
86
|
+
static const Option<bool> DumpUninitVar;
|
|
87
|
+
static const Option<bool> DumpUninitPtr;
|
|
88
|
+
static const Option<bool> DumpSUPts;
|
|
89
|
+
static const Option<bool> DumpSUStore;
|
|
90
|
+
static const Option<bool> MallocOnly;
|
|
91
|
+
static const Option<bool> TaintUninitHeap;
|
|
92
|
+
static const Option<bool> TaintUninitStack;
|
|
93
93
|
|
|
94
94
|
// DDAPass.cpp
|
|
95
|
-
static const
|
|
96
|
-
static const
|
|
97
|
-
static const
|
|
98
|
-
static const
|
|
99
|
-
static const
|
|
100
|
-
static const
|
|
101
|
-
static const
|
|
102
|
-
static const
|
|
103
|
-
static const
|
|
104
|
-
static
|
|
95
|
+
static const Option<u32_t> MaxPathLen;
|
|
96
|
+
static const Option<u32_t> MaxContextLen;
|
|
97
|
+
static const Option<u32_t> MaxStepInWrapper;
|
|
98
|
+
static const Option<std::string> UserInputQuery;
|
|
99
|
+
static const Option<bool> InsenRecur;
|
|
100
|
+
static const Option<bool> InsenCycle;
|
|
101
|
+
static const Option<bool> PrintCPts;
|
|
102
|
+
static const Option<bool> PrintQueryPts;
|
|
103
|
+
static const Option<bool> WPANum;
|
|
104
|
+
static OptionMultiple<PointerAnalysis::PTATY> DDASelected;
|
|
105
105
|
|
|
106
106
|
// FlowDDA.cpp
|
|
107
|
-
static const
|
|
107
|
+
static const Option<u32_t> FlowBudget;
|
|
108
108
|
|
|
109
109
|
// Offline constraint graph (OfflineConsG.cpp)
|
|
110
|
-
static const
|
|
110
|
+
static const Option<bool> OCGDotGraph;
|
|
111
111
|
|
|
112
112
|
// Program Assignment Graph for pointer analysis (SVFIR.cpp)
|
|
113
|
-
static
|
|
114
|
-
static const
|
|
113
|
+
static Option<bool> HandBlackHole;
|
|
114
|
+
static const Option<bool> FirstFieldEqBase;
|
|
115
115
|
|
|
116
116
|
// SVFG optimizer (SVFGOPT.cpp)
|
|
117
|
-
static const
|
|
118
|
-
static const
|
|
119
|
-
static const
|
|
117
|
+
static const Option<bool> ContextInsensitive;
|
|
118
|
+
static const Option<bool> KeepAOFI;
|
|
119
|
+
static const Option<std::string> SelfCycle;
|
|
120
120
|
|
|
121
121
|
// Sparse value-flow graph (VFG.cpp)
|
|
122
|
-
static const
|
|
122
|
+
static const Option<bool> DumpVFG;
|
|
123
123
|
|
|
124
124
|
// Location set for modeling abstract memory object (LocationSet.cpp)
|
|
125
|
-
static const
|
|
125
|
+
static const Option<bool> SingleStride;
|
|
126
126
|
|
|
127
127
|
// Base class of pointer analyses (PointerAnalysis.cpp)
|
|
128
|
-
static const
|
|
129
|
-
static const
|
|
130
|
-
static const
|
|
131
|
-
static const
|
|
132
|
-
static const
|
|
133
|
-
static const
|
|
134
|
-
static const
|
|
135
|
-
static const
|
|
136
|
-
static const
|
|
137
|
-
static const
|
|
138
|
-
static const
|
|
139
|
-
static const
|
|
140
|
-
static const
|
|
141
|
-
static const
|
|
142
|
-
static const
|
|
143
|
-
static const
|
|
128
|
+
static const Option<bool> TypePrint;
|
|
129
|
+
static const Option<bool> FuncPointerPrint;
|
|
130
|
+
static const Option<bool> PTSPrint;
|
|
131
|
+
static const Option<bool> PTSAllPrint;
|
|
132
|
+
static const Option<bool> PStat;
|
|
133
|
+
static const Option<u32_t> StatBudget;
|
|
134
|
+
static const Option<bool> PAGDotGraph;
|
|
135
|
+
static const Option<bool> ShowSVFIRValue;
|
|
136
|
+
static const Option<bool> DumpICFG;
|
|
137
|
+
static const Option<bool> CallGraphDotGraph;
|
|
138
|
+
static const Option<bool> PAGPrint;
|
|
139
|
+
static const Option<u32_t> IndirectCallLimit;
|
|
140
|
+
static const Option<bool> UsePreCompFieldSensitive;
|
|
141
|
+
static const Option<bool> EnableAliasCheck;
|
|
142
|
+
static const Option<bool> EnableThreadCallGraph;
|
|
143
|
+
static const Option<bool> ConnectVCallOnCHA;
|
|
144
144
|
|
|
145
145
|
// PointerAnalysisImpl.cpp
|
|
146
|
-
static const
|
|
146
|
+
static const Option<bool> INCDFPTData;
|
|
147
147
|
|
|
148
148
|
// Memory region (MemRegion.cpp)
|
|
149
|
-
static const
|
|
149
|
+
static const Option<bool> IgnoreDeadFun;
|
|
150
150
|
|
|
151
151
|
// Base class of pointer analyses (MemSSA.cpp)
|
|
152
|
-
static const
|
|
153
|
-
static const
|
|
152
|
+
static const Option<bool> DumpMSSA;
|
|
153
|
+
static const Option<std::string> MSSAFun;
|
|
154
154
|
// static const llvm::cl::opt<string> MSSAFun;
|
|
155
|
-
static const
|
|
155
|
+
static const OptionMap<MemSSA::MemPartition> MemPar;
|
|
156
156
|
|
|
157
157
|
// SVFG builder (SVFGBuilder.cpp)
|
|
158
|
-
static const
|
|
159
|
-
static
|
|
158
|
+
static const Option<bool> SVFGWithIndirectCall;
|
|
159
|
+
static Option<bool> OPTSVFG;
|
|
160
160
|
|
|
161
|
-
static const
|
|
162
|
-
static const
|
|
161
|
+
static const Option<std::string> WriteSVFG;
|
|
162
|
+
static const Option<std::string> ReadSVFG;
|
|
163
163
|
|
|
164
164
|
// FSMPTA.cpp
|
|
165
|
-
static const
|
|
166
|
-
static const
|
|
167
|
-
static const
|
|
168
|
-
static const
|
|
165
|
+
static const Option<bool> UsePCG;
|
|
166
|
+
static const Option<bool> IntraLock;
|
|
167
|
+
static const Option<bool> ReadPrecisionTDEdge;
|
|
168
|
+
static const Option<u32_t> AddModelFlag;
|
|
169
169
|
|
|
170
170
|
// LockAnalysis.cpp
|
|
171
|
-
static const
|
|
171
|
+
static const Option<bool> PrintLockSpan;
|
|
172
172
|
|
|
173
173
|
// MHP.cpp
|
|
174
|
-
static const
|
|
175
|
-
static const
|
|
174
|
+
static const Option<bool> PrintInterLev;
|
|
175
|
+
static const Option<bool> DoLockAnalysis;
|
|
176
176
|
|
|
177
177
|
// MTA.cpp
|
|
178
|
-
static const
|
|
179
|
-
static const
|
|
178
|
+
static const Option<bool> AndersenAnno;
|
|
179
|
+
static const Option<bool> FSAnno;
|
|
180
180
|
|
|
181
181
|
// MTAAnnotator.cpp
|
|
182
|
-
static const
|
|
182
|
+
static const Option<u32_t> AnnoFlag;
|
|
183
183
|
|
|
184
184
|
// MTAResultValidator.cpp
|
|
185
|
-
static const
|
|
185
|
+
static const Option<bool> PrintValidRes;
|
|
186
186
|
|
|
187
|
-
static const
|
|
187
|
+
static const Option<bool> LockValid;
|
|
188
188
|
//MTAStat.cpp
|
|
189
|
-
static const
|
|
189
|
+
static const Option<bool> AllPairMHP;
|
|
190
190
|
|
|
191
191
|
// PCG.cpp
|
|
192
|
-
//const
|
|
192
|
+
//const Option<bool> TDPrint
|
|
193
193
|
|
|
194
194
|
// TCT.cpp
|
|
195
|
-
static const
|
|
195
|
+
static const Option<bool> TCTDotGraph;
|
|
196
196
|
|
|
197
197
|
// LeakChecker.cpp
|
|
198
|
-
static const
|
|
198
|
+
static const Option<bool> ValidateTests;
|
|
199
199
|
|
|
200
200
|
// Source-sink analyzer (SrcSnkDDA.cpp)
|
|
201
|
-
static const
|
|
202
|
-
static const
|
|
201
|
+
static const Option<bool> DumpSlice;
|
|
202
|
+
static const Option<u32_t> CxtLimit;
|
|
203
203
|
|
|
204
204
|
// CHG.cpp
|
|
205
|
-
static const
|
|
205
|
+
static const Option<bool> DumpCHA;
|
|
206
206
|
|
|
207
207
|
// DCHG.cpp
|
|
208
|
-
static const
|
|
208
|
+
static const Option<bool> PrintDCHG;
|
|
209
209
|
|
|
210
210
|
// LLVMModule.cpp
|
|
211
|
-
static const
|
|
212
|
-
static const
|
|
211
|
+
static const Option<std::string> Graphtxt;
|
|
212
|
+
static const Option<bool> SVFMain;
|
|
213
213
|
|
|
214
214
|
// SymbolTableInfo.cpp
|
|
215
|
-
static const
|
|
216
|
-
static const
|
|
217
|
-
static const
|
|
218
|
-
static const
|
|
215
|
+
static const Option<bool> LocMemModel;
|
|
216
|
+
static const Option<bool> ModelConsts;
|
|
217
|
+
static const Option<bool> ModelArrays;
|
|
218
|
+
static const Option<bool> SymTabPrint;
|
|
219
219
|
|
|
220
220
|
// Conditions.cpp
|
|
221
|
-
static const
|
|
221
|
+
static const Option<u32_t> MaxZ3Size;
|
|
222
222
|
|
|
223
223
|
// SaberCondAllocator.cpp
|
|
224
|
-
static const
|
|
224
|
+
static const Option<bool> PrintPathCond;
|
|
225
225
|
|
|
226
226
|
// SVFUtil.cpp
|
|
227
|
-
static const
|
|
227
|
+
static const Option<bool> DisableWarn;
|
|
228
228
|
|
|
229
229
|
// Andersen.cpp
|
|
230
|
-
static const
|
|
231
|
-
static const
|
|
232
|
-
static const
|
|
233
|
-
// static const
|
|
234
|
-
static const
|
|
235
|
-
// static const
|
|
236
|
-
static const
|
|
237
|
-
static const
|
|
238
|
-
static
|
|
239
|
-
static const
|
|
230
|
+
static const Option<bool> ConsCGDotGraph;
|
|
231
|
+
static const Option<bool> BriefConsCGDotGraph;
|
|
232
|
+
static const Option<bool> PrintCGGraph;
|
|
233
|
+
// static const Option<string> WriteAnder;
|
|
234
|
+
static const Option<std::string> WriteAnder;
|
|
235
|
+
// static const Option<string> ReadAnder;
|
|
236
|
+
static const Option<std::string> ReadAnder;
|
|
237
|
+
static const Option<bool> DiffPts;
|
|
238
|
+
static Option<bool> DetectPWC;
|
|
239
|
+
static const Option<bool> VtableInSVFIR;
|
|
240
240
|
|
|
241
241
|
// WPAPass.cpp
|
|
242
|
-
static const
|
|
243
|
-
static const
|
|
244
|
-
static const
|
|
245
|
-
static
|
|
246
|
-
static
|
|
242
|
+
static const Option<bool> AnderSVFG;
|
|
243
|
+
static const Option<bool> SABERFULLSVFG;
|
|
244
|
+
static const Option<bool> PrintAliases;
|
|
245
|
+
static OptionMultiple<PointerAnalysis::PTATY> PASelected;
|
|
246
|
+
static OptionMultiple<WPAPass::AliasCheckRule> AliasRule;
|
|
247
247
|
|
|
248
248
|
// DOTGraphTraits
|
|
249
|
-
static const
|
|
249
|
+
static const Option<bool> ShowHiddenNode;
|
|
250
250
|
|
|
251
251
|
// CFL option
|
|
252
|
-
static const
|
|
253
|
-
static const
|
|
254
|
-
static const
|
|
255
|
-
static const
|
|
256
|
-
static const
|
|
257
|
-
static const
|
|
252
|
+
static const Option<std::string> GrammarFilename;
|
|
253
|
+
static const Option<std::string> CFLGraph;
|
|
254
|
+
static const Option<bool> PrintCFL;
|
|
255
|
+
static const Option<bool> FlexSymMap;
|
|
256
|
+
static const Option<bool> PEGTransfer;
|
|
257
|
+
static const Option<bool> CFLSVFG;
|
|
258
258
|
|
|
259
259
|
// Loop Analysis
|
|
260
|
-
static const
|
|
261
|
-
static const
|
|
260
|
+
static const Option<bool> LoopAnalysis;
|
|
261
|
+
static const Option<u32_t> LoopBound;
|
|
262
262
|
};
|
|
263
263
|
} // namespace SVF
|
|
264
264
|
|
|
@@ -231,7 +231,7 @@ public:
|
|
|
231
231
|
|
|
232
232
|
void setDetectPWC(bool flag)
|
|
233
233
|
{
|
|
234
|
-
Options::DetectPWC
|
|
234
|
+
Options::DetectPWC.setValue(flag);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
protected:
|
|
@@ -242,7 +242,7 @@ protected:
|
|
|
242
242
|
/// Handle diff points-to set.
|
|
243
243
|
virtual inline void computeDiffPts(NodeID id)
|
|
244
244
|
{
|
|
245
|
-
if (Options::DiffPts)
|
|
245
|
+
if (Options::DiffPts())
|
|
246
246
|
{
|
|
247
247
|
NodeID rep = sccRepNode(id);
|
|
248
248
|
getDiffPTDataTy()->computeDiffPts(rep, getDiffPTDataTy()->getPts(rep));
|
|
@@ -251,7 +251,7 @@ protected:
|
|
|
251
251
|
virtual inline const PointsTo& getDiffPts(NodeID id)
|
|
252
252
|
{
|
|
253
253
|
NodeID rep = sccRepNode(id);
|
|
254
|
-
if (Options::DiffPts)
|
|
254
|
+
if (Options::DiffPts())
|
|
255
255
|
return getDiffPTDataTy()->getDiffPts(rep);
|
|
256
256
|
else
|
|
257
257
|
return getPTDataTy()->getPts(rep);
|
|
@@ -260,7 +260,7 @@ protected:
|
|
|
260
260
|
/// Handle propagated points-to set.
|
|
261
261
|
inline void updatePropaPts(NodeID dstId, NodeID srcId)
|
|
262
262
|
{
|
|
263
|
-
if (!Options::DiffPts)
|
|
263
|
+
if (!Options::DiffPts())
|
|
264
264
|
return;
|
|
265
265
|
NodeID srcRep = sccRepNode(srcId);
|
|
266
266
|
NodeID dstRep = sccRepNode(dstId);
|
|
@@ -268,7 +268,7 @@ protected:
|
|
|
268
268
|
}
|
|
269
269
|
inline void clearPropaPts(NodeID src)
|
|
270
270
|
{
|
|
271
|
-
if (Options::DiffPts)
|
|
271
|
+
if (Options::DiffPts())
|
|
272
272
|
{
|
|
273
273
|
NodeID rep = sccRepNode(src);
|
|
274
274
|
getDiffPTDataTy()->clearPropaPts(rep);
|