blob: cb75bd603e7dccd8883df831d5ec922b20c27c0e [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <ctype.h>
30#include <errno.h>
31#include <limits.h>
32#include <signal.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/cdefs.h>
36
37#include <string>
38#include <vector>
39
Christopher Ferris63860cb2015-11-16 17:30:32 -080040#include <private/bionic_macros.h>
41
42#include "Config.h"
43#include "debug_log.h"
44
Christopher Ferris549e5222016-02-22 19:23:26 -080045// Config constants
46static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb;
47static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef;
48
49static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa;
50static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb;
51
52// Used as the default for all guard values.
53static constexpr size_t DEFAULT_GUARD_BYTES = 32;
54static constexpr size_t MAX_GUARD_BYTES = 16384;
55
56static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16;
57static constexpr size_t MAX_BACKTRACE_FRAMES = 256;
58
59static constexpr size_t DEFAULT_EXPAND_BYTES = 16;
60static constexpr size_t MAX_EXPAND_BYTES = 16384;
61
62static constexpr size_t DEFAULT_FREE_TRACK_ALLOCATIONS = 100;
63static constexpr size_t MAX_FREE_TRACK_ALLOCATIONS = 16384;
64
Christopher Ferris7bd01782016-04-20 12:30:58 -070065static constexpr size_t DEFAULT_RECORD_ALLOCS = 8000000;
66static constexpr size_t MAX_RECORD_ALLOCS = 50000000;
67static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
Christopher Ferris63860cb2015-11-16 17:30:32 -080068
Christopher Ferris7bd01782016-04-20 12:30:58 -070069struct Option {
70 Option(std::string name, uint64_t option, bool combo_option = false, bool* config = nullptr)
71 : name(name), option(option), combo_option(combo_option), config(config) {}
72 virtual ~Option() = default;
73
74 std::string name;
75
76 uint64_t option;
Christopher Ferris63860cb2015-11-16 17:30:32 -080077 // If set to true, then all of the options following are set on until
Christopher Ferris7bd01782016-04-20 12:30:58 -070078 // the combo_option value is set to false.
Christopher Ferris63860cb2015-11-16 17:30:32 -080079 bool combo_option = false;
Christopher Ferris7bd01782016-04-20 12:30:58 -070080 bool* config;
81
82 virtual bool ParseValue(const std::string& option_name, const std::string& value) const;
83
84 virtual void SetDefault() const { }
Christopher Ferris63860cb2015-11-16 17:30:32 -080085};
86
Christopher Ferris7bd01782016-04-20 12:30:58 -070087bool Option::ParseValue(const std::string& option_name, const std::string& raw_value) const {
88 if (!raw_value.empty()) {
89 error_log("%s: value set for option '%s' which does not take a value",
90 getprogname(), option_name.c_str());
91 return false;
92 }
93 return true;
94}
95
96struct OptionString : public Option {
97 OptionString(std::string name, uint64_t option, std::string default_value,
98 std::string* value, bool combo_option = false,
99 bool* config = nullptr)
100 : Option(name, option, combo_option, config), default_value(default_value), value(value) {}
101 virtual ~OptionString() = default;
102
103 std::string default_value;
104 std::string* value;
105
106 bool ParseValue(const std::string& option_name, const std::string& value) const override;
107
108 void SetDefault() const override { if (value) *value = default_value; }
109};
110
111bool OptionString::ParseValue(const std::string&, const std::string& raw_value) const {
112 if (!raw_value.empty()) {
113 *value = raw_value;
114 }
115 return true;
116}
117
118struct OptionSizeT : public Option {
119 OptionSizeT(std::string name, size_t default_value, size_t min_value, size_t max_value,
120 uint64_t option, size_t* value, bool combo_option = false, bool* config = nullptr)
121 : Option(name, option, combo_option, config), default_value(default_value),
122 min_value(min_value), max_value(max_value), value(value) {}
123 virtual ~OptionSizeT() = default;
124
125 size_t default_value;
126 size_t min_value;
127 size_t max_value;
128
129 size_t* value;
130
131 bool ParseValue(const std::string& option_name, const std::string& value) const override;
132
133 void SetDefault() const override { if (value) *value = default_value; }
134};
135
136bool OptionSizeT::ParseValue(const std::string& option_name, const std::string& raw_value) const {
137 if (raw_value.empty()) {
138 // Value should have been set by the SetDefault() pass.
139 return true;
140 }
141
142 // Parse the value into a size_t value.
143 errno = 0;
144 char* end;
145 long parsed_value = strtol(raw_value.c_str(), &end, 10);
146 if (errno != 0) {
147 error_log("%s: bad value for option '%s': %s", getprogname(), option_name.c_str(),
148 strerror(errno));
149 return false;
150 }
151 if (end == raw_value.c_str()) {
152 error_log("%s: bad value for option '%s'", getprogname(), option_name.c_str());
153 return false;
154 }
155 if (static_cast<size_t>(end - raw_value.c_str()) != raw_value.size()) {
156 error_log("%s: bad value for option '%s', non space found after option: %s",
157 getprogname(), option_name.c_str(), end);
158 return false;
159 }
160 if (parsed_value < 0) {
161 error_log("%s: bad value for option '%s', value cannot be negative: %ld",
162 getprogname(), option_name.c_str(), parsed_value);
163 return false;
164 }
165
166 if (static_cast<size_t>(parsed_value) < min_value) {
167 error_log("%s: bad value for option '%s', value must be >= %zu: %ld",
168 getprogname(), option_name.c_str(), min_value, parsed_value);
169 return false;
170 }
171 if (static_cast<size_t>(parsed_value) > max_value) {
172 error_log("%s: bad value for option '%s', value must be <= %zu: %ld",
173 getprogname(), option_name.c_str(), max_value, parsed_value);
174 return false;
175 }
176 *value = static_cast<size_t>(parsed_value);
177 return true;
178}
179
Christopher Ferris63860cb2015-11-16 17:30:32 -0800180class PropertyParser {
181 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -0700182 explicit PropertyParser(const char* property) : cur_(property) {}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800183
Christopher Ferris7bd01782016-04-20 12:30:58 -0700184 bool Get(std::string* property, std::string* value);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800185
186 bool Done() { return done_; }
187
188 void LogUsage();
189
Christopher Ferris63860cb2015-11-16 17:30:32 -0800190 private:
191 const char* cur_ = nullptr;
192
193 bool done_ = false;
194
195 DISALLOW_COPY_AND_ASSIGN(PropertyParser);
196};
197
Christopher Ferris7bd01782016-04-20 12:30:58 -0700198bool PropertyParser::Get(std::string* property, std::string* value) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800199 // Process each property name we can find.
200 while (isspace(*cur_))
201 ++cur_;
202
203 if (*cur_ == '\0') {
204 done_ = true;
205 return false;
206 }
207
Christopher Ferris7bd01782016-04-20 12:30:58 -0700208 const char* start = cur_;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800209 while (!isspace(*cur_) && *cur_ != '=' && *cur_ != '\0')
210 ++cur_;
211
Christopher Ferris7bd01782016-04-20 12:30:58 -0700212 *property = std::string(start, cur_ - start);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800213
214 // Skip any spaces after the name.
Christopher Ferris7bd01782016-04-20 12:30:58 -0700215 while (isspace(*cur_))
Christopher Ferris63860cb2015-11-16 17:30:32 -0800216 ++cur_;
217
Christopher Ferris7bd01782016-04-20 12:30:58 -0700218 value->clear();
Christopher Ferris63860cb2015-11-16 17:30:32 -0800219 if (*cur_ == '=') {
220 ++cur_;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700221 // Skip the space after the equal.
222 while (isspace(*cur_))
223 ++cur_;
224
225 start = cur_;
226 while (!isspace(*cur_) && *cur_ != '\0')
227 ++cur_;
228
229 if (cur_ != start) {
230 *value = std::string(start, cur_ - start);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800231 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800232 }
233 return true;
234}
235
236void PropertyParser::LogUsage() {
237 error_log("malloc debug options usage:");
238 error_log("");
239 error_log(" front_guard[=XX]");
240 error_log(" Enables a front guard on all allocations. If XX is set");
241 error_log(" it sets the number of bytes in the guard. The default is");
Christopher Ferris549e5222016-02-22 19:23:26 -0800242 error_log(" %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800243 error_log("");
244 error_log(" rear_guard[=XX]");
245 error_log(" Enables a rear guard on all allocations. If XX is set");
246 error_log(" it sets the number of bytes in the guard. The default is");
Christopher Ferris549e5222016-02-22 19:23:26 -0800247 error_log(" %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800248 error_log("");
249 error_log(" guard[=XX]");
250 error_log(" Enables both a front guard and a rear guard on all allocations.");
251 error_log(" If XX is set it sets the number of bytes in both guards.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800252 error_log(" The default is %zu bytes, the max bytes is %zu.",
253 DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800254 error_log("");
255 error_log(" backtrace[=XX]");
256 error_log(" Enable capturing the backtrace at the point of allocation.");
257 error_log(" If XX is set it sets the number of backtrace frames.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800258 error_log(" The default is %zu frames, the max number of frames is %zu.",
259 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800260 error_log("");
261 error_log(" backtrace_enable_on_signal[=XX]");
262 error_log(" Enable capturing the backtrace at the point of allocation.");
263 error_log(" The backtrace capture is not enabled until the process");
264 error_log(" receives a signal. If XX is set it sets the number of backtrace");
Christopher Ferris549e5222016-02-22 19:23:26 -0800265 error_log(" frames. The default is %zu frames, the max number of frames is %zu.",
266 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800267 error_log("");
268 error_log(" fill_on_alloc[=XX]");
269 error_log(" On first allocation, fill with the value 0x%02x.", DEFAULT_FILL_ALLOC_VALUE);
270 error_log(" If XX is set it will only fill up to XX bytes of the");
271 error_log(" allocation. The default is to fill the entire allocation.");
272 error_log("");
273 error_log(" fill_on_free[=XX]");
274 error_log(" On free, fill with the value 0x%02x. If XX is set it will",
275 DEFAULT_FILL_FREE_VALUE);
276 error_log(" only fill up to XX bytes of the allocation. The default is to");
277 error_log(" fill the entire allocation.");
278 error_log("");
279 error_log(" fill[=XX]");
280 error_log(" On both first allocation free, fill with the value 0x%02x on",
281 DEFAULT_FILL_ALLOC_VALUE);
282 error_log(" first allocation and the value 0x%02x. If XX is set, only fill",
283 DEFAULT_FILL_FREE_VALUE);
284 error_log(" up to XX bytes. The default is to fill the entire allocation.");
285 error_log("");
286 error_log(" expand_alloc[=XX]");
287 error_log(" Allocate an extra number of bytes for every allocation call.");
288 error_log(" If XX is set, that is the number of bytes to expand the");
Christopher Ferris549e5222016-02-22 19:23:26 -0800289 error_log(" allocation by. The default is %zu bytes, the max bytes is %zu.",
290 DEFAULT_EXPAND_BYTES, MAX_EXPAND_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800291 error_log("");
292 error_log(" free_track[=XX]");
293 error_log(" When a pointer is freed, do not free the memory right away.");
294 error_log(" Instead, keep XX of these allocations around and then verify");
295 error_log(" that they have not been modified when the total number of freed");
296 error_log(" allocations exceeds the XX amount. When the program terminates,");
Christopher Ferris7993b802016-01-28 18:35:05 -0800297 error_log(" the rest of these allocations are verified. When this option is");
298 error_log(" enabled, it automatically records the backtrace at the time of the free.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800299 error_log(" The default is to record %zu allocations, the max allocations",
300 DEFAULT_FREE_TRACK_ALLOCATIONS);
301 error_log(" to record is %zu.", MAX_FREE_TRACK_ALLOCATIONS);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800302 error_log("");
Christopher Ferris7993b802016-01-28 18:35:05 -0800303 error_log(" free_track_backtrace_num_frames[=XX]");
304 error_log(" This option only has meaning if free_track is set. This indicates");
305 error_log(" how many backtrace frames to capture when an allocation is freed.");
306 error_log(" If XX is set, that is the number of frames to capture. If XX");
307 error_log(" is set to zero, then no backtrace will be captured.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800308 error_log(" The default is to record %zu frames, the max number of frames is %zu.",
309 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris7993b802016-01-28 18:35:05 -0800310 error_log("");
Christopher Ferris63860cb2015-11-16 17:30:32 -0800311 error_log(" leak_track");
312 error_log(" Enable the leak tracking of memory allocations.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700313 error_log("");
314 error_log(" record_allocs[=XX]");
315 error_log(" Record every single allocation/free call. When a specific signal");
316 error_log(" is sent to the process, the contents of recording are written to");
317 error_log(" a file (%s) and the recording is cleared.", DEFAULT_RECORD_ALLOCS_FILE);
318 error_log(" If XX is set, that is the total number of allocations/frees that can");
319 error_log(" recorded. of frames to capture. The default value is %zu.", DEFAULT_RECORD_ALLOCS);
320 error_log(" If the allocation list fills up, all further allocations are not recorded.");
321 error_log("");
Tamas Berghammer545808a2016-08-26 12:34:16 +0100322 error_log(" record_allocs_file[=FILE]");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700323 error_log(" This option only has meaning if the record_allocs options has been specified.");
324 error_log(" This is the name of the file to which recording information will be dumped.");
325 error_log(" The default is %s.", DEFAULT_RECORD_ALLOCS_FILE);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800326}
327
328// This function is designed to be called once. A second call will not
329// reset all variables.
Tamas Berghammerac81fe82016-08-26 15:54:59 +0100330bool Config::Set(const char* options_str) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800331 // Initialize a few default values.
Christopher Ferris549e5222016-02-22 19:23:26 -0800332 fill_alloc_value = DEFAULT_FILL_ALLOC_VALUE;
333 fill_free_value = DEFAULT_FILL_FREE_VALUE;
334 front_guard_value = DEFAULT_FRONT_GUARD_VALUE;
335 rear_guard_value = DEFAULT_REAR_GUARD_VALUE;
Christopher Ferrisea26b332016-04-15 14:13:52 -0700336 backtrace_signal = SIGRTMAX - 19;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700337 record_allocs_signal = SIGRTMAX - 18;
338 free_track_backtrace_num_frames = 0;
339 record_allocs_file.clear();
Christopher Ferris63860cb2015-11-16 17:30:32 -0800340
341 // Parse the options are of the format:
342 // option_name or option_name=XX
343
Christopher Ferris7bd01782016-04-20 12:30:58 -0700344 // Supported options:
345 const OptionSizeT option_guard(
346 "guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, 0, nullptr, true);
347 // Enable front guard. Value is the size of the guard.
348 const OptionSizeT option_front_guard(
349 "front_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, FRONT_GUARD,
350 &this->front_guard_bytes, true);
351 // Enable end guard. Value is the size of the guard.
352 const OptionSizeT option_rear_guard(
353 "rear_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, REAR_GUARD, &this->rear_guard_bytes,
354 true);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800355
Christopher Ferris7bd01782016-04-20 12:30:58 -0700356 // Enable logging the backtrace on allocation. Value is the total
357 // number of frames to log.
358 const OptionSizeT option_backtrace(
359 "backtrace", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES, BACKTRACE | TRACK_ALLOCS,
360 &this->backtrace_frames, false, &this->backtrace_enabled);
361 // Enable gathering backtrace values on a signal.
362 const OptionSizeT option_backtrace_enable_on_signal(
363 "backtrace_enable_on_signal", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
364 BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, false, &this->backtrace_enable_on_signal);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800365
Christopher Ferris7bd01782016-04-20 12:30:58 -0700366 const OptionSizeT option_fill("fill", SIZE_MAX, 1, SIZE_MAX, 0, nullptr, true);
367 // Fill the allocation with an arbitrary pattern on allocation.
368 // Value is the number of bytes of the allocation to fill
369 // (default entire allocation).
370 const OptionSizeT option_fill_on_alloc(
371 "fill_on_alloc", SIZE_MAX, 1, SIZE_MAX, FILL_ON_ALLOC, &this->fill_on_alloc_bytes, true);
372 // Fill the allocation with an arbitrary pattern on free.
373 // Value is the number of bytes of the allocation to fill
374 // (default entire allocation).
375 const OptionSizeT option_fill_on_free(
376 "fill_on_free", SIZE_MAX, 1, SIZE_MAX, FILL_ON_FREE, &this->fill_on_free_bytes, true);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800377
Christopher Ferris7bd01782016-04-20 12:30:58 -0700378 // Expand the size of every alloc by this number bytes. Value is
379 // the total number of bytes to expand every allocation by.
380 const OptionSizeT option_expand_alloc(
381 "expand_alloc", DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, EXPAND_ALLOC,
382 &this->expand_alloc_bytes);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800383
Christopher Ferris7bd01782016-04-20 12:30:58 -0700384 // Keep track of the freed allocations and verify at a later date
385 // that they have not been used. Turning this on, also turns on
386 // fill on free.
387 const OptionSizeT option_free_track(
388 "free_track", DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
389 FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations);
390 // Number of backtrace frames to keep when free_track is enabled. If this
391 // value is set to zero, no backtrace will be kept.
392 const OptionSizeT option_free_track_backtrace_num_frames(
393 "free_track_backtrace_num_frames", DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES, 0,
394 &this->free_track_backtrace_num_frames);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800395
Christopher Ferris7bd01782016-04-20 12:30:58 -0700396 // Enable printing leaked allocations.
397 const Option option_leak_track("leak_track", LEAK_TRACK | TRACK_ALLOCS);
398
399 const OptionSizeT option_record_allocs(
400 "record_allocs", DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS, RECORD_ALLOCS,
401 &this->record_allocs_num_entries);
402 const OptionString option_record_allocs_file(
403 "record_allocs_file", 0, DEFAULT_RECORD_ALLOCS_FILE, &this->record_allocs_file);
404
405 const Option* option_list[] = {
406 &option_guard, &option_front_guard, &option_rear_guard,
407 &option_backtrace, &option_backtrace_enable_on_signal,
408 &option_fill, &option_fill_on_alloc, &option_fill_on_free,
409 &option_expand_alloc,
410 &option_free_track, &option_free_track_backtrace_num_frames,
411 &option_leak_track,
412 &option_record_allocs, &option_record_allocs_file,
Christopher Ferris63860cb2015-11-16 17:30:32 -0800413 };
414
Christopher Ferris7bd01782016-04-20 12:30:58 -0700415 // Set defaults for all of the options.
416 for (size_t i = 0; i < sizeof(option_list)/sizeof(Option*); i++) {
417 option_list[i]->SetDefault();
418 }
419
Christopher Ferris63860cb2015-11-16 17:30:32 -0800420 // Process each property name we can find.
Tamas Berghammerac81fe82016-08-26 15:54:59 +0100421 PropertyParser parser(options_str);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800422 bool valid = true;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700423 std::string property;
424 std::string value;
425 while (valid && parser.Get(&property, &value)) {
Christopher Ferrisa4b14252016-03-14 15:29:46 -0700426 bool found = false;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700427 for (size_t i = 0; i < sizeof(option_list)/sizeof(Option*); i++) {
428 if (property == option_list[i]->name) {
429 if (option_list[i]->option == 0 && option_list[i]->combo_option) {
430 const std::string* option_name = &option_list[i]->name;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800431 i++;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700432 for (; i < sizeof(option_list)/sizeof(Option*) && option_list[i]->combo_option; i++) {
433 if (!option_list[i]->ParseValue(*option_name, value)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800434 valid = false;
435 break;
436 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700437 if (option_list[i]->config) {
438 *option_list[i]->config = true;
439 }
440 options |= option_list[i]->option;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800441 }
442 if (!valid) {
443 break;
444 }
445 } else {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700446 if (!option_list[i]->ParseValue(option_list[i]->name, value)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800447 valid = false;
448 break;
449 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700450 if (option_list[i]->config) {
451 *option_list[i]->config = true;
452 }
453 options |= option_list[i]->option;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800454 }
455 found = true;
456 break;
457 }
458 }
459 if (valid && !found) {
460 error_log("%s: unknown option %s", getprogname(), property.c_str());
461 valid = false;
462 break;
463 }
464 }
465
466 valid = valid && parser.Done();
467
468 if (valid) {
Christopher Ferris72df6702016-02-11 15:51:31 -0800469 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
Christopher Ferris63860cb2015-11-16 17:30:32 -0800470 // make sure that the header is aligned properly.
471 if (options & FRONT_GUARD) {
Christopher Ferris72df6702016-02-11 15:51:31 -0800472 front_guard_bytes = BIONIC_ALIGN(front_guard_bytes, MINIMUM_ALIGNMENT_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800473 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800474 } else {
475 parser.LogUsage();
476 }
477
478 return valid;
479}