1*76559068SAndroid Build Coastguard Worker //===-- flags_parser.cpp ----------------------------------------*- C++ -*-===//
2*76559068SAndroid Build Coastguard Worker //
3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*76559068SAndroid Build Coastguard Worker //
7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*76559068SAndroid Build Coastguard Worker
9*76559068SAndroid Build Coastguard Worker #include "flags_parser.h"
10*76559068SAndroid Build Coastguard Worker #include "common.h"
11*76559068SAndroid Build Coastguard Worker #include "report.h"
12*76559068SAndroid Build Coastguard Worker
13*76559068SAndroid Build Coastguard Worker #include <errno.h>
14*76559068SAndroid Build Coastguard Worker #include <limits.h>
15*76559068SAndroid Build Coastguard Worker #include <stdlib.h>
16*76559068SAndroid Build Coastguard Worker #include <string.h>
17*76559068SAndroid Build Coastguard Worker
18*76559068SAndroid Build Coastguard Worker namespace scudo {
19*76559068SAndroid Build Coastguard Worker
20*76559068SAndroid Build Coastguard Worker class UnknownFlagsRegistry {
21*76559068SAndroid Build Coastguard Worker static const u32 MaxUnknownFlags = 16;
22*76559068SAndroid Build Coastguard Worker const char *UnknownFlagsNames[MaxUnknownFlags];
23*76559068SAndroid Build Coastguard Worker u32 NumberOfUnknownFlags;
24*76559068SAndroid Build Coastguard Worker
25*76559068SAndroid Build Coastguard Worker public:
add(const char * Name)26*76559068SAndroid Build Coastguard Worker void add(const char *Name) {
27*76559068SAndroid Build Coastguard Worker CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);
28*76559068SAndroid Build Coastguard Worker UnknownFlagsNames[NumberOfUnknownFlags++] = Name;
29*76559068SAndroid Build Coastguard Worker }
30*76559068SAndroid Build Coastguard Worker
report()31*76559068SAndroid Build Coastguard Worker void report() {
32*76559068SAndroid Build Coastguard Worker if (!NumberOfUnknownFlags)
33*76559068SAndroid Build Coastguard Worker return;
34*76559068SAndroid Build Coastguard Worker Printf("Scudo WARNING: found %d unrecognized flag(s):\n",
35*76559068SAndroid Build Coastguard Worker NumberOfUnknownFlags);
36*76559068SAndroid Build Coastguard Worker for (u32 I = 0; I < NumberOfUnknownFlags; ++I)
37*76559068SAndroid Build Coastguard Worker Printf(" %s\n", UnknownFlagsNames[I]);
38*76559068SAndroid Build Coastguard Worker NumberOfUnknownFlags = 0;
39*76559068SAndroid Build Coastguard Worker }
40*76559068SAndroid Build Coastguard Worker };
41*76559068SAndroid Build Coastguard Worker static UnknownFlagsRegistry UnknownFlags;
42*76559068SAndroid Build Coastguard Worker
reportUnrecognizedFlags()43*76559068SAndroid Build Coastguard Worker void reportUnrecognizedFlags() { UnknownFlags.report(); }
44*76559068SAndroid Build Coastguard Worker
printFlagDescriptions()45*76559068SAndroid Build Coastguard Worker void FlagParser::printFlagDescriptions() {
46*76559068SAndroid Build Coastguard Worker Printf("Available flags for Scudo:\n");
47*76559068SAndroid Build Coastguard Worker for (u32 I = 0; I < NumberOfFlags; ++I)
48*76559068SAndroid Build Coastguard Worker Printf("\t%s\n\t\t- %s\n", Flags[I].Name, Flags[I].Desc);
49*76559068SAndroid Build Coastguard Worker }
50*76559068SAndroid Build Coastguard Worker
isSeparator(char C)51*76559068SAndroid Build Coastguard Worker static bool isSeparator(char C) {
52*76559068SAndroid Build Coastguard Worker return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
53*76559068SAndroid Build Coastguard Worker C == '\r';
54*76559068SAndroid Build Coastguard Worker }
55*76559068SAndroid Build Coastguard Worker
isSeparatorOrNull(char C)56*76559068SAndroid Build Coastguard Worker static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
57*76559068SAndroid Build Coastguard Worker
skipWhitespace()58*76559068SAndroid Build Coastguard Worker void FlagParser::skipWhitespace() {
59*76559068SAndroid Build Coastguard Worker while (isSeparator(Buffer[Pos]))
60*76559068SAndroid Build Coastguard Worker ++Pos;
61*76559068SAndroid Build Coastguard Worker }
62*76559068SAndroid Build Coastguard Worker
parseFlag()63*76559068SAndroid Build Coastguard Worker void FlagParser::parseFlag() {
64*76559068SAndroid Build Coastguard Worker const uptr NameStart = Pos;
65*76559068SAndroid Build Coastguard Worker while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
66*76559068SAndroid Build Coastguard Worker ++Pos;
67*76559068SAndroid Build Coastguard Worker if (Buffer[Pos] != '=')
68*76559068SAndroid Build Coastguard Worker reportError("expected '='");
69*76559068SAndroid Build Coastguard Worker const char *Name = Buffer + NameStart;
70*76559068SAndroid Build Coastguard Worker const uptr ValueStart = ++Pos;
71*76559068SAndroid Build Coastguard Worker const char *Value;
72*76559068SAndroid Build Coastguard Worker if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
73*76559068SAndroid Build Coastguard Worker const char Quote = Buffer[Pos++];
74*76559068SAndroid Build Coastguard Worker while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
75*76559068SAndroid Build Coastguard Worker ++Pos;
76*76559068SAndroid Build Coastguard Worker if (Buffer[Pos] == 0)
77*76559068SAndroid Build Coastguard Worker reportError("unterminated string");
78*76559068SAndroid Build Coastguard Worker Value = Buffer + ValueStart + 1;
79*76559068SAndroid Build Coastguard Worker ++Pos; // consume the closing quote
80*76559068SAndroid Build Coastguard Worker } else {
81*76559068SAndroid Build Coastguard Worker while (!isSeparatorOrNull(Buffer[Pos]))
82*76559068SAndroid Build Coastguard Worker ++Pos;
83*76559068SAndroid Build Coastguard Worker Value = Buffer + ValueStart;
84*76559068SAndroid Build Coastguard Worker }
85*76559068SAndroid Build Coastguard Worker if (!runHandler(Name, Value, '='))
86*76559068SAndroid Build Coastguard Worker reportError("flag parsing failed.");
87*76559068SAndroid Build Coastguard Worker }
88*76559068SAndroid Build Coastguard Worker
parseFlags()89*76559068SAndroid Build Coastguard Worker void FlagParser::parseFlags() {
90*76559068SAndroid Build Coastguard Worker while (true) {
91*76559068SAndroid Build Coastguard Worker skipWhitespace();
92*76559068SAndroid Build Coastguard Worker if (Buffer[Pos] == 0)
93*76559068SAndroid Build Coastguard Worker break;
94*76559068SAndroid Build Coastguard Worker parseFlag();
95*76559068SAndroid Build Coastguard Worker }
96*76559068SAndroid Build Coastguard Worker }
97*76559068SAndroid Build Coastguard Worker
parseString(const char * S)98*76559068SAndroid Build Coastguard Worker void FlagParser::parseString(const char *S) {
99*76559068SAndroid Build Coastguard Worker if (!S)
100*76559068SAndroid Build Coastguard Worker return;
101*76559068SAndroid Build Coastguard Worker // Backup current parser state to allow nested parseString() calls.
102*76559068SAndroid Build Coastguard Worker const char *OldBuffer = Buffer;
103*76559068SAndroid Build Coastguard Worker const uptr OldPos = Pos;
104*76559068SAndroid Build Coastguard Worker Buffer = S;
105*76559068SAndroid Build Coastguard Worker Pos = 0;
106*76559068SAndroid Build Coastguard Worker
107*76559068SAndroid Build Coastguard Worker parseFlags();
108*76559068SAndroid Build Coastguard Worker
109*76559068SAndroid Build Coastguard Worker Buffer = OldBuffer;
110*76559068SAndroid Build Coastguard Worker Pos = OldPos;
111*76559068SAndroid Build Coastguard Worker }
112*76559068SAndroid Build Coastguard Worker
parseBool(const char * Value,bool * b)113*76559068SAndroid Build Coastguard Worker inline bool parseBool(const char *Value, bool *b) {
114*76559068SAndroid Build Coastguard Worker if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
115*76559068SAndroid Build Coastguard Worker strncmp(Value, "false", 5) == 0) {
116*76559068SAndroid Build Coastguard Worker *b = false;
117*76559068SAndroid Build Coastguard Worker return true;
118*76559068SAndroid Build Coastguard Worker }
119*76559068SAndroid Build Coastguard Worker if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
120*76559068SAndroid Build Coastguard Worker strncmp(Value, "true", 4) == 0) {
121*76559068SAndroid Build Coastguard Worker *b = true;
122*76559068SAndroid Build Coastguard Worker return true;
123*76559068SAndroid Build Coastguard Worker }
124*76559068SAndroid Build Coastguard Worker return false;
125*76559068SAndroid Build Coastguard Worker }
126*76559068SAndroid Build Coastguard Worker
parseStringPair(const char * Name,const char * Value)127*76559068SAndroid Build Coastguard Worker void FlagParser::parseStringPair(const char *Name, const char *Value) {
128*76559068SAndroid Build Coastguard Worker if (!runHandler(Name, Value, '\0'))
129*76559068SAndroid Build Coastguard Worker reportError("flag parsing failed.");
130*76559068SAndroid Build Coastguard Worker }
131*76559068SAndroid Build Coastguard Worker
runHandler(const char * Name,const char * Value,const char Sep)132*76559068SAndroid Build Coastguard Worker bool FlagParser::runHandler(const char *Name, const char *Value,
133*76559068SAndroid Build Coastguard Worker const char Sep) {
134*76559068SAndroid Build Coastguard Worker for (u32 I = 0; I < NumberOfFlags; ++I) {
135*76559068SAndroid Build Coastguard Worker const uptr Len = strlen(Flags[I].Name);
136*76559068SAndroid Build Coastguard Worker if (strncmp(Name, Flags[I].Name, Len) != 0 || Name[Len] != Sep)
137*76559068SAndroid Build Coastguard Worker continue;
138*76559068SAndroid Build Coastguard Worker bool Ok = false;
139*76559068SAndroid Build Coastguard Worker switch (Flags[I].Type) {
140*76559068SAndroid Build Coastguard Worker case FlagType::FT_bool:
141*76559068SAndroid Build Coastguard Worker Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));
142*76559068SAndroid Build Coastguard Worker if (!Ok)
143*76559068SAndroid Build Coastguard Worker reportInvalidFlag("bool", Value);
144*76559068SAndroid Build Coastguard Worker break;
145*76559068SAndroid Build Coastguard Worker case FlagType::FT_int:
146*76559068SAndroid Build Coastguard Worker char *ValueEnd;
147*76559068SAndroid Build Coastguard Worker errno = 0;
148*76559068SAndroid Build Coastguard Worker long V = strtol(Value, &ValueEnd, 10);
149*76559068SAndroid Build Coastguard Worker if (errno != 0 || // strtol failed (over or underflow)
150*76559068SAndroid Build Coastguard Worker V > INT_MAX || V < INT_MIN || // overflows integer
151*76559068SAndroid Build Coastguard Worker // contains unexpected characters
152*76559068SAndroid Build Coastguard Worker (*ValueEnd != '"' && *ValueEnd != '\'' &&
153*76559068SAndroid Build Coastguard Worker !isSeparatorOrNull(*ValueEnd))) {
154*76559068SAndroid Build Coastguard Worker reportInvalidFlag("int", Value);
155*76559068SAndroid Build Coastguard Worker break;
156*76559068SAndroid Build Coastguard Worker }
157*76559068SAndroid Build Coastguard Worker *reinterpret_cast<int *>(Flags[I].Var) = static_cast<int>(V);
158*76559068SAndroid Build Coastguard Worker Ok = true;
159*76559068SAndroid Build Coastguard Worker break;
160*76559068SAndroid Build Coastguard Worker }
161*76559068SAndroid Build Coastguard Worker return Ok;
162*76559068SAndroid Build Coastguard Worker }
163*76559068SAndroid Build Coastguard Worker // Unrecognized flag. This is not a fatal error, we may print a warning later.
164*76559068SAndroid Build Coastguard Worker UnknownFlags.add(Name);
165*76559068SAndroid Build Coastguard Worker return true;
166*76559068SAndroid Build Coastguard Worker }
167*76559068SAndroid Build Coastguard Worker
registerFlag(const char * Name,const char * Desc,FlagType Type,void * Var)168*76559068SAndroid Build Coastguard Worker void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,
169*76559068SAndroid Build Coastguard Worker void *Var) {
170*76559068SAndroid Build Coastguard Worker CHECK_LT(NumberOfFlags, MaxFlags);
171*76559068SAndroid Build Coastguard Worker Flags[NumberOfFlags].Name = Name;
172*76559068SAndroid Build Coastguard Worker Flags[NumberOfFlags].Desc = Desc;
173*76559068SAndroid Build Coastguard Worker Flags[NumberOfFlags].Type = Type;
174*76559068SAndroid Build Coastguard Worker Flags[NumberOfFlags].Var = Var;
175*76559068SAndroid Build Coastguard Worker ++NumberOfFlags;
176*76559068SAndroid Build Coastguard Worker }
177*76559068SAndroid Build Coastguard Worker
178*76559068SAndroid Build Coastguard Worker } // namespace scudo
179